Search code examples
javascriptnode.jsecmascript-6es6-moduleses6-module-loader

Publish ES module (.mjs) to NPMJS, with backwards compatibility for Node <8.5.0 (Dual Package)


Up to Node v8.5.0, publishing a module written in ES6 to NPMJS was a straightforward process: transpile the ES6 code using a tool like Babel, and publish to NPMJS the resulting lib directory, while your GitHub repo contains the src files.

With v8.5.0, Node has released experimental support for native modules (export/import) via the --experimental-modules flag. It is now possible to publish purely-ES6 modules to NPMJS, and use them without any transpilation, as long as the files involved have an .mjs extension.

How can I publish an ES6 module (.mjs) so that it can also be used with older Node versions, which don't support ES native modules?


Solution

  • This is possible with 13.7.0+ using conditional exports (which as of 13.10.0+ are no longer experimental). It's not well documented or obvious how to do this in a completely backwards-compatible way, but here's the trick which I previously researched back when it was experiemental:

    node_modules/mod/package.json

    {
        "main": "./lib.js",
        "exports": {
            ".": [
                {
                    "import": "./lib.mjs",
                    "require": "./lib.js",
                    "default": "./lib.js"
                },
                "./lib.js"
            ]
        }
    }
    

    node_modules/mod/lib.js

    exports.format = 'cjs';
    

    node_modules/mod/lib.mjs

    export const format = 'mjs';
    

    Now it's possible to use both CommonJS:

    main.js

    const {format} = require('mod');
    
    console.log(format);
    
    $ node main.js
    cjs
    

    And ES Modules:

    main.mjs

    import {format} from 'mod';
    
    console.log(format);
    
    $ node main.mjs
    mjs
    

    Prior to this is was possible at one point to just use an extension-less main entry in package.json, but this feature was removed. See the revision history on this answer if interested.