Search code examples
javascriptmodulerequirejsamd

RequireJS: bundling module with plugins


I'm using an external library that consists of a "core" plus multiple "extensions". Every extension depends on the core. Think jQuery or Rx.

What I need to do is to bundle the core together with some of the extensions and provide that as a single module. On the surface, it seems that something like this should work:

// lib.js
define(
    "lib",
    ["./Lib/lib", "./Lib/ext1", "./Lib/ext2"], 
    function(lib) { return lib; }
);

The problem, however, is that extensions expect the "core" to be available by the module ID of "lib". In other words, "ext1" is defined like this:

// Lib/ext1.js
define( ["lib"], function(lib) { lib.ext.someFunc = ... } );

One can spot the problem here: because the name "lib" refers to my "bundled" module instead of just the "core", it is not yet available at the time ext1 loads, so the whole chain becomes circular and falls apart.

Of course, I could map the core to "lib" and then give my bundled module a different name:

// main.js
require.config( { paths: { lib: "Lib/lib" } } );

// lib.js
define(
    "bundled-lib",
    ["./Lib/lib", "./Lib/ext1", "./Lib/ext2"], 
    function(lib) { return lib; }
);

But that approach is highly undesirable for a few reasons:

  1. It's just plain inconvenient to use a different name. There is no good common sense name that I could use instead, "lib" is pretty much the only option, and anything else will look ugly.

  2. But more importantly, this may lead to hard-to-catch bugs. Down the road, when I have forgotten all about this little hack, I may just follow my common sense and import "lib" instead of "bundled-lib", and then my extensions will not get loaded. Or sometimes they will. If some other module which correctly imports "bundled-lib" just happens to load before the new "lib"-importing module, then it will work. Otherwise, it won't. Meaning that my application will either crash or not depending on whether certain features have or have not been used.

So the bottom line is, I would like to bundle the core with extensions, call the bundle "lib", but somehow have the extensions to only import the core, while not modifying the extensions themselves.

Any ideas anyone?


Solution

  • So just a few hours after asking the question, I have found the answer on my own.

    The answer is - the map config of RequireJS.
    Basically, as it turns out, I can define a mapping of module names as seen by each module individually.

    In particular, my problem as it is described in the question, would be solved by the following configuration:

    require.config( {
        map: {
            'ext1': { 'lib': 'Lib/lib' }
            'ext2': { 'lib': 'Lib/lib' }
        }
    } );
    

    This will make both ext1 and ext2 see module 'Lib/lib' as 'lib', while not affecting all other modules.