Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I load multiple optimized requirejs modules dynamically in a production env?

I've started to play with require js on a dummy project. I now want to use the r.js script to build my project for production.

The context is this:

  • Main file called start.js is:

    require([/* some stuff */], function (){ /* app logic */ });
    

    which has an if that decides what I should require based on some condition.

  • The required files are either ModuleA or ModuleB

  • Both ModuleA and ModuleB have dependencies.

    define([/*some deps*/], function(dep1, dep2...) { 
        /* app logic */ 
        return { /* interface */
    }
    
  • Everything works fine in development mode, before optimization and module concatenation.

  • When building with r.js I specify as module targets the following : modules : [ { name : "start" }, { name : "ModuleA" }, { name : "ModuleB" } ]

The problem is that my ModuleA becomes :

 define(dep1 ..);
 define(dep2 ..);
 define(ModuleA ..);

But nothings loads from ModuleA. The code from ModeulA in development loads and executes, the code after building loads but does not run.

How could I fix this problem?

UPDATE

http://pastebin.com/p1xUcY0A --> start.js

http://pastebin.com/dXa6PtpX --> ModuleA js-animation.js

http://pastebin.com/xcCvhLrT --> ModuleB css-animation.js no deps.

http://pastebin.com/j51V5kMt --> The r.js config file used when running the optimizer.

http://pastebin.com/UVkWjwe9 --> How the js-animation.js looks after running r.js. This is the file that has problems. I don't get the js-animation module from this file. The require does not return my js-animation object.

Edit:

After removing the .js at the end of the module definitions and in from start js, the optimized start.js is http://pastebin.com/LfaLkJaT and the js-animations module is http://pastebin.com/qwnpkCC6. In chrome, I get this error in my console http://pastebin.com/Hq7HGcmm

like image 875
Vlad Nicula Avatar asked Aug 07 '12 23:08

Vlad Nicula


People also ask

Is RequireJS synchronous?

So, RequireJS doesn't support it. From your use case it seems that you don't need synchronous RequireJS, you need to return result asynchronously. AMD pattern allows to define dependencies and load them asynchronously, but module's factory function must return result synchronously.

What is Shim RequireJS?

shim: Configure the dependencies, exports, and custom initialization for older, traditional "browser globals" scripts that do not use define() to declare the dependencies and set a module value. Here is an example. It requires RequireJS 2.1. 0+, and assumes backbone. js, underscore.

What is a RequireJS module?

RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code.

How do I use require config?

RequireJS can be initialized by passing the main configuration in the HTML template through the data-main attribute. It is used by RequireJS to know which module to load in your application. To include the Require. js file, you need to add the script tag in the html file.


1 Answers

I believe the problem with your setup is that you end your module dependency names in .js. As per the docs:

RequireJS also assumes by default that all dependencies are scripts, so it does not expect to see a trailing ".js" suffix on module IDs. RequireJS will automatically add it when translating the module ID to a path.

If RequireJS sees a module name ending in .js it assumes that the module name is a path relative to the document. By ending your module dependency names in .js it works fine in development mode because RequireJS will go and load the file specified as a dependency. In your case it will load the file js/js-animation.js, see an anonymous define and load the module properly.

In production, your start.js module still requires "js/js-animation.js". RequireJS will load your optimized module at the path js/js-animation.js but now the optimizer has converted your anonymous modules into named modules (in this case "js/js-animation"). The result is the file will be loaded but no define'd modules within the file have a name that matches "js/js-animation.js" so in a sense your animation module is missing.

Solution / TL;DR: Remove the trailing .js from all your module dependency names (and your module definitions in the r.js config) and you should be fine. So your start.js should become (changes on line 4):

require([], function () {
  var $html = $("html"),
    animationModule = localStorage['cssanimations'] == 'true' ? 
    'js/css-animation' : 'js/js-animation',
    $doc = $html.find("body");

  console.debug("loading ", animationModule);
  require([animationModule], function( animationModule ) {
    animationModule.run({
      target : $("div.flex")
    });
  } );
} );

Also note your may want to use baseUrl and paths in your RequireJS config to clean up module names (e.g. so you can remove the js/ prefix).

like image 174
rharper Avatar answered Sep 19 '22 18:09

rharper