Easier modularization of templates

Currently apart from using tools like Grunt, there is no easy, out of the box way to separate templates into files of their own. This is an issue since even for a mid to large size program, you dont want to have a single huuuge html file containing all the templates inline.

There needs to be an easy way to split up the templates across multiple files.

1 Like

It is very easy though. Using a simple Ruby/Python/Bash script itā€™s possible to recurse through a directory and its subdirectories with handlebar files. Read the files and add them to a single .js file which can be loaded in your browser.

Quick example from a test project:

def compile_handlebars_templates(templates_dir="../static/scripts/templates"):
    EMBER_TEMPLATES = """
    Ember.TEMPLATES['{name}'] = Ember.Handlebars.compile('{template}');
    """
    compiled = []

    for current_dir, dirs, files in os.walk(templates_dir):
        for filename in files:
            if not filename.endswith('.handlebars'):
                continue

            name, extension = filename.split('.')

            if current_dir != templates_dir:
                name = "{}/{}".format(current_dir.split('/')[-1], name)

            with open(os.path.join(current_dir, filename)) as f:
                compiled.append(EMBER_TEMPLATES.format(
                    name=name, template=f.read().replace('\n', '')))

    with open(os.path.join(templates_dir, 'compiled.js'), 'w') as f:
        f.write(''.join(compiled))

the fact that you have to write an external script makes it not so easy. Also it makes it tougher to develop since you cant just edit a file and refresh your browser, You have to go through a whole ā€˜compileā€™ phase with this script before thatā€¦

2 Likes

Use something like incron (inotify - get your file system supervised) for auto detection of changes in a file or directories.

Also most (web) frameworks have similar mechanisms.

The way we solve this, is to host our Ember.js app in a Rails app, using the ember-rails gem. Although it makes hosting the app a bit more involved, it allows us to break up our templates into smaller bits. We can also make use of Coffeescript and Emblem.js this way, which is nice.

@pdeva have you seen https://github.com/dgeb/grunt-ember-templates? I use it for my Ember.js projects and it works great!

the issue with that is a lot of projects dont use ruby or rails. For example our backend is in Java and we dont want to deal with ruby just to be able to break up the template into multiple files.

I know one can use a filesystem watcher to basically run a task in the background that does the auto compilation. But the key issue here is that all of these are hacks for what is essentially basic functionality that should be part of the framework. Ember should allow one to specify the template using something like ā€˜foo/templatename.handlebarā€™. I dont see what is the issue here. If anything it will make the initial load much faster since the template will be downloaded by ember only when it is actually used.

1 Like

Yes, I understand that our approach may not be ideal for everyone. I have no experience with it, put perhaps a Grunt-based system might suit you better? See the link by @pangratz for example.

Itā€™s probably not a good thing to load all templates dynamically. Combining everything into a single file - so that there will be only one request - is the most fast way to load your app. For initial loading time I would focus on improving other things. Loading templates just canā€™t be the bottleneck. I guess writing a simple function for your Java application can be done in a couple of minutes? If you have a good asset system, combining JS/CSS files wonā€™t be an issue either.

Iā€™m not for including such functionality in the framework itself, because such things are always a hassle. Everyone uses a different approach anyway, so it would be a waste.

Maybe take a look at a JS library like requireJS? Better not to clutter Ember with that.

iā€™d say that at this point in time you should be using some sort of build system, even for client-side HTML. check out yeoman, or maybe charcoal.

I use https://github.com/component/component which has a bin to convert templates to js then register them to Em.TEMPLATES as simple as:

//Makefile
component convert photos.html #yields photos.js

//component.json
{
  "templates": [
    "app.js"
  ]
}

//app.js
Em.TEMPLATES['photos'] = require('photos');

We will not be adding a feature to dynamically load templates over the network, since adding asychrony into the process of rendering templates would significantly increase code complexity. If your app has grown beyond what is comfortable embedding inside your HTML file, itā€™s time to move to a build tool. This gets you the twin benefits of not having to load multiple files over the network as well as having the Handlebars templates be pre-compiled, reducing the startup cost of the app.

1 Like

@pangratz I used grunt-ember-template and compiled the templates to a file named result.js

Then I included that file in my index.html file after ember. However, I still donā€™t see any content from those templates being rendered. Content from application template, which is defined in index.html is being rendered though. So, how do I get those templates rendered? (I donā€™t see nay error in console or anything)

My result.js looks like this:

define(["ember"], function(Ember){

Ember.TEMPLATES["index"] = Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [4,'>= 1.0.0'];
helpers = this.merge(helpers, Ember.Handlebars.helpers); data = data || {};
  


  data.buffer.push("<h1>Hello</h1>\n");
  
});

});

ā€œIf your app has grown beyond what is comfortable embedding inside your HTML file, itā€™s time to move to a build tool.ā€

This is sad. While this explanation is understandable, it is most likely a turn off for some. Ember.js looks good in many ways and has real potential to become de-facto framework for web app development. Having to use external build tools just to organise the template structures is really unexpected.

I am unaware of anyone building a production app, whether it be in Ember, Backbone, Angular, etc., that doesnā€™t use a build tool. Better to have build tools than to offer a half-measure that quickly falls apart.

But you have the option to not use a build tool- throw it all in one HTML file and use code-collapsing to navigate it. Setting up a Grunt file or whatever takes minutes. You can sample the framework without any tools, and you can use the build tools to develop with more modularity (and performance) than you ever could with plain HTML files. How could this compromise have been better?

for what its worth, both angular router and the angular ui-router do load templates asyncronously and they dont seem to have any issues with it. It makes things much easier since one can just specify a url to a template.

Ok, thanks @kylecoberly and @tomdale for your replies. Points taken.

In that case I would suggest at least include some recommendations of best practices in the official guide (maybe I missed it?). Iā€™m sure others look for them as well. I landed in here while researching this topic, and some SO posts suggested other ways such as using Require.js or some other custom dynamic loading solution.

Or, maybe even better, develop an official ember-build-tool kind of thing to deliver such feature as part of the framework. You donā€™t find other MVC frameworks that expect you either 1) use one file to hold all views, or 2) find your own ways outside the framework.

Seeā€¦ a comment in Using separate template files in Ember.js - Stack Overflow is what ā€œsadā€ meansā€¦

ā€œFor anyone dealing with this in Ember, this was one of many issues that helped me decide to go back to Angular.ā€