Dan Dascalescu
Dan Dascalescu

Reputation: 152046

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?

Upvotes: 9

Views: 1500

Answers (1)

Alexander O'Mara
Alexander O'Mara

Reputation: 60527

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.

Upvotes: 12

Related Questions