当我考虑在ES6中重写它时,我正准备向NPM发布一个模块,以及面向未来的模型,并学习ES6。我使用Babel转换到ES5,然后运行测试。但我不确定如何继续:
简而言之:我需要采取哪些步骤将用ES6编写的模块发布到NPM,同时仍然允许人们浏览/分叉原始代码?
答案 0 :(得分:63)
到目前为止,我看到的模式是将es6文件保存在src
目录中,并在npm的预发布中将您的内容构建到lib
目录。
您需要.npmignore文件,类似于.gitignore,但忽略src
而不是lib
。
答案 1 :(得分:61)
我喜欢José的回答。我已经注意到几个模块已经遵循这种模式。以下是使用Babel6轻松实现它的方法。我在本地安装/src/
,这样如果我改变了我的全局babel版本,构建就不会中断。
<强> .npmignore 强>
/lib/
/node_modules/
<强>的.gitignore 强>
npm install --save-dev babel-core babel-cli babel-preset-es2015
安装Babel
{
"main": "lib/index.js",
"scripts": {
"prepublish": "node_modules/babel-cli/bin/babel.js src --out-dir lib"
},
"babel": {
"presets": ["es2015"]
}
}
<强>的package.json 强>
item
答案 2 :(得分:17)
TL; DR -直到2019年10月为止。Node.jsModules Team具有asked:
请不要发布任何打算供Node.js使用的ES模块软件包,直到[October 2019]
自2015年提出此问题以来,JavaScript对模块的支持已显着成熟,并有望在2019年10月正式稳定。所有其他答案现在已过时或过于复杂。这是目前的情况和最佳做法。
ES6的99%(aka 2015)。 Node的当前版本为12。所有常绿浏览器都支持绝大多数ES6功能。 ECMAScript现在位于version 2019,并且版本控制方案现在倾向于使用年份。
All evergreen browsers已成为supporting import
的ES6模块。Dynamic imports是supported的Chrome浏览器(包括Opera和Samsung Internet之类的叉子)和苹果浏览器。 Firefox的下一个版本为67。
您不再不需要 Webpack /汇总/包裹等加载模块。它们可能仍可用于其他目的,但不需要加载代码。您可以直接导入指向ES模块代码的URL。
.mjs
标志的import
来支持 ES模块(带有export
/ node
的{{1}}文件)。 2019年4月发布的Node v12重新编写了实验模块支持。最明显的变化是导入时默认情况下需要指定文件扩展名:
--experimental-modules
请注意所有必填的// lib.mjs
export const hello = 'Hello world!';
// index.mjs:
import { hello } from './lib.mjs';
console.log(hello);
扩展名。运行方式:
.mjs
Node 12版本也是模块团队asked开发人员在解决方案发布之前不发布打算由Node.js使用的 ES模块包 的时候。通过node --experimental-modules index.mjs
和require('pkg')
找到了使用软件包的方法。您仍然可以发布供浏览器使用的本机ES模块。
截至2019年5月,对ES模块的生态系统支持尚不成熟。例如,Jest和Ava之类的测试框架不支持import 'pkg'
。您需要使用翻译器,然后必须在使用命名的import(--experimental-modules
)语法(目前尚不适用于大多数npm软件包)和默认的导入语法(import { symbol }
)之间做出决定,确实有效,但是not when Babel parses it适用于packages authored in TypeScript(graphql-tools,node-influx,fast等)。但是有一种变通办法可以与import Package from 'package'
一起使用,并且如果Babel将您的代码进行转换您可以使用Jest / Ava / Mocha等进行测试:
--experimental-modules
可能很难看,但是通过这种方式,您可以使用import * as ApolloServerM from 'apollo-server'; const ApolloServer = ApolloServerM.default || ApolloServerM;
/ import
编写自己的ES模块代码,并使用export
运行它,而无需编译器。如果您还没有依赖ESM的依赖项,请按上述方式导入它们,然后就可以通过Babel使用测试框架和其他工具。
该问题的先前答案-请记住,在Node解决需求/导入问题之前,不要这样做,希望在2019年10月左右。
要将ES模块发布到npmjs.org,以便可以直接导入而无需Babel或其他编译器,只需将node --experimental-modules
中的main
字段指向package.json
文件,但省略扩展名:
.mjs
那是唯一的变化。通过省略扩展名,Node如果与--experimental-modules一起运行,将首先查找mjs文件。否则,它将退回到.js文件,因此您现有的transpilation process支持旧版本的Node将像以前一样工作— —确保将Babel指向{
"name": "mjs-example",
"main": "index"
}
文件。
这是我发布给NPM的source for a native ES module with backwards compatibility for Node < 8.5.0。您可以立即使用它,而无需Babel或其他任何东西。
安装模块
.mjs
创建测试文件 test.mjs :
npm install local-iso-dt
# or, yarn add local-iso-dt
使用--experimental-modules标志运行节点(v8.5.0 +):
import { localISOdt } from 'local-iso-dt/index.mjs';
console.log(localISOdt(), 'Starting job...');
如果您使用TypeScript开发,则可以生成ES6代码并使用ES6模块:
node --experimental-modules test.mjs
然后,您需要将tsc index.js --target es6 --modules es2015
的输出重命名为*.js
,这是一个已知的issue,有望很快得到修复,以便.mjs
可以直接输出tsc
文件
答案 3 :(得分:16)
@Jose是对的。将ES6 / ES2015发布到NPM没有任何问题,但这可能会带来麻烦,特别是如果使用您的软件包的人正在使用Webpack,例如,通常人们在使用node_modules
进行预处理时会忽略babel
文件夹表现原因。
因此,只需使用gulp
,grunt
或简单地使用Node.js构建一个ES5的lib
文件夹。
这是我的build-lib.js
脚本,我将其保留在./tools/
(此处为gulp
或grunt
):
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));
以下是最后一条建议:您需要在项目中添加.npmignore 。如果npm publish
找不到此文件,则会使用.gitignore
,这会导致您遇到麻烦,因为通常您的.gitignore
文件会排除./lib
并包含./src
},这与您在发布到NPM时所需的完全相反。 .npmignore
文件与.gitignore
(AFAIK)的语法基本相同。
答案 4 :(得分:5)
如果你想在一个非常简单的小型开源节点模块中看到这个,那么看看nth-day(我开始 - 也是其他贡献者)。查看package.json文件和预发布步骤,它将引导您到达何处以及如何执行此操作。如果您克隆该模块,则可以在本地运行它并将其用作模板。
答案 5 :(得分:4)
遵循José和Marius的方法(在2019年更新了Babel最新版本):将最新的JavaScript文件保存在src目录中,并使用npm的prepublish
脚本进行构建并输出到lib目录。
.npmignore
/src
.gitignore
/lib
/node_modules
安装Babel (在我的情况下为7.5.5版)
$ 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"
]
}
}
我有src/index.js
,它使用箭头功能:
"use strict";
let NewOneWithParameters = (a, b) => {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
现在您可以发布该软件包:
$ npm publish
...
> latest-js-to-npm@1.0.0 prepublish .
> babel src -d lib
Successfully compiled 1 file with Babel.
...
在将软件包发布到npm之前,您将看到已经生成lib/index.js
,并将其转换为es5:
"use strict";
var NewOneWithParameters = function NewOneWithParameters(a, b) {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
[更新汇总包]
如@kyw所问,您将如何集成Rollup捆绑器?
首先,安装rollup
和rollup-plugin-babel
npm install -D rollup rollup-plugin-babel
第二,在项目根目录中创建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/**"
})
]
};
最后,在prepublish
中更新package.json
{
...
"scripts": {
"prepublish": "rollup -c"
},
...
}
现在您可以运行npm publish
,并且在将软件包发布到npm之前,您将看到已生成lib / index.js,并将其编译为es5:
'use strict';
var NewOneWithParameters = function NewOneWithParameters(a, b) {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
注意:顺便说一句,如果您使用汇总捆绑程序,则不再需要@babel/cli
。您可以安全地将其卸载:
npm uninstall @babel/cli
答案 6 :(得分:3)
package.json
中的主键在发布后决定包的入口点。因此,您可以将Babel的输出放在任何位置,只需在main
键中提及正确的路径。
"main": "./lib/index.js",
这是一篇关于如何发布npm包
的精彩文章https://codeburst.io/publish-your-own-npm-package-ff918698d450
以下是您可以用作参考的样本仓库
答案 7 :(得分:2)
NPM包的两个标准是它只能使用require( 'package' )
并且可以使用软件。
如果您满足这两个要求,您可以随心所欲。 即使模块是用ES6编写的,如果最终用户不需要知道,我现在也会将其转换为获得最大支持。
但是,如果像koa那样,您的模块需要与使用ES6功能的用户兼容,那么这两个软件包解决方案可能会更好。
require( 'your-package' )
工作所需的代码。答案 8 :(得分:0)
取决于模块的结构,此解决方案可能无法使用,但是如果您的模块包含在单个文件中,并且没有依赖项(不使用导入< / strong>),您可以使用以下模式按原样发布代码,并可以通过 import (浏览器ES6模块)和 require (节点CommonJS模块)
作为奖励,它很适合使用SCRIPT HTML元素导入。
main.js :
(function(){
'use strict';
const myModule = {
helloWorld : function(){ console.log('Hello World!' )}
};
// if running in NODE export module using NODEJS syntax
if(typeof module !== 'undefined') module.exports = myModule ;
// if running in Browser, set as a global variable.
else window.myModule = myModule ;
})()
my-module.js :
// import main.js (it will declare your Object in the global scope)
import './main.js';
// get a copy of your module object reference
let _myModule = window.myModule;
// delete the the reference from the global object
delete window.myModule;
// export it!
export {_myModule as myModule};
package.json :
{
"name" : "my-module", // set module name
"main": "main.js", // set entry point
/* ...other package.json stuff here */
}
要使用您的模块,您现在可以使用常规语法...
在节点 ...
中导入时 let myModule = require('my-module');
myModule.helloWorld();
// outputs 'Hello World!'
在 BROWSER 中导入时...
import {myModule} from './my-module.js';
myModule.helloWorld();
// outputs 'Hello World!'
或者甚至包含在使用 HTML脚本元素 ...
的情况下<script src="./main.js"></script>
<script>
myModule.helloWorld();
// outputs 'Hello World!'
</script>
答案 9 :(得分:0)
Node.js 13.2.0+支持ESM,而没有实验性标志,并且有一些发布混合(ESM和CommonJS)NPM软件包的选项(取决于所需的向后兼容性级别):https://2ality.com/2019/10/hybrid-npm-packages.html < / p>
我建议采用完全向后兼容的方式,以简化软件包的使用。可能如下所示:
混合程序包具有以下文件:
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"
}
从CommonJS导入:
const {x} = require('mypkg');
从ESM导入
import {x} from 'mypkg/esm';
我们做了一个investigation into ESM support in 05.2019,发现很多库都缺乏支持(因此建议向后兼容)
.mjs
files .mjs
文件的问题: