How to Use Grunt with Keystone.js for Minify CSS, Javascript and HTML

2016/2/13 min read
bookmark this
Responsive image

I'm using keystone.js with Jade view template engine, back-end is MongoDB, I didn't try Grunt at Keystone.js before, this blog is How I tried, it's not perfect but the output is close to what I want. So anyway, from browser source code point of view, following is what I want.

  • Minify CSS/Javascript
  • Minify Html
  • In Development mode, I should have choice to not minify CSS/Javascrout, not minify HTML.

So following are list of things how I tried to make it happen.

1. Grunt file setup


Use grunt-jade-usemin

First thing I'm doing here is use jadeUsemin setup task for jade template. Then, there are some clean up so I can make my web application work, which is 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 at Jade template

Next thing to do is, add html comment as following for your javascript or CSS, the file path after the build:jswill be the actual file path when run the Grunt task.

There're some trick here, when I wrote the path start with slush /, grunt task will create this post.jsto my local drive's root folder. If i didn't add the sluch then will create the file under my current application's root folder. That's why I'm doing cheat here at my copy task command. Something i think I need to figure out the 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 template to another folder at Grunt task, because of this I need ability at keystone.js when in development/production use different view template.

Following is what I did at 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 at Keystone.js I'm able to achieve following thing by using grunt task, on Production you'll get most optimized enviroment.

  • Minify CSS
  • Minify Javascript
  • Minify HTML
  • Ability to swich minify on/off in Development

There are list of thing I don't think I'm doing it right, so need to figure out in the future.

  • How to setup path at jade template