Alex Dow
Alex Dow

Reputation: 648

Distributing underscore.js-based templates

I need to bundle client side templates for other people to use as part of a library of Backbone components. I can not use RequireJS or any other AMD solution.

The idea I've had is to combine all the HTML templates into a isngle JS file that defines variables to contain the templates. Then someone would just have to do:

<script type="text/javascript" src="/js/templates.js"></script>

templates.js could look something like

var ns = ns || {};
ns.templates = {};
ns.templates['my-special-list'] = "<% _.each(stuff, function(model) { %><li><% print(model.get('title')); %></li><% }); %>";

then my views could do things like:

var V = Backbone.View.extend({
    initialize: function() {
        if (_.isUndefined(this.template)) {
            this.template = _.template(ns.templates['my-special-list']);
        } else {
            this.template = _.template(this.template);
        }
   }

   render: function() {
        this.$el.html(this.template.render(this.options));
   }
}

This idea seems to work. Still allows people to pass in their own templates effortlessly while still letting me combine all our templates into a single HTML file at build time.

That said though, I sense complications combining all of this. For starters, every new line would need to be converted to \n, escaping characters, etc.

I can not think of another way to do it to be honest. I tried googling around and didn't see much that helps out. RequireJS just offers a nice way to load text but this doesn't help much for me.

Are there better ways to accomplish what I want or is my approach as good as it gets?

Upvotes: 3

Views: 224

Answers (1)

hamstu
hamstu

Reputation: 1644

Are you familiar with Grunt? In one my projects I'm using the JST task to compile my individual templates into one file at build time. I store them each as individual HTML files and then have this in the Gruntfile.js:

jst: {
    compile: {
        options: {
            namespace: 'app.templates',
            processName: function(filename) {
                // simplify the template names
                filename = filename.replace('app/templates/', '');
                return filename.replace('.html', '');
            }
        },
        files: {
            "<%= yeoman.app %>/scripts/templates.js": ["<%= yeoman.app %>/templates/{,*/}*.html", "<%= yeoman.app %>/templates/**/{,*/}*.html"]
        }
    }
}

My header template (app/templates/inc/header.html), for example, looks like this:

<h1 class='topbar-header'><%= title %></h1> <h2 class="subtitle"><%= subtitle %></h2>

Which is compiled by JST and made available via app.templates['inc/header'] which is a actually a function you call (not a string) with the object containing the parameters. In the case of my header template, I would have to pass in an object with title and subtitle properties.

var template = app.templates['inc/header'];
var code = template({title: 'Hello', subtitle: 'World'});
this.$el.html(code);

Upvotes: 1

Related Questions