1. Today Shape Security is releasing Bandolier, a Java library that bundles JavaScript written with ES2015 module syntax.

    Bandolier takes JavaScript code like this:

    import { b } from './foo.js'
    console.log(42 + b);
    

    where the foo module is defined as:

    // foo.js
    export var b = 100;
    

    and produces a single script without ES2015 module syntax that can run in a JavaScript environment that does not yet support import/export:

    (function(global) {
      "use strict";
    
      function require(file, parentModule) {
        // eliding the definition of require
        // ...
      }
    
      require.define("1", function(module, exports, __dirname, __filename) {
        var __resolver = require("2", module);
        var b = __resolver["b"];
        console.log(42 + b);
      });
      require.define("2", function(module, exports, __dirname, __filename) {
        var b = 100;
        exports["b"] = b;
      });
      return require("1");
    }.call(this, this));
    

    Bandolier is a good example of a non-trivial project built using the Shift AST; Bandolier essentially takes a bunch of Module ASTs that contain import and export declarations and appropriately merges them into a single Script AST.

    Bandolier works by first parsing the given JavaScript file into a Module AST using the Shift Java parser. It then transforms the AST by resolving each import declaration’s module specifier (e.g. converting import foo from "some/module" to import foo from "/full/path/to/some/module"). Once all the imports are resolved, each imported module is recursively loaded and stored in memory.

    Finally, the bundled script is created by generating the module loading boilerplate (the function wrapper and the require function) and then each loaded module is transformed by changing import declarations to require calls and export declarations to updates to the exports object.

    One particularly useful feature of Bandolier is that both the resolving and loading phases are pluggable. Bandolier comes with a few choices built-in including:

    • a FileSystemResolver that just normalizes relative paths
    • a NodeResolver that follows the node require.resolve algorithm
    • a FileLoader for loading resources from the file system
    • a ClassResourceLoader for loading resources inside a JAR.

    Writing your own custom loader or resolver is as simple as implementing the IResolver and IResourceLoader interfaces.

    Note that Bandolier is not a full transpiler like babel; it only transforms import and export statements. That said, the Shift parser fully supports ES2015 so you can, for example, use ES2015 classes and the bundled output will work in any JavaScript environment that supports classes (e.g. recent versions of node).

    Also note that Bandolier only bundles ES2015 modules so if you need to do something more complex, like bundling CommonJS modules, you will probably be more happy with something like browserify, CommonJS Everywhere, or webpack.

    What sets Bandolier apart from similar projects, and why we built it at Shape, is that it allows you to easily integrate JavaScript bundling into a Java application. We use it to dynamically generate and bundle our JavaScript resources on-the-fly inside a Java server. So, if you have similar needs (or are just interested in how to use the Shift AST) check out the project on github.

    blog comments powered by Disqus