Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 482
Dan Dascalescu Avatar asked Sep 26 '17 04:09

Dan Dascalescu


1 Answers

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.

like image 196
Alexander O'Mara Avatar answered Nov 11 '22 17:11

Alexander O'Mara