How to Use Grunt with Keystone.js for Minifying CSS, JavaScript, and HTML
Table of Contents
- Introduction
- Grunt File Setup
- Place JavaScript/CSS Files in Jade Template
- Keystone.js Init
- Conclusion
Introduction
I'm using Keystone.js with the Jade view template engine, and the back-end is MongoDB. I hadn't tried Grunt with Keystone.js before. This blog covers how I tried it — it's not perfect, but the output is close to what I want. From the browser source code point of view, here is what I wanted to achieve:
- Minify CSS/JavaScript
- Minify HTML
- In development mode, I should have the choice to not minify CSS/JavaScript and not minify HTML.

The following are the steps I took to make it happen.
Grunt File Setup
Use grunt-jade-usemin
The first thing I'm doing here is using jadeUsemin to set up a task for the Jade template. Then, there is some cleanup so I can make my web application work, which is the copy task.
/*
* grunt-jade-usemin
*
*
* Copyright ©2014 Gilad Peleg
* Licensed under the MIT license.
*/
'use strict';
module.exports = function (grunt) {
// load all npm grunt tasks
require('load-grunt-tasks')(grunt);
// Project configuration.
grunt.initConfig({
// Before generating any new files, remove any previously-created files.
clean: {
tests: ['tmp', 'test/compiled']
},
filerev: {
jadeUsemin: {
options: {
noDest: true
}
}
},
// Configuration to be run (and then tested).
jadeUsemin: {
options: {
replacePath: {
'#{baseDir}': 'test', //optional - key value to replace in src path
'#{baseDistPath}': '/'
}
},
basic: {
options: {
tasks: {
js: ['concat', 'uglify'],
css: ['concat', 'cssmin']
}
},
files: [
{
dest: 'templates/compiled/layouts/default.jade',
src: 'templates/layouts/default.jade'
}]
}
},
copy: {
// copy UI assets for development
development: {
cwd: 'public',
src: '**/*',
dest: 'public/public',
expand: true
},
production: {
cwd: '/dist',
src: '**/*',
dest: 'public/dist',
expand: true
},
production_fonts: {
cwd: 'public/fonts',
src: '**/*',
dest: 'public/dist/fonts',
expand: true
},
production_fontsAwesome: {
cwd: 'bower_components/font-awesome-bower/fonts',
src: '**/*',
dest: 'public/dist/fonts',
expand: true
}
}
});
// Actually load this plugin's task(s).
grunt.loadTasks('tasks');
// Whenever the "test" task is run, first clean the "tmp" dir, then run this
// plugin's task(s), then test the result.
grunt.registerTask('[production]', [
'jadeUsemin:basic',
'copy:development',
'copy:production',
'copy:production_fonts',
'copy:production_fontsAwesome'
]);
};
Place JavaScript/CSS Files in Jade Template
The next thing to do is add HTML comments as follows for your JavaScript or CSS. The file path after build:js will be the actual file path when running the Grunt task.
There's a trick here: when I wrote the path starting with a slash /, the Grunt task created post.js in my local drive's root folder. If I didn't add the slash, it would create the file under my current application's root folder. That's why I'm using a workaround in my copy task command. I think I need to figure out a better way to do it.
block js
script(src='https://apis.google.com/js/platform.js', async='', defer='')
//-<!-- build:js /dist/js/post.js -->
script(src='./public/js/shared/socials/facebook_sdk.js', type='text/javascript')
script(src='./public/js/shared/socials/share_core.js', type='text/javascript')
script(src='./public/js/shared/socials/share_facebook2.js', type='text/javascript')
script(src='./public/js/shared/socials/share_googlePlus.js', type='text/javascript')
//-<!-- endbuild -->
Keystone.js Init
I copy all the Jade templates to another folder in the Grunt task. Because of this, I need the ability in Keystone.js to use different view templates in development and production.
The following is what I did in Keystone.js:
var viewPath = 'templates/compiled/views';
if (process.env.NODE_ENV === 'development') {
viewPath = 'templates/views';
}
keystone.init({
'views': viewPath,
....
});
Conclusion
I'm happy that in Keystone.js I was able to achieve the following by using a Grunt task. In production, you'll get the most optimized environment:
- Minify CSS
- Minify JavaScript
- Minify HTML
- Ability to switch minification on/off in development
There are a few things I don't think I'm doing right, so I need to figure them out in the future:
- How to set up paths in the Jade template correctly