Grunt for requirejs projects

Fri 05 July 2013
  • 装备 tags:
  • Grunt
  • javascript published: true comments: true

the Problem

You have modularize your JavaScript project with requirejs. And you need a build tool for both development and deployment phases, helping you to organize, optimize the source code.

the Solution

Grunt has been the standard tool chain for web development. I used to think the grunt configuration file could be verbose and complicated, because the JavaScript world has never come up with a standard, even common, archetype (until yeoman, but it's after Grunt). The projects are organized manually, or by some custom shell scripts. So grunt cannot take the advantage of 'convention over configuration', which Maven does well in the Java world.

This idea was changed until I use Grunt seriously. Grunt configuration parser has excellent support for expressions of 'path'. You can use wildcards like 'src/*.js', 'src/**/*.js', ['src/**/*.js', 'vendor/lib/*.js'] and even more 'path' to find and match your files. You don't have to write your script name one-by-one. I'm sure Grunt developers have lots of experience on JavaScript development so they know the problem.

So I strongly recommend you to use Grunt to manage your JavaScript project, especially when it's a large project.

Assume you have your JavaScript sources in 'src', and the 'src/main.js' is the entry point of your requirejs modules.

The first step is to create a work directory for publishing your sources, say 'public', and also put your vendor scripts in 'src/libs' Setup your first Grunt task, copy:dev. The copy plugin is one of the most used plugin for copying files. This will copy your source code from src/ to public/, as well as your vendor scripts.

copy: {
  dev: {
    files: [
      {expand: true, src: ['src/**/*.js'], dest: 'public/js', filter: 'isFile'}
    ]
  }
}

Then move your requirejs.config from html to your main.js. Require.js is able to read configuration after it loaded your entry script. This is of great helpful for optimized code.

In development phase, you can have your static server over 'public'. For deployment, you need to optimize the JavaScript code: concat and uglify. This can be done with r.js, which is developed by requirejs project. Grunt also has a plugin to integrate r.js, grunt-contrib-requirejs. r.js could concat all requirejs modules by analyzing their dependency tree. You need a simple config for that:

requirejs: {
  compile: {
    options: {
      baseUrl: "src/",
      mainConfigFile: "src/main.js",
      out: "public/js/main.js"
    }
  }
}

The mainConfigFile is the JavaScript file contains requirejs.config. r.js can also parse it from a requirejs module. r.js will concat and uglify all your scripts, include vendor scripts in one file, output as 'public/js/main.js'. With the same name of your entry point.

With that, you don't have to change any single line of js/html for switching between deployment and development. During development, requirejs loads JavaScript files on demand. While on the production, it loads main.js with all dependencies combined in.