Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

usemin revved filenames and requirejs dependencies

I'm running into the following problem with requirejs and usemin:

I want to setup a multipage application, where I dynamically load modules that only contain page specific functionality (e.g. about -> about.js, home -> home.js). I could go ahead and pack everything in a single file, but that just leads to a bigger file size and overhead on functionality that isn't necessary on each site! (e.g. why would I need to load a carousel plugin on a page that doesn't have a carousel!)

I checked out the example https://github.com/requirejs/example-multipage-shim

That is in fact a great way to deal with it, until I bring usemin into the game. After revving the filenames the src path of each script tag is updated, but what about the dependencies?

<script src="scripts/vendor/1cdhj2.require.js"></script>
<script type="text/javascript">
   require(['scripts/common'], function (common) {
      require(['app'], function(App) {
          App.initialize();
      });
   });
</script>

In that case, require.js got replaced by the revved file 1cdhj2.require.js. Great!

But the required modules "common" and "app" no longer work since common became 4jsh3b.common.js and app became 23jda3.app.js!

What can I do about this? Thanks for your help! (Also using Yeoman, btw)

like image 718
manuel-v Avatar asked Jan 28 '13 07:01

manuel-v


2 Answers

It's a tricky problem and I'm sure somebody else fixed in in a more elegant way, but the following works for me.

I might publish this as a grunt plugin once it's a little more robust.

Taken from my Gruntfile:

"regex-replace": {
  rjsmodules: { // we'll build on this configuration later, inside the 'userevd-rjsmodules' task
    src: ['build/**/*.js'],
    actions: []
  }
},


grunt.registerTask('userevd-rjsmodules', 'Make sure RequireJS modules are loaded by their revved module name', function() {
// scheduled search n replace actions
var actions = grunt.config("regex-replace").rjsmodules.actions;

// action object
var o = {
  search: '',
  replace: '', //<%= grunt.filerev.summary["build/js/app/detailsController.js"] %>
  flags: 'g'
};

// read the requirejs config and look for optimized modules
var modules = grunt.config("requirejs.compile.options.modules");
var baseDir = grunt.config("requirejs.compile.options.dir");

var i, mod;
for (i in modules) {
  mod = modules[i].name;
  revvedMod = grunt.filerev.summary[baseDir + "/" + mod + ".js"];
  revvedMod = revvedMod.replace('.js', '').replace(baseDir+'/','');

  o.name = mod;
  o.search = "'"+mod+"'";
  // use the moduleid, and the grunt.filerev.summary object to find the revved file on disk
  o.replace = "'"+revvedMod+"'";
  // update the require(["xxx/yyy"]) declarations by scheduling a search/replace action
  actions.push(o);
}

grunt.config.set('regex-replace.rjsmodules.actions', actions);
grunt.log.writeln('%j', grunt.config("regex-replace.rjsmodules"));

grunt.task.run("regex-replace:rjsmodules");
}),
like image 199
Dave Goulash Avatar answered Sep 22 '22 01:09

Dave Goulash


You can also use requirejs' map config to specify a mapping between your original module and your revved one. Filerev outputs a summary object containing a mapping of all the modules that were versioned and their original names. Use grunt file write feature to write a file in AMD way with the contents being the summary object:

// Default task(s).
grunt.registerTask('default', ['uglify', 'filerev', 'writeSummary']);

grunt.registerTask('writeSummary', 'Writes the summary output of filerev task to a file', function() {
    grunt.file.write('filerevSummary.js', 'define([], function(){ return ' + JSON.stringify(grunt.filerev.summary) + '; })');
})

and use this file in your require config so that the new revved modules are used instead of old ones:

require(['../filerevSummary'], function(fileRev) {

var filerevMap = {};
for (var key in fileRev) {
    var moduleID = key.split('/').pop().replace('.js', '');
    var revvedModule = '../' + fileRev[key].replace('.js', '');

    filerevMap[moduleID] = revvedModule;
}

require.config({
    map: {
        '*': filerevMap
    }
});

The filerevMap object that I created above is specific to my folder structure. You can tweak it as per yours. It just loops through the filerev summary and makes sure the keys are modified as per your module names and values as per your folder structure.

like image 38
Rahul Dole Avatar answered Sep 23 '22 01:09

Rahul Dole