Friday, March 7, 2014

Introducing grunt-namespacer Task

Grunt has caught my eye, again, as a nice way to "build" all my javascript into a small, clean file that I can include in the websites I work on.

With the Grunt setup complete on the Wordpress site/theme I am working on, I started looking for a way to concat, closure wrap, and compress/obfuscate all the JavaScript in my source folder so I can separate out my scripts into different files (kinda like how a bunch of node.js projects work). I figured, at the most, this would be nice for utility functions that I could copy from site to site with minimal code editing.

My searches on GitHub lead me to the following tasks: grunt-contrib-concat, grunt-wrap, grunt-contrib-uglify. But, after setting up these tasks and doing some test builds, I started thinking that it would be nice if there was a task that would create namespaces automatically to avoid method name collisions. The only task I could find that was close was grunt-autowrap but it didn't do exactly what I wanted. This lead me into looking at how to build your own grunt tasks.

This is what I ended up with: grunt-namespacer.

//Gruntfile.js
grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    
    //grunt-namespacer task config
    namespacer : {
        basic : {
            src: 'js/src/app/',
            dest: 'js/build/'
        }
    }
    ...
  });

  // Load the plugins for all tasks.
  grunt.loadNpmTasks('grunt-namespacer');

  // Default task(s).
  grunt.registerTask('default', ['namespacer']);

This task will take your javascript files and concat and closure wrap them based on your folder structure.

For example, if your folder structure in your js folder is like this:
+ src/
    + app/
        init.js
        + controls/
            checkbox.js
            tabs.js
            forms.js
        + models/
            person.js
            cart.js
        + utils/
            empty.js
            json.js
            ajax.js

Then after you run the namespacer task you will get a file named 'app.js' (base folder name), and be able to access everything like this:
app.init.run();

var person = new app.models.Person('Dave');
app.utils.ajax('/register', person, function(response)
{
    person.id = response.data.id;
});

Also, scope is based on folder so any function in tabs.js can access methods in forms.js without having to use the namespace.

This task is free to use and I welcome any comments to help improve it.

later,
-Jason

No comments:

Post a Comment