Using Jade templates with Yeoman

Phuse
Phuse
Published in
3 min readAug 30, 2013

Yeoman is a great toolset for front-end development, giving you access to a generator, front-end package management with Bower, and automation with Grunt. Though it’s primarily discussed as a tool for building web apps using frameworks like Backbone or Angular, for which you might not be dealing with a great deal of static HTML, it can also be a useful toolset when working on larger static sites. In these situations, it can be really useful to have some sort of template system so that you can leverage includes to avoid repetition. Since Grunt is a JavaScript task runner, it makes sense to use a JavaScript-based template language, such as Jade. There can be a few gotchas involved with setting up Jade and Yeoman, so let’s go through the steps in order:

1. Create a new project and install dependencies

npm install generator-webapp

yo webapp

npm install grunt-contrib-jade --save-dev

Note: I’m doing this without require.js. There may be additional modifications you need to make to include require.js support.

2. Create a jade task in your Gruntfile

jade: {
dist: {
options: {
pretty: true
},
files: [{
expand: true,
cwd: '<%= yeoman.app %>',
dest: '.tmp',
src: '*.jade',
ext: '.html'
}]
}
},

This tells grunt to watch for any .jade files in your app directory, and compile them to html in the .tmp directory.

3. Update references to html files to point to .tmp directory

Since we have a handfull of other tasks that expect our html files to be in the <%= yeoman.app %> directory, we need to point those tasks to .tmp now. We're also going to create a task for jade in the watch task.

There are 3 tasks we need to modify: useminPrepare, htmlmin, and watch:

useminPrepare: {
options: {
dest: '<%= yeoman.dist %>'
},
html: '.tmp/index.html'
},
/* ... */
watch: {
/* ... */
jade: {
files: ['<%= yeoman.app %>/{,*/}*.jade'],
tasks: ['jade']
},
livereload: {
options: {
livereload: LIVERELOAD_PORT
},
files: [
'.tmp/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
/* ... */
htmlmin: {
dist: {
files: [{
expand: true,
cwd: '.tmp',
src: '*.html',
dest: '<%= yeoman.dist %>'
}]
}
},
4. Add the jade task to the server, build, and watch tasksThen just add the jade task to the concurrent task for server, as well as to the build task, making sure you include it before the useminPrepare and htmlmin tasks.concurrent: {
server: [
'jade',
'compass',
'coffee:dist',
'copy:styles'
],
},
/* ... */grunt.registerTask('build', [
'clean:dist',
'jade',
'useminPrepare',
'concurrent:dist',
/* ... */
]);
5. Create index.jadeTry using html2jade to convert index.html, then delete index.html.

6. Update usemin blocks in your jade template

Right now, usemin is looking through our generated index.html file for usemin blocks, which are conditional comments which look like:<!-- build:js scripts/vendor.js-->
<script src="bower_components/jquery/jquery.js"></script>
<!-- endbuild-->
By default, it's going to look for those scripts in the same location as the index.html file it's parsing, which is going to be .tmp in our case. Since all our files are actually still in /app, we need to indicate this to usemin. So, anywhere you have a usemin block that refers to files in /app, indcate it with (app).// build:js(app) scripts/vendor.js
script(src='bower_components/jquery/jquery.js')
// endbuild

Conclusion

You can take a look at the Gruntfile I've used for full reference (just remember to make updates to your usemin blocks too). Now go forth and use templates!Yeoman is a relativley new thing, and though it's now at 1.0, it could still be unstable. If the above doesn't work for you and you think it's a bug, submit an issue on Github.

--

--

Phuse
Phuse
Editor for

Phuse is a remote-based design and development agency headquartered in Toronto. We craft websites, interfaces and brands.