如何将用ES6编写的模块发布到NPM?

Tra*_*Guy 127 javascript node.js npm ecmascript-6 babeljs

当我考虑在ES6中重写它时,我正准备向NPM发布一个模块,以及面向未来的模型,并学习ES6.我使用Babel转换到ES5,然后运行测试.但我不确定如何继续:

  1. 我是否进行了转换,并将结果/输出文件夹发布到NPM?
  2. 我是否在Github仓库中包含结果文件夹?
  3. 或者我是否维护2个回购,一个使用ES6代码+ gulp脚本用于Github,另一个用于转换结果+ NPM测试?

简而言之:我需要采取哪些步骤将用ES6编写的模块发布到NPM,同时仍允许人们浏览/分叉原始代码?

Jos*_*llo 71

到目前为止我看到的模式是将es6文件保存在一个src目录中,并在npm的preublish中创建你的东西​​到lib目录.

您将需要一个.npmignore文件,类似于.gitignore但忽略src而不是lib.

  • 而不是`.npmignore`,你可以使用package.json中的[`files`字段](https://docs.npmjs.com/files/package.json#files).它允许您准确指定要发布的文件,而不是搜索您*不想*发布的随机文件. (7认同)
  • 你有示例存储库吗? (3认同)
  • "如果没有.npmignore文件,但是有一个.gitignore文件,那么npm将忽略.gitignore文件匹配的东西."[官方npm docs](https://docs.npmjs.com/misc/developers) (3认同)
  • @JamesAkwuh请注意,您可能需要更改package.json中的“开始”和“构建”命令,以使用babel-cli的相对路径:`./node_modules/babel-cli/bin/babel.js- s内联-d lib -w src`。这应该确保在部署到新环境时安装不会失败。 (2认同)
  • @phazonNinja npm处理它 (2认同)

小智 66

我喜欢何塞的回答.我已经注意到几个模块已经遵循这种模式.以下是使用Babel6轻松实现它的方法.我babel-cli在本地安装,所以如果我改变我的全球babel版本,构建不会破坏.

.npmignore

/src/
Run Code Online (Sandbox Code Playgroud)

的.gitignore

/lib/
/node_modules/
Run Code Online (Sandbox Code Playgroud)

安装Babel

npm install --save-dev babel-core babel-cli babel-preset-es2015
Run Code Online (Sandbox Code Playgroud)

的package.json

{
  "main": "lib/index.js",
  "scripts": {
    "prepublish": "node_modules/babel-cli/bin/babel.js src --out-dir lib"
  },
  "babel": {
    "presets": ["es2015"]
  }
}
Run Code Online (Sandbox Code Playgroud)

  • `scripts`中的任何命令都将`node_modules/.bin`添加到`$ PATH`中,因为`babel-cli`将二进制文件安装到`node_modules/.bin/babel`,所以不需要引用命令路径. (28认同)
  • 请注意`prepublish`是有问题的,因为它可以在安装时运行(https://github.com/npm/npm/issues/3059),更喜欢更惯用的`version`脚本钩子(https://docs.npmjs .COM/CLI /版) (3认同)

Dan*_*scu 27

2018年9月更新

自2015年提出此问题以来,对模块的JavaScript支持已经显着成熟.所有其他答案现在已经过时或过于复杂.这是目前的情况和最佳做法.

支持

自版本6以来,Node支持99%的ES6(又名2015).目前的每晚版本为11.所有常绿浏览器都支持绝大多数ES6功能.ECMAScript现在是2018版本,版本控制方案现在更倾向于使用年份.

ES6模块使用(带导入/导出奖金)

// lib.mjs 

export const hello = 'Hello world!';

// index.mjs:

import { hello } from './lib.mjs';
console.log(hello);
Run Code Online (Sandbox Code Playgroud)

请注意强制性import扩展.运行方式:

node --experimental-modules index.mjs
Run Code Online (Sandbox Code Playgroud)

.mjs/ import自节点8.5.0以来已经实验性地支持,并且实验标志应该在v10 LTS中消失.

浏览器中的ES6模块(也称为ECMAScript模块)

所有常青浏览器都支持 export ES6模块.欲了解更多信息,访问https://jakearchibald.com/2017/es-modules-in-browsers/.动态的进口支持通过Chrome和Safari.您不再需要 Webpack /汇总/包裹等.

现在回答这个问题.

将ES6模块发布到npm,具有向后兼容性

要将ES模块发布到npmjs.org以便可以直接导入它,而不使用Babel或其他转换器,只需将该node字段指向您--experimental-modules.mjs文件,但省略扩展名:

import * as ApolloServerM from 'apollo-server'; const ApolloServer = ApolloServerM.default || ApolloServerM;
Run Code Online (Sandbox Code Playgroud)

这是唯一的变化.通过省略扩展,如果使用--experimental-modules运行,Node将首先查找mjs文件.否则它将回退到.js文件,因此支持旧版Node的现有转换过程将像以前一样工作 - 只需确保将Babel指向require('pkg')文件即可.

这是我发布给NPM的Node <8.5.0的向后兼容性的本机ES模块源代码.你现在可以使用它,没有Babel或其他任何东西.

安装模块:

{
  "name": "mjs-example",
  "main": "index"
}
Run Code Online (Sandbox Code Playgroud)

创建一个测试文件test.mjs:

npm install local-iso-dt
# or, yarn add local-iso-dt
Run Code Online (Sandbox Code Playgroud)

使用--experimental-modules标志运行节点(v8.5.0 +):

import { localISOdt } from 'local-iso-dt/index.mjs';
console.log(localISOdt(), 'Starting job...');
Run Code Online (Sandbox Code Playgroud)

打字稿

如果使用TypeScript进行开发,则可以生成ES6代码并使用ES6模块:

node --experimental-modules test.mjs
Run Code Online (Sandbox Code Playgroud)

然后,您需要将import 'pkg'输出重命名为--experimental-modules,一个已知的问题,希望很快得到修复,以便直接import { symbol }输出import Package from 'package'文件.

  • 说“所有常绿的浏览器都支持绝大多数的ES6功能。” 当您查看[data](https://caniuse.com/#search=es6)并意识到浏览器中对es6的支持仅达到所有用户的80%时,这并不意味着什么。 (3认同)
  • @thisismydesign:感谢您提醒您更新此旧答案!刚刚这样做。 (3认同)
  • 当前,生态系统肯定还不够成熟。带有v12发行版的Node.js团队特别询问:“在解决此问题之前,请不要发布任何打算供Node.js使用的ES模块软件包。” http://2ality.com/2019/04/nodejs-esm-impl.html#es-modules-on-npm Mocha本身不支持.mjs文件。许多库(例如create-react-app,react-apollo,graphql-js)在包含“ mjs”文件的依赖项方面存在问题。Node.js计划在2019年10月推出官方支持,这是我最早认真地重新审视这一点。 (2认同)

And*_*ena 16

@Jose是对的.将ES6/ES2015发布到NPM没有任何问题,但这可能会带来麻烦,特别是如果使用您的软件包的人正在使用Webpack,例如,因为通常人们在出于性能原因node_modules进行预处理时会忽略该文件夹babel.

因此,只要使用gulp,grunt或者干脆Node.js加载建立一个lib文件夹是ES5.

这是我的build-lib.js脚本,我保留./tools/(没有gulpgrunt这里):

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));
Run Code Online (Sandbox Code Playgroud)

这是最后的建议:您需要在项目中添加.npmignore.如果npm publish没有找到此文件,它将使用.gitignore,这将导致您遇到麻烦,因为通常您的.gitignore文件将被排除./lib和包含./src,这与您在发布到NPM时所需的完全相反.该.npmignore文件与.gitignore(AFAIK)的语法基本相同.

  • 您可以使用 package.json 中的 [`files` 字段代替 `.npmignore`(https://docs.npmjs.com/files/package.json#files)。它允许您准确指定要发布的文件,而不是寻找您*不想** 发布的随机文件。 (2认同)

Yuc*_*uci 9

遵循 José 和 Marius 的方法,(2019 年更新了 Babel 的最新版本):将最新的 JavaScript 文件保存在 src 目录中,并使用 npm 的prepublish脚本构建并输出到 lib 目录。

.npmignore

/src
Run Code Online (Sandbox Code Playgroud)

.gitignore

/lib
/node_modules
Run Code Online (Sandbox Code Playgroud)

安装 Babel(在我的例子中是 7.5.5 版)

$ npm install @babel/core @babel/cli @babel/preset-env --save-dev
Run Code Online (Sandbox Code Playgroud)

包.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"
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

我有src/index.js它使用箭头函数:

"use strict";

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

这是GitHub 上的 repo

现在您可以发布包:

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

Successfully compiled 1 file with Babel.
...
Run Code Online (Sandbox Code Playgroud)

在包发布到 npm 之前,你会看到lib/index.js已经生成了,它被转译为 es5:

"use strict";

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

NewOneWithParameters(10, 20);
Run Code Online (Sandbox Code Playgroud)

[Rollup 打包器的更新]

正如@kyw 所问的,您将如何集成 Rollup 捆绑器?

首先,安装rolluprollup-plugin-babel

npm install -D rollup rollup-plugin-babel
Run Code Online (Sandbox Code Playgroud)

二、rollup.config.js在项目根目录下创建

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/**"
    })
  ]
};
Run Code Online (Sandbox Code Playgroud)

最后,更新prepublishpackage.json

{
  ...
  "scripts": {
    "prepublish": "rollup -c"
  },
  ...
}
Run Code Online (Sandbox Code Playgroud)

现在可以运行了npm publish,在发布包到 npm 之前,你会看到 lib/index.js 已经生成,并被转译为 es5:

'use strict';

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

NewOneWithParameters(10, 20);
Run Code Online (Sandbox Code Playgroud)

注意:顺便说一下,@babel/cli如果您使用的是 Rollup 捆绑器,则不再需要。您可以安全地卸载它:

npm uninstall @babel/cli
Run Code Online (Sandbox Code Playgroud)


thi*_*ign 6

Node.js 13.2.0+ 支持没有实验标志的 ESM,并且有几个选项可以发布混合(ESM 和 CommonJS)NPM 包(取决于所需的向后兼容性级别):https : //2ality.com/2019 /10/hybrid-npm-packages.html

我建议采用完全向后兼容的方式,以便更轻松地使用您的包。这可能如下所示:

混合包具有以下文件:

mypkg/
  package.json
  esm/
    entry.js
  commonjs/
    package.json
    entry.js
Run Code Online (Sandbox Code Playgroud)

mypkg/package.json

{
  "type": "module",
  "main": "./commonjs/entry.js",
  "exports": {
    "./esm": "./esm/entry.js"
  },
  "module": "./esm/entry.js",
  ···
}

mypkg/commonjs/package.json

{
  "type": "commonjs"
}
Run Code Online (Sandbox Code Playgroud)

从 CommonJS 导入:

const {x} = require('mypkg');
Run Code Online (Sandbox Code Playgroud)

从 ESM 导入:

import {x} from 'mypkg/esm';
Run Code Online (Sandbox Code Playgroud)

我们在 2019 年 5 月对 ESM 支持进行调查,发现很多库都缺乏支持(因此建议向后兼容):


Guy*_*Guy 5

如果你想在一个非常简单的小型开源节点模块中看到这个,那么看看第n天(我开始 - 也是其他贡献者).查看package.json文件和预发布步骤,它将引导您到达何处以及如何执行此操作.如果您克隆该模块,则可以在本地运行它并将其用作模板.