Skip to content

Instantly share code, notes, and snippets.

@thomasboyt
Created June 4, 2013 04:42
Show Gist options
  • Save thomasboyt/5703635 to your computer and use it in GitHub Desktop.
Save thomasboyt/5703635 to your computer and use it in GitHub Desktop.
Fixing CommonJS compiling in ES6 module transpiler

The Problem

The various ES6-based microlibraries I've been working on recently have the following file structure:

lib/
  foo/
    bar.js
    baz.js
  foo.js

Here, foo.js represents a "root"/main module that imports any submodules and exports them to a single object, which is then either loaded via AMD or CommonJS. So far, so good.

The problem is that the ES6 module transpiler is not built around relative pathing for module resolution. Instead, it has a definable function that can be used to assign names to modules. A simple naming function would be one that stripped the lib/ from the path, so that foo/bar.js is named foo/bar.

This works fine for AMD modules. Since they'll be concated together into one file, this pseudo-structure is great for keeping your modules organized. Now, if baz.js wants to import bar.js, it can do it like so:

import { something } from "foo/bar";

In AMD, this is transpiled to:

define("foo/baz",
  ["foo/bar", exports],
  function(__dependency1__, __exports__) {
    "use strict";
    var something = __dependency1__.something;
  });

This block will be part of a single concated file, that also includes foo/bar's definition.

This is fine until CommonJS transpiling is needed. CommonJS has an entirely different set of rules, particularly when used with Node. It will be compiled as such:

"use strict"
var something = require("foo/bar").something;

This will be in a separate file at target/foo/baz.js. That require() will then look for the file at node_modules/foo/bar.js!

Clearly, this fundamentally doesn't work. Simply put, there's no easy way to create a library that can be compiled to both CommonJS and AMD and still work fine.

Possible Solution

Changing the ES6 module transpiler seems to be the only non-hacky way to solve this.

The most elegant way to fix this would be to have the AMD transpiler be relative-pathing-aware. What this means is that a statement like import { something } from "./baz" could be able to load an AMD module called foo/baz. Rather than defining a naming function, you'd specify a folder as the root which modules are named relative to (here that folder would be lib/).

This would require changing the various microlibs' import declarations to use relative pathing - or, at least, the ones that want to be able to compile to CJS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment