An Introduction to CommonJS

June 16, 2015

The CommonJS specification includes a module loading syntax to cleanly specify JavaScript dependencies. While first widely used in Node it is now used heavily in the browser as well. Historically, when specifying dependencies for the browser, we have had to manually manage a list of our files and keep them in the right order. For the modules to communicate, everything had to be in global scope.

The Basics of CommonJS

With CommonJS modules, every file explicitly states its dependencies, letting the tooling figure out what the ordering is. Using CommonJS modules also keeps us from polluting the global namespace which enables engineers to now write and distribute high quality libraries with shared dependencies.

Every CommonJS module is given two main globals: module.exports and require.

Require Caches Modules

From Good Eggs: “An important behavior of require is that it caches the value of module.exports and returns the same value for all future calls to require. It caches based on the absolute file path of the required file.”

You can see that require is returning the same reference for each call.

Different Exporting Styles

There are a few different ways that you can and should export from your module. They are good for different times and different uses. Exporting objects and classes are the most common patterns we use.

  • Objects
  • Classes
  • Singletons
  • Monkey Patch

Objects

You can also use this style to return a collection of functions that don’t share any state:

Classes

If you want to have multiple instances with shared state, then you should probably be exporting a class.

Singletons

Since require caches the value assigned to module.exports, all calls to require the module are given the same reference. This makes creating a singleton extremely similar to creating a class. We simply return a new instance of our class.

Monkey Patch

Warning! This pattern is dangerous and should rarely ever be used. Monkey patches are modules that modify global state. You may also hear them called shims.

This is typically a very dangerous pattern to follow because it breaks the dependency graph of the application. Depending on where shim is required we could be changing the behavior of our application.

This is typically only a reasonable thing to do if you are importing polyfills at the very top of your application. This will have pretty much the same behavior as saying:

Public / Private State

One of the great parts about CommonJS is that everything is private except for what is set to module.exports. That means that we can separate our public api and private helpers quite easily:

Simply don’t export the things you don’t want to have be public, and they won’t be accessible!

Conclusion

Specifying dependencies using CommonJS enables us to work on individual units of code and better reason about the environment they are being run in. By explicitly stating the dependencies for each file we don’t need to maintain an ordered list of our files and can instead let our tools figure that out for us.

Writing our JavaScript in this way lets us be more explicit about what API modules provide while hiding their implementation. Our engineering team at Wealthfront has found the developer productivity gains and ease of testing invaluable with CommonJS and thinks you will too.

Read More

The CommonJS module syntax is the key behind reusable JavaScript code and is utilized by a large number of tools. Node uses CommonJS by default, and NPM is a package manager for people to distribute and share packages of CommonJS modules.

Browserify and Webpack are both bundlers which can be given a CommonJS module. They will walk the dependency tree of requires and bundle all of the files’ dependencies into a single file (generally) that is then meant to be used on websites. Ben Clinkinbeard has written a great post explaining how Browserify works with CommonJS.