Understand the different javascript modules formats

Home>Web>Understand the different javascript modules formats

- 3 min read

When it comes to building your application, if you're like me you always ask yourself: which format should I use ? CJS ? AMD ? UMD ? ESM ? What are the differences ? Why so many formats ?

Through this article, I'll try to answer those questions 😊.

The different formats

CommonJS (CJS)

This is one of the first format created. I'm pretty sure you've already used it. It's the module system that initially inspired NodeJS.

This system relies on importing and exporting modules thanks to some well-known keywords: require and exports. The module.exports object is really specific to NodeJS.

  // utils.js
  // we create a function 
  function add(r){
    return r + r;
  }
  // export (expose) add to other modules
  exports.add = add;


  // index.js
  var utils = require('./utils.js');
  utils.add(4); // = 8

The commonJS team created this API as a synchronous one which is not that good for browsers... Moreover, Commonjs isn't natively understood by browsers; it requires either a loader library or some transpiling.

Asynchronous Module Definition (AMD)

AMD is some kind of a split of CommonJS. It has been created by members of the CJS team that disagreed with the direction taken by the rest of the team.

They've decided to create AMD to support asynchronous module loading. This is the module system used by RequireJS and that is working client-side (in browsers).

  // add.js
  define(function() {
    return add = function(r) {
      return r + r;
    }
  });


  // index.js
  define(function(require) {
    require('./add');
    add(4); // = 8
  }

This example works only if you have requirejs on your website. You can find some other examples here.

Universal Module Definition (UMD)

As you may have understood those 2 formats are unfortunately mutually unintelligible to each other. This is why the UMD has been created. It is based on AMD but with some special cases included to handle CommonJS compatibility.

Unfortunately, this compatibility adds some complexity that makes it complicated to read / write. If you want, you can find multiple templates of UMD code on this github repository.

ES2015 Modules (ESM)

As those 3 formats are not that easy to read, hard to analyze for static code analyzer and not supported everywhere, The ECMA team (the team behind the standardization of Javascript) decided to create the ECMAScript 2015 (also known as ES6) standard. This format is really simple to read and write and supports both synchronous and asynchronous modes of operation.

  // add.js
  export function add(r) {
    return r + r;
  }


  // index.js
  import add from "./add";
  add(4); // = 8

Moreover, es modules can be statically analyze which allow build tools (like Webpack or Rollup) to perform tree-shaking on the code. Tree-shaking is a process that removes unused code from bundles.

Unfortunately, this format still have 2 cons (but they're improving):

  • ESM doesn't supports dynamically imported modules but there is a proposal for months now that has started to be implemented on some browsers.
  • It isn't supported on all the browsers but fortunately, this can be "fixed" thanks to... transpiling !

Transpiling

Transpiling is the process of translating one language or version of a language to another. So here, the idea is to transpile ES6 to ES5 to get a better browser support. Unfortunately, this transpilation has a cost as it adds some extra code to patch the missing features of ES6 that don't exist in ES5.

The most famous transpiler that is usually used in this case is Babel.

Further readings

If you want to go further (through examples, explanations, etc.) to understand how those different formats work, here are some readings I've found and that inspired me:

If you liked this article, please share it on Twitter.

Victor Gosse

@VictorGosse

I work at Attineos since 2015 as a front-end developer. This blog is mine and I'll be very happy to discuss about it with you in DM on Twitter.