Posted by & filed under Javascript.

In a previous post Building React.js with Grunt I have shown how we used Grunt to build our React files. But our issues were not over. We have a total of ~ 250 Javascript files in our project, not counting vendor libraries. Approximately 2/3 of these files are React views, while the rest are our Backbone models, collections, Chaplin controllers, libraries and miscellaneous application files. All of them are RequireJS modules.

Now the biggest problem with this was that to load main page of our application, browser needed to download 112 JS files. Using grunt-contrib-requirejs and a list of custom modules to optimize JS files helped a bit: now instead of 112 files browser loaded only 71. That’s better but far from ideal. At this point, I was having two problems: files optimized by r.js were not nested, and I had to manually maintain list of modules. After a bit of trial and error I have managed to decrease number of loaded files to just 9. How did I do this?

Here’s the solution I came to so far

To build static files for production I use a series of Grunt tasks:

  1. shell:make — invokes make for vendor files that need building
  2. shell:build-jsx — compiles React view files to JS as per previous post
  3. shell:clean-jsx-cache — removes .module-cache folder from compiled views
  4. prep-rjs-modules — makes a list of JS files that need to be optimized by r.js
  5. requirejs:all — optimizes using grunt-contrib-requirejs
  6. stylus — compiles Stylus files to CSS

Now I’d like to explain steps 4 and 5 in more detials:

prep-rjs-modules Grunt task does two things: 1) creates a list of JS files for optimizer, and 2) removes “jsx!” from compiled React modules.

Removing “jsx!” is necessary because otherwise running requirejs task will fail with an error, example:

Error: Loader plugin did not call the load callback in the build:

Let me show you actual code examples:

Code snippet for prep-rjs-modules task

Note that in the last line we pass list of modules to requirejs config if grunt is run with --prod flag. I know that this looks like a hack, but so far it works and maybe I will find a more elegant solution later.

Requirejs Grunt task file

Note that findNestedDependencies flag is set to true, otherwise r.js will not nest dependencies. Also note that modules is an empty array. When it’s empty, r.js will not convert JS files to built modules. We do not create optimized modules for development, therefore as I have shown above, list of modules is passed to requirejs only when grunt is executed with --prod flag.

And finally, because we use separate files per each Grunt task, you load these example files as follows:

grunt.registerTask('prep-rjs-modules', 'Make JS files ready for requirejs optimization', require('./grunt/prep_rjs_modules').bind(this, grunt));

Leave a Reply

  • (will not be published)