7
votes

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

2
I can paste the entire code of the dummy project, it has around 300 lines though.Vlad Nicula
put your code on pastebin.com and edit your question and attach your pastebin url :)Andrei Sfat
not sure if pastebin is a good options. The projects has 4 js files in dev, and should have 3 in production. :|Vlad Nicula
Clarification: does your "start" module have logic outside of the require that generates an array of dependencies? And if so, this array will contain the dependency name "ModuleA" or "ModuleB"? Maybe you could just add the code for start.js...rharper
Thanks for the comment @rharper. My start.js module has two requires inside it. Only one of the two inner require calls is done based on a condition. Did that clarify my situation?Vlad Nicula

2 Answers

1
votes

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).

1
votes

It seems this is problematic with the current require.js implementation. The way around it was to create a global mediator or mediator module and have all dynamically loaded modules call the mediator and announce themselves via an event. This worked for me.