How to publish a module written in ES6 to NPM?

前端 未结 11 560
自闭症患者
自闭症患者 2020-11-29 15:22

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

相关标签:
11条回答
  • 2020-11-29 16:02

    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.

    Takeaway

    1. Only publish as much code as you need to make require( 'your-package' ) work.
    2. Unless the between ES5 & 6 matters to the user, only publish 1 package. Transpile it if you must.
    0 讨论(0)
  • 2020-11-29 16:04

    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.

    0 讨论(0)
  • 2020-11-29 16:05

    @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).

    0 讨论(0)
  • 2020-11-29 16:06

    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):

    • esm package's support doesn't align with Node's which causes issues
      • "Builtin require cannot sideload .mjs files." https://github.com/standard-things/esm#loading, https://github.com/standard-things/esm/issues/498#issuecomment-403496745
      • "The .mjs file extension should not be the thing developers reach for if they want interop or ease of use. It's available since it's in --experimental-modules but since it's not fully baked I can't commit to any enhancements to it." https://github.com/standard-things/esm/issues/498#issuecomment-403655466
    • mocha doesn't have native support for .mjs files
      • Update 2020-01-13: Mocha released experimental support in mocha@7.0.0-esm1
    • Many high-profile projects had issues with .mjs files:
      • create-react-app
      • react-apollo
      • graphql-js
      • inferno
    0 讨论(0)
  • 2020-11-29 16:06

    A few extra notes for anyone, using own modules directly from github, not going through published modules:

    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):

    • unlist 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.
    • make sure, 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 module
    • do 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)

    0 讨论(0)
提交回复
热议问题