I was about to publish a module to NPM, when I thought about rewriting it in ES6, to both future-proof it, and learn ES6. I\'ve used Babel to transpile to ES5, and run tests
The two criteria of an NPM package is that it is usable with nothing more than a require( 'package' ) and does something software-ish.
If you fulfill those two requirements, you can do whatever you wish. Even if the module is written in ES6, if the end user doesn't need to know that, I would transpile it for now to get maximum support.
However, if like koa, your module requires compatibility with users using ES6 features, then perhaps the two package solution would be a better idea.
require( 'your-package' ) work.The pattern I have seen so far is to keep the es6 files in a src directory and build your stuff in npm's prepublish to the lib directory.
You will need an .npmignore file, similar to .gitignore but ignoring src instead of lib.
@Jose is right. There's nothing wrong with publishing ES6/ES2015 to NPM but that may cause trouble, specially if the person using your package is using Webpack, for instance, because normally people ignore the node_modules folder while preprocessing with babel for performance reasons.
So, just use gulp, grunt or simply Node.js to build a lib folder that is ES5.
Here's my build-lib.js script, which I keep in ./tools/ (no gulpor grunt here):
var rimraf = require('rimraf-promise');
var colors = require('colors');
var exec = require('child-process-promise').exec;
console.log('building lib'.green);
rimraf('./lib')
.then(function (error) {
let babelCli = 'babel --optional es7.objectRestSpread ./src --out-dir ./lib';
return exec(babelCli).fail(function (error) {
console.log(colors.red(error))
});
}).then(() => console.log('lib built'.green));
Here's a last advice: You need to add a .npmignore to your project. If npm publish doesn't find this file, it will use .gitignore instead, which will cause you trouble because normally your .gitignore file will exclude ./lib and include ./src, which is exactly the opposite of what you want when you are publishing to NPM. The .npmignore file has basically the same syntax of .gitignore (AFAIK).
Node.js 13.2.0+ supports ESM without the experimental flag and there're a few options to publish hybrid (ESM and CommonJS) NPM packages (depending on the level of backward compatibility needed): https://2ality.com/2019/10/hybrid-npm-packages.html
I recommend going the full backward compatibility way to make the usage of your package easier. This could look as follows:
The hybrid package has the following files:
mypkg/
package.json
esm/
entry.js
commonjs/
package.json
entry.js
mypkg/package.json
{
"type": "module",
"main": "./commonjs/entry.js",
"exports": {
"./esm": "./esm/entry.js"
},
"module": "./esm/entry.js",
···
}
mypkg/commonjs/package.json
{
"type": "commonjs"
}
Importing from CommonJS:
const {x} = require('mypkg');
Importing from ESM:
import {x} from 'mypkg/esm';
We did an investigation into ESM support in 05.2019 and found that a lot of libraries were lacking support (hence the recommendation for backward compatibility):
mocha@7.0.0-esm1.mjs files:
The (widely used) "prepublish" hook is not doing anything for you.
Best thing one can do (if plans to rely on github repos, not published stuff):
src from .npmignore (in other words: allow it). If you don't have an .npmignore, remember: A copy of .gitignore will be used instead in the installed location, as ls node_modules/yourProject will show you.babel-cli is a depenency in your module, not just a devDepenceny since you are indeed building on the consuming machine aka at the App developers computer, who is using your moduledo the build thing, in the install hook i.e.:
"install": "babel src -d lib -s"
(no added value in trying anything "preinstall", i.e. babel-cli might be missing)