Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Compile *.ejs Templates

EJS Compiler

This is used to generate a templates.js file where the keys are template identifiers and the values are the raw, escaped EJS templates.

Templates are semi-compiled server side. Results of compilation are memoized on the client side using Underscore.

This is useful for maintaining multiple template files server-side and compiling them into a client-side script.

This requires the use of the ejs client side library. Requires ejs to be available on window. See: https://github.com/visionmedia/ejs#client-side-support

Resources

module.exports = function(grunt) {
var config = grunt.config
, file = grunt.file
, log = grunt.log;
grunt.initConfig( {
'ejs': {
'app/assets/js/templates.js': 'app/views/templates/**/*.ejs'
}
, 'watch': {
'files': 'app/views/templates/**/*.ejs'
, 'tasks': 'ejs'
}
} );
grunt.registerMultiTask( 'ejs' , 'Compile ejs templates to JST file' , function(){
// If namespace is specified use that, otherwise fallback
var namespace = config( 'meta.ejs.namespace' ) || 'JST';
console.log(namespace);
// Create JST file.
var files = file.expand( this.data );
file.write(
this.target
, grunt.helper( 'ejs' , files , namespace )
);
// Fail task if errors were logged.
if ( grunt.errors ) { return false; }
// Otherwise, print a success message.
log.writeln( 'File "' + this.target + '" created.' );
});
grunt.registerTask( 'default' , 'ejs' );
grunt.registerHelper( 'ejs' , function( files , namespace ){
namespace = "window['" + namespace + "']";
var contents = namespace + ' = ' + namespace + " || {};\n"
, raw_namespace = namespace + "['raw']";
contents = contents + raw_namespace + ' = ' + raw_namespace + " || {};\n\n";
// Compile the template and get the function source
contents += files ? files.map( function( filepath ){
console.log( 'compiling file:' + filepath );
var key = filepath.replace( /app\/views\/templates\// , '' ).replace( /\.ejs/ , '' )
, template = JSON.stringify( file.read( filepath ) );
var compile_fn = "function( locals ){ return window.ejs.compile( " + raw_namespace + "['" + key + "'] )( locals ); }"
, hash_fn = "function( locals ){ return _.chain( locals ).values().reduce( function( m , v ){ return m + v.toString() } , '' ).value(); }"
, template_data = '';
template_data = template_data + raw_namespace + "['" + key + "'] = " + template + ";\n";
template_data = template_data + namespace + "['" + key + "'] = _.memoize( " + compile_fn + " , " + hash_fn + " );\n";
return template_data;
} ).join( "\n\n" ) : "";
return contents;
});
};
<!-- based on the example output, this file would be at app/views/templates/activities/index.ejs -->
<% _.each( activities , function( activity , id ){ %>
<%
var id = activity.ID
, note = activity.Note;
%>
<tr>
<td><%= id %></td>
<td><%= note %></td>
<td class="code-cell">
<pre><%= directive %></pre>
</td>
<td class="code-cell">
<pre><%= response %></pre>
</td>
<td><%= on_tap %></td>
<td>
<button
class="btn btn-large btn-warning edit-activity-btn"
data-activity-id="<%= id %>"
data-activity-note="<%= note %>"
>*</button>
</td>
</tr>
<% } ); %>
// EXAMPLE OUTPUT
window['JST'] = window['JST'] || {};
window['JST']['raw'] = window['JST']['raw'] || {};
window['JST']['raw']['activities/index'] = "<% _.each( activities , function( activity , id ){ %>\n <%\n var id = activity.ID\n , note = activity.Note;\n %>\n <tr>\n <td><%= id %></td>\n <td><%= note %></td>\n <td class=\"code-cell\">\n <pre><%= directive %></pre>\n </td>\n <td class=\"code-cell\">\n <pre><%= response %></pre>\n </td>\n <td><%= on_tap %></td>\n <td>\n <button\n class=\"btn btn-large btn-warning edit-activity-btn\"\n data-activity-id=\"<%= id %>\"\n data-activity-note=\"<%= note %>\"\n >*</button>\n </td>\n </tr>\n<% } ); %>\n";
window['JST']['activities/index'] = _.memoize( function( locals ){ return window.ejs.compile( window['JST']['raw']['activities/index'] )( locals ); } , function( locals ){ return _.chain( locals ).values().reduce( function( m , v ){ return m + v.toString() } , '' ).value(); } );
@sylvinus

This comment has been minimized.

Copy link

@sylvinus sylvinus commented Jan 3, 2013

This is great. Why don't you use ejs.compile() though?

@cookrn

This comment has been minimized.

Copy link
Owner Author

@cookrn cookrn commented Jan 28, 2013

@sylvinus actually using it on the client side. at the time I wrote this, i was not able to get ejs.compile() working on the server side. the compiled templates were generated but not executable in the browser.

@cookrn

This comment has been minimized.

Copy link
Owner Author

@cookrn cookrn commented Jan 28, 2013

There's definitely some room for improvement of this code. If you'd like to see that work done, please respond here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment