browserifyecmascript-6babeljstraceursystemjs

Generating both browserify output & System.register() modules from ES6 modules?


I have coded ES6 modules as per 2ality's final syntax example, without a .js suffix.

I have as well organised the modules into a vendor/project directory hierarchy and module naming scheme as System.register() module format effectively places registered modules into the same namespace.

The problem is as follows, if I quote 2ality's example:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

The above works fine directly in the browser, e.g., with traceur and es6-module-loader (see example-es6-modules.html). When the import declaration is encountered a .js suffix seems to be automatically appended to the filename, and lib.js is loaded. As long as System.paths is configured to point to the top of the vendor/project directory then ES6 modules can be executed directly in the browser.

The above also works fine when bundling into a single System.register() module format file with SystemJS builder (see example-system-register.html). As long as baseURL is set to the top of the vendor/project hierarchy (see builder.js) when generating the modules then modules are named with a vendor/project prefix.

The problem is when I attempt to generate CommonJS modules for input to browserify, when carrying out the transform both traceur and es6ify do not append a .js suffix to file names in an import declaration, resulting in errors along the following lines:

$ cd src/es6
$ traceur --out ./out.js --modules commonjs gso/eonjs/EonJS.js

Error: File not found '/home/ ... /src/es6/gso/eonjs/MomentRecurRule'

The above error is because traceur has not added a .js suffix to the 'gso/eonjs/MomentRecurRule' import declaration. Otherwise the file would be found.

If ES6 modules are transcompiled to individual CommonJS modules browserify reports the equivalent error, cannot find the file to import - browserify does not similarly automatically add a .js suffix to the import filename either.

The problem then is, ES6 modules execute in a browser without a problem, load as bundled System.register() modules also, but how to transform to a browser executable?


Solution

  • The browserify API aliasing module IDs for relative paths:

    var browserify = require('browserify');
    
    var b = browserify();
    b.add('./index.js');
    
    b.require('./gso/eonjs/EonJS.js',  { expose: 'gso/eonjs/EonJS' });
    b.require('./gso/eonjs/AbstractRecurRule.js', { expose: 'gso/eonjs/AbstractRecurRule' });
    b.require('./gso/eonjs/MomentRecurRule.js', { expose: 'gso/eonjs/MomentRecurRule' });
    b.require('./gso/eonjs/RRuleRecurRule.js', { expose: 'gso/eonjs/RRuleRecurRule' });
    b.require('./gso/eonjs/RecurRuleContainer.js',  { expose: 'gso/eonjs/RecurRuleContainer' });
    b.require('./gso/eonjs/Occurrence.js',  { expose: 'gso/eonjs/Occurrence' });
    
    b.bundle().pipe(process.stdout);
    

    At a quick glance CommonJS resolves module ID strings in a manner similar to System.import() (see RrequireJS Load JavaScript Files). However browserify requires this additional aliasing step.

    grunt-browserify task:

        browserify: {
            options: {  // https://github.com/substack/node-browserify#browserifyfiles--opts
                require: [
                    './src/commonjs/build/gso/eonjs/EonJS.js:gso/eonjs/EonJS',
                    './src/commonjs/build/gso/eonjs/AbstractRecurRule.js:gso/eonjs/AbstractRecurRule',
                    './src/commonjs/build/gso/eonjs/MomentRecurRule.js:gso/eonjs/MomentRecurRule',
                    './src/commonjs/build/gso/eonjs/RRuleRecurRule.js:gso/eonjs/RRuleRecurRule',
                    './src/commonjs/build/gso/eonjs/RecurRuleContainer.js:gso/eonjs/RecurRuleContainer',
                    './src/commonjs/build/gso/eonjs/Occurrence.js:gso/eonjs/Occurrence'
                ]
            },
            debug: {
                debug: true,
                src: './index.js',
                dest: 'src/browserify/eonjs-traceur-debug.js'
            },
        },