ariya.io About Collections Archives

Esprima and Harmony Module

4 min read

When developing a large-scale application, modularity becomes an important factor. If the environment is JavaScript, several module patterns, from AMD to CommonJS, are available for your disposal. Every one of them usually works around the fact that there is no linking stage in JavaScript, all compilation units are loaded together. Fortunately, this issue is addressed in Harmony, aka the next-generation ECMAScript, since it will introduce a new form of module system.

As of now, no JavaScript environment understands the Harmony module syntax yet. Therefore, there is no way you can use the syntax directly. One possible solution is to convert this future syntax to something which can be consumed by this generation’s browsers. It’s like Back to Future, except it’s going the other way around. This approach is often denoted as transpilation. Google’s project Traceur is probably one example of such a transpiler. For example, given this futuristic code:

module LinearAlgebra {
    export const CoordinateSystem = 'Cartesian';
 
    // Create 2-D point.
    export function Point(x, y) {
        return { x, y };
    }
}

Traceur will compile it to something like this (note that any comments will be removed):

var LinearAlgebra =(function() { 
  "use strict"; 
  Object.defineProperty(this, "CoordinateSystem", { 
    get: function() { 
      return CoordinateSystem; 
    }, 
    enumerable: true 
  }); 
  Object.defineProperty(this, "Point", { 
    get: function() { 
      return Point; 
    }, 
    enumerable: true 
  }); 
  Object.freeze(this); 
  var CoordinateSystem = 'Cartesian'; 
  function Point(x, y) { 
    return { 
      x: x, 
      y: y 
    }; 
  } 
  return this; 
}).call(Object.create(null));

Careful readers might spot return {x, y}, which is invalid in today’s JavaScript. This is another Harmony feature: property value shorthand for object literals.

Using transpiler seems to be an optimal solution since we can already use the syntax (until one day all JavaScript engines understand the module system) and therefore it’s future-proof. Of course, even better if we can tweak the transpiler to output something which suits our need. Some projects use AMD and might prefer that format as the target compilation. Others may want to preserve all comments, possibly because of important annotation and/or API documentation.

Fortunately, it’s rather possible to create your own transpiler based on Esprima, the ECMAScript parser project I started few months ago. In the harmony branch of Esprima, support for features available in future generation JavaScript is being developed. As of now, it does understand Harmony module syntax on a best-effort basis, since the proposed syntax may change again. You can already try this with the online parser demo. If you paste the previous example and visualize the syntax, it will be like the following (collapsed at the statement level, but you get the idea):

Once you get the syntax tree, it’s now easy to convert the syntax. Because Esprima can track the location of each syntax node, there is no need to regenerate the entire code (like what Traceur does). This is what I often call as non-destructive partial modification (those who follow my blog may notice that I’ve previously used the same technique to change string literal quote, inject function prolog, and track application startup). Essentially we are just interested in the module construct (since we want to transpile it) and therefore we won’t touch anything else, hence the term non-destructive. This also means that comments and formatting will be intact!

As the demo, please just use Esprima-based online transpiler (part of the harmony branch, not the master branch). The previous example will be converted into (note how the the single-line comment there is not removed at all):

var LinearAlgebra = function() {
    const CoordinateSystem = 'Cartesian';
 
    // Create 2-D point.
    function Point(x, y) {
        return { x: x, y: y };
    }
 
    return {
        CoordinateSystem: CoordinateSystem,
        Point: Point
    };
}();

The core functionality of the module transpiler is actually a separate project by Jason Diamond, it’s called Harmonizr. In fact, Harmonizr can target other types of module including AMD and Node.js, see its really cool online demo you can play with. It should not also come as a surprise that Harmonizr transpiles itself.

It’s hot, don’t you think so?

Related posts:

♡ this article? Explore more, check the archives, or follow me Twitter.

Share this on Twitter Facebook Google+

comments powered by Disqus