Inject Add-Ons And Plugins With RequireJS, Non-AMD Libraries And Shims


I’m using a few libraries that don’t have official support for AMD, in my current project with RequireJS. No problem – just shim the library in, and it’s good to go. Some of these libraries also need some add-ons and plugins, though… and there aren’t necessarily official hooks for the add-ons, either. So I find myself in this situation: I need a non-AMD library with non-AMD add-ons, loaded through a single require statement in my module. What to do?

Named Dependencies

In your app configuration for RequireJS, you can name dependencies to make it easier to load them later. I do this for my 3rd party libraries and other common things in the app.

Example:

I’ve named “jquery”, “rsvp”, “kendoui” and “thatCoolLib” (a made up example name for this post) here, so that I don’t have to load them by the full path, later.

Now I can include these libs in my other modules with just the name.

Now let’s say that I now want to load an add-on for thatCoolLib, by including yet another file in the project. Perhaps I want to add a new function to an existing prototype from that library. How do I do that?

Hijacking The Named Dependencies

Say I’ve got this awesome plugin for thatCoolLib:

I want to get this loaded in to the library whenever I require “thatCoolLib”, but I don’t want to specify yet another dependency in my modules. I just want this add-on to be available, always. To do that, I can hijack the named dependencies, and compose the modified version of thatCoolLib at runtime.

Rename the current “thatCoolLib” in the requirejs config, to “thatCoolLib.original” or any other name that would say this is the original version. Keep it pointing to the same file, though – just change the name.

Now add another named dependency, called “thatCoolLib” – yes, the name that you just changed – and point it to a new file. In this case, I’ll point it to “vendor/thatCoolLib.bootstrap”.

Create the “thatCoolLib.boostrap.js” file, next. Add a standard AMD module to it, and require the “thatCoolLib.original” in to the module. Now you can modify the original object with your add-on code, and then return thatCoolLib from your new module. You can even include other external files, and attach the functions to the library inside of this module.

New Behavior Without Modifying The Rest Of The App

Now when any part of your app requires “thatCoolLib” in to a module, it will get the new behavior from the plugins. But the best part, here, is that any existing use of “thatCoolLib” will also have the new behavior available, without having to change any of the dependencies, or any any new dependencies, in the existing modules.

My attempt to understand the dark side… err… AMD/RequireJS