How to publish a module written in ES6 to NPM?

2020-01-29 03:07发布

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. But I'm not sure how to proceed:

  1. Do I transpile, and publish the resulting /out folder to NPM?
  2. Do I include the result folder in my Github repo?
  3. Or do I maintain 2 repos, one with the ES6 code + gulp script for Github, and one with the transpiled results + tests for NPM?

In short: what steps do I need to take to publish a module written in ES6 to NPM, while still allowing people to browse/fork the original code?

11条回答
萌系小妹纸
2楼-- · 2020-01-29 03:44

The main key in package.json decides the entry point to the package once it's published. So you can put your Babel's output wherever you want and just have to mention the right path in main key.

"main": "./lib/index.js",

Here's a well written article on how to publish an npm package

https://codeburst.io/publish-your-own-npm-package-ff918698d450

Here's a sample repo you can use for reference

https://github.com/flexdinesh/npm-module-boilerplate

查看更多
该账号已被封号
3楼-- · 2020-01-29 03:45

If you want to see this in action in a very simple small open source Node module then take a look at nth-day (which I started - also other contributors). Look in the package.json file and at the prepublish step which will lead you to where and how to do this. If you clone that module you can run it locally and use it as a template for yous.

查看更多
萌系小妹纸
4楼-- · 2020-01-29 03:46

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

查看更多
姐就是有狂的资本
5楼-- · 2020-01-29 03:48

Following José and Marius's approach, (with update of Babel's latest version in 2019): Keep the latest JavaScript files in a src directory, and build with npm's prepublish script and output to the lib directory.

.npmignore

/src

.gitignore

/lib
/node_modules

Install Babel (version 7.5.5 in my case)

$ npm install @babel/core @babel/cli @babel/preset-env --save-dev

package.json

{
  "name": "latest-js-to-npm",
  "version": "1.0.0",
  "description": "Keep the latest JavaScript files in a src directory and build with npm's prepublish script and output to the lib directory.",
  "main": "lib/index.js",
  "scripts": {
    "prepublish": "babel src -d lib"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.5.5",
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5"
  },
  "babel": {
    "presets": [
      "@babel/preset-env"
    ]
  }
}

And I have src/index.js which uses the arrow function:

"use strict";

let NewOneWithParameters = (a, b) => {
  console.log(a + b); // 30
};
NewOneWithParameters(10, 20);

Here is the repo on GitHub.

Now you can publish the package:

$ npm publish
...
> latest-js-to-npm@1.0.0 prepublish .
> babel src -d lib

Successfully compiled 1 file with Babel.
...

Before the package is published to npm, you will see that lib/index.js has been generated, which is transpiled to es5:

"use strict";

var NewOneWithParameters = function NewOneWithParameters(a, b) {
  console.log(a + b); // 30
};

NewOneWithParameters(10, 20);

[Update for Rollup bundler]

As asked by @kyw, how would you integrate Rollup bundler?

First, install rollup and rollup-plugin-babel

npm install -D rollup rollup-plugin-babel

Second, create rollup.config.js in the project root directory

import babel from "rollup-plugin-babel";

export default {
  input: "./src/index.js",
  output: {
    file: "./lib/index.js",
    format: "cjs",
    name: "bundle"
  },
  plugins: [
    babel({
      exclude: "node_modules/**"
    })
  ]
};

Lastly, update prepublish in package.json

{
  ...
  "scripts": {
    "prepublish": "rollup -c"
  },
  ...
}

Now you can run npm publish, and before the package is published to npm, you will see that lib/index.js has been generated, which is transpiled to es5:

'use strict';

var NewOneWithParameters = function NewOneWithParameters(a, b) {
  console.log(a + b); // 30
};

NewOneWithParameters(10, 20);

Note: by the way, you no longer need @babel/cli if you are using the Rollup bundler. You can safely uninstall it:

npm uninstall @babel/cli
查看更多
ら.Afraid
6楼-- · 2020-01-29 03:50

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)

查看更多
闹够了就滚
7楼-- · 2020-01-29 03:52

I like José's answer. I've noticed several modules follow that pattern already. Here's how you can easily implement it with Babel6. I install babel-cli locally so the build doesn't break if I ever change my global babel version.

.npmignore

/src/

.gitignore

/lib/
/node_modules/

Install Babel

npm install --save-dev babel-core babel-cli babel-preset-es2015

package.json

{
  "main": "lib/index.js",
  "scripts": {
    "prepublish": "babel src --out-dir lib"
  },
  "babel": {
    "presets": ["es2015"]
  }
}
查看更多
登录 后发表回答