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:
shell:make— invokes make for vendor files that need building
shell:build-jsx— compiles React view files to JS as per previous post
shell:clean-jsx-cache— removes .module-cache folder from compiled views
prep-rjs-modules— makes a list of JS files that need to be optimized by r.js
requirejs:all— optimizes using grunt-contrib-requirejs
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: jsx: jsx!views/layout/base-layout
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
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
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));