0

Sometimes I've come across a particular pattern present in some javascript libraries. Maybe it's a coincidence but I've seen it in libraries with dependencies. The syntax is as follows (The sample is taken from Backbone which has a hard dependency on underscore)

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
            root.Backbone = factory(root, exports, _, $);
        });
  } else if (typeof exports !== 'undefined') {
      var _ = require('underscore');
      factory(root, exports, _);
  } else {
      root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
  }

}(this, function(root, Backbone, _, $)

Can someone explain why this pattern is used. The parts I don't understand very well is the use of the factory variable, why is testing for the property define.amd and why exports is loaded as a dependency in define(['underscore', 'jquery', 'exports'].

I'm familiar with AMD modules but seeing this makes me wonder if I should use the same pattern if I'm writting a library with a dependency or this pattern should be used everytime even if I have no dependencies at all.

1 Answer 1

1

The gist

This is called the universal module definition pattern. It comes in countless variations. The core of it is that JavaScript has no builtin module system (up until ES6 modules become widely adopted) and there are numerous of these out there to fill the gap (e.g. requirejs, yepnope, labjs). So the UMD is a pattern that has been conceived in order for your modules to support module systems in multiple environments, since JavaScript is now being used almost everywhere.

Your example

In your example you will be supporting script loaders that understand the Asynchronous Module Definition, CommonJS module loaders like the one that NodeJS introduced as well as plain browsers or other environments that don't expose a module system that the definition is aware of:

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // This branch is to support AMD loaders
        define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
            root.Backbone = factory(root, exports, _, $);
        });
  } else if (typeof exports !== 'undefined') {
      // This supports the CommonJS module system that NodeJS uses
      var _ = require('underscore');
      factory(root, exports, _);
  } else {
      // Attaching your library root in an environment that has no
      // module system or a system you don't support like a plain
      // browser before ES6 modules become the standard
      root.Backbone = /* ... */
  }

}(this, function(root, Backbone, _, $)

With this boiler plate code you can write your module once and at the same time it can be used with different loaders/build tools in the browser, on the server and everywhere else you may find a JavaScript environment.

I suggest you read up on JavaScript modules/module systems to get a deeper insight. Addy osmani's blog is also a good place to start. There are dozens of resources on the topic.

Hope this helps! Happy coding.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.