Compile a RequireJS Project to a Single File

Splitting all your JavaScript code into modules and loading them with RequireJS makes for a warm and fuzzy development experience. At some point though, I'd like to deliver a single file with all the dependencies included. The biggest reason being that HTTP requests are expensive and by lazy-loading all your tiny modules, RequireJS makes a lot of them.

There's an optimizing tool for RequireJS called r.js. You can use it to minimize and concatenate your code. The documentation is in a few places and I had a bit of trouble getting it to do what I want. IMHO the best source of info after the basic stuff is the example build file with all the options explained. For installation instructions just check out the documentation.

In this tutorial I'm going to walk you through my build file with a few added comments. Except for a few dirs omitted for brevity, my project structure looks like this:

├── README.md
├── app
│   ├── libs
│   ├── main.js
│   ├── models
│   ├── require.js
│   ├── templates
│   └── views
├── build.js
└── package.json

All the code is in app and external dependencies are in app/libs. The build.js file looks like this.

({
  baseUrl: 'app',
  out: 'build/main.js',

Your paths will be relative to the baseUrl so it makes sense to make this the app folder as all the files there. Specifying the out parameter tells r.js that you want everything in one file. The alternative is specifying dir in which case the contents of your app folder are copied into that dir.

A few options like appDir, dir and modules are incompatible with out aka compiling to a single file so don't use those.

  include: ['libs/almond', 'main'],
  wrap: true,

Usually, you would use the name parameter to specify your main module but we're using include here because we're bundling the almond loader as well. Almond is a much smaller and simpler AMD loader that makes sense in our case because we're not loading modules dynamically.

The include parameter is an array specifying which other modules to include in the build. When we specify the "main" one, r.js traces all other modules that main depends on and includes them.

Wrap, unsurprisingly wraps module requires into a closure so that only what you export gets into the global environment. To be honest, I don't really need this but if you're bundling a widget or something someone will use with a lot of other stuff I guess it's a good idea.

  exclude: ['coffee-script'],
  stubModules: ['cs'],

I use CoffeScript for development and compile files in the browser. This is obviously slower than it needs to be for production so we exclude the compiler module and "stub out" the cs loader plugin. This results in all coffee files being compiled to JavaScript and inlined.

  paths: {
    backbone: 'libs/backbone-amd',
    underscore: 'libs/underscore-amd',
    jquery: 'libs/jquery',
    cs: 'libs/cs',
    'coffee-script': 'libs/coffee-script',
    text: 'libs/text'
  }
})

The rest of the file is a standard paths configuration.

Finally to compile, run:

r.js -o build.js

And your compiled project should be in build/main.js.

A sincere thank you to James Burke for reviewing this post.

Check out my other posts →