Combining and Minifying JavaScript Files with Google Closure Compiler

GOAL

The goal is to combine and minify several JS files into one JS file in the right order.

PROBLEM

Let’s assume we have the following directory structure with three JS files.

Directory Structure

appdev
└── src
    ├── appdev.blackcow.js
    ├── appdev.js
    └── appdev.whitesheep.js

appdev.js

var AppDev = {
    modules : [],

    start : function () {
        var moduleName;
        for ( moduleName in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( moduleName ) ) {
                AppDev.modules[moduleName]();
            }
        }
    }
};

appdev.blackcow.js

AppDev.modules.blackcow = function ( config ) {
    console.log( 'in black cow module...', config );
};

appdev.whitesheep.js

AppDev.modules.whitesheep = function ( config ) {
    console.log( 'in white sheep module...', config );
};

SOLUTION

To pull this off, we will leverage Google Closure Compiler.

There are multiple ways to use this compiler, but if you are using Mac, the easiest approach, in my opinion, is to install this compiler using Brew.

brew install closure-compiler

Once installed, navigate to the appdev directory and run the following command:-

closure-compiler --js `find src/**/*.js` --js_output_file appdev.min.js

Now, a new file called appdev.min.js will be created.

appdev
├── appdev.min.js
└── src
    ├── appdev.blackcow.js
    ├── appdev.js
    └── appdev.whitesheep.js

The reformatted file content looks like this:-

AppDev.modules.blackcow = function ( a ) {
    console.log( "in black cow module...", a )
};
var AppDev = {
    modules : [], start : function () {
        for ( var a in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( a ) ) {
                AppDev.modules[a]()
            }
        }
    }
};
AppDev.modules.whitesheep = function ( a ) {
    console.log( "in white sheep module...", a )
};

The generated code is going to cause problem because the Closure Compiler basically appends each file content based on the order of the JS file names.

To fix this, we have to specify the dependencies so that the Closure Compiler will auto-sort the files correctly.

appdev.js

goog.provide('AppDev');

var AppDev = {
    modules : [],

    start : function () {
        var moduleName;
        for ( moduleName in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( moduleName ) ) {
                AppDev.modules[moduleName]();
            }
        }
    }
};

appdev.blackcow.js

goog.require('AppDev');

AppDev.modules.blackcow = function ( config ) {
    console.log( 'in black cow module...', config );
};

appdev.whitesheep.js

goog.require('AppDev');

AppDev.modules.whitesheep = function ( config ) {
    console.log( 'in white sheep module...', config );
};

After rerunning the compiler, the file content for appdev.min.js now looks correct.

var AppDev = {
    modules : [], start : function () {
        for ( var a in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( a ) ) {
                AppDev.modules[a]()
            }
        }
    }
};
AppDev.modules.blackcow = function ( a ) {
    console.log( "in black cow module...", a )
};
AppDev.modules.whitesheep = function ( a ) {
    console.log( "in white sheep module...", a )
};
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s