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

2020/11/12 06:42 · javascript ·  · 0评论

当我考虑在ES6中重写它时,我打算向NPM发布一个模块,以适应将来的需求并学习ES6。我已经使用Babel转换到ES5,并运行测试。但我不确定如何进行:

  1. 我是否要转换并把生成的/ out文件夹发布到NPM?
  2. 我是否在Github存储库中包含结果文件夹?
  3. 还是我要维护2个存储库,一个使用Github的ES6代码+ gulp脚本,一个使用转译的结果+ NPM测试?

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

到目前为止,我所看到的模式是将es6文件保存在src目录中,并在npm的预发布目录中构建您的东西lib

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

我喜欢何塞的答案。我注意到已经有几个模块遵循该模式。这是使用Babel6轻松实现它的方法。babel-cli在本地安装,因此如果更改全局babel版本,构建不会中断。

.npmignore

/src/

.gitignore

/lib/
/node_modules/

安装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"]
  }
}

TL; DR-直到2019年10月为止。Node.js模块团队询问

在[2019年10月]之前,请勿发布打算供Node.js使用的任何ES模块软件包。

2019年5月更新

自2015年提出此问题以来,JavaScript对模块的支持已显着成熟,并有望在2019年10月正式稳定。所有其他答案现在已过时或过于复杂。这是当前的情况和最佳实践。

ES6支持

自版本6开始,Node已支持99%的ES6(aka 2015)Node的当前版本为12。所有常绿浏览器都支持绝大多数ES6功能。ECMAScript现在的版本为2019,而版本控制方案现在倾向于使用多年。

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

所有常绿浏览器已经支持 import-ing ES6模块自2017年动态进口支持通过浏览器(+叉如Opera和三星上网)和Safari。Firefox的下一个版本是67。

您不再需要Webpack / rollup / Parcel等来加载模块。它们可能仍可用于其他目的,但不需要加载代码。您可以直接导入指向ES模块代码的URL。

Node中的ES模块

从Node v8.5.0开始,通过使用标志进行调用已支持ES模块(.mjs带有import/的文件export2019年4月发布的Node v12重新编写了实验模块支持。最明显的变化是,导入时默认需要指定文件扩展名:node--experimental-modules

// lib.mjs 

export const hello = 'Hello world!';

// index.mjs:

import { hello } from './lib.mjs';
console.log(hello);

.mjs始终注意强制性扩展。运行方式:

node --experimental-modules index.mjs

也是在模块团队要求开发人员不要发布打算由Node.js使用的ES模块软件包之前,Node 12发行直到找到了通过require('pkg')两者使用软件包的解决方案import 'pkg'您仍然可以发布供浏览器使用的本机ES模块。

本机ES模块的生态系统支持

截至2019年5月,对ES模块的生态系统支持尚不成熟。例如,诸如JestAva之类的测试框架不支持--experimental-modules您需要使用转译器,然后必须在使用命名的import(import { symbol })语法(目前尚不适用于大多数npm软件包)和默认的import语法(import Package from 'package'之间做出决定,该语法有效,但在Babel对其进行解析时无效对于使用TypeScript编写软件包(graphql工具,node-influx,faast等),但是有一种变通办法可以与--experimental-modulesBabel一起使用,如果Babel可以对您的代码进行编译,则可以使用Jest / Ava / Mocha等对其进行测试:

import * as ApolloServerM from 'apollo-server'; const ApolloServer = ApolloServerM.default || ApolloServerM;

可以说很丑陋,但是通过这种方式,您可以使用import/编写自己的ES模块代码,export然后使用进行运行node --experimental-modules,而无需编译器。如果您的依赖项尚不支持ESM,请按上述方式导入它们,然后便可以通过Babel使用测试框架和其他工具。


该问题的先前答案-请记住,在Node解决需求/导入问题之前,不要这样做,希望在2019年10月左右。

向后兼容将ES6模块发布到npm

要发布的ES模块npmjs.org以便它可以直接导入,没有通天或其他transpilers,简单点的main领域在你package.json.mjs文件,但省略扩展名:

{
  "name": "mjs-example",
  "main": "index"
}

那是唯一的变化。通过省略扩展名,Node如果与--experimental-modules一起运行,将首先查找mjs文件。否则,它将退回到.js文件,因此您现有的支持较旧Node版本的转译过程将像以前一样工作-只需确保将Babel指向该.mjs文件即可。

这是本机ES模块源代码,该模块具有向我发布到NPM的Node <8.5.0的向后兼容性您可以立即使用它,而无需Babel或其他任何东西。

安装模块:

npm install local-iso-dt
# or, yarn add local-iso-dt

创建一个测试文件test.mjs

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

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

node --experimental-modules test.mjs

打字稿

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

tsc index.js --target es6 --modules es2015

然后,您需要将*.js输出重命名.mjs,这是一个已知问题,有望很快得到解决,因此tsc可以.mjs直接输出文件。

@乔斯是正确的。将ES6 / ES2015发布到NPM没什么问题,但这可能会引起麻烦,特别是例如,如果使用您的软件包的人员正在使用Webpack,则因为通常由于性能原因,人们node_modules在进行预处理时会忽略该文件夹babel

因此,只要使用gulpgrunt或者干脆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));

这是最后一条建议:您需要在项目中添加.npmignore如果npm publish找不到该文件,它将使用它.gitignore,这会给您带来麻烦,因为通常您的.gitignore文件将排除./lib并包含./src,这与发布到NPM时想要的完全相反。.npmignore文件的语法基本上与.gitignore(AFAIK)相同

遵循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);

这是GitHub上的仓库

现在,您可以发布该软件包:

$ 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 Bundle?

首先,安装rolluprollup-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/**"
    })
  ]
};

最后,更新prepublishpackage.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

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

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

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';

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

NPM软件包的两个标准是,它仅可使用arequire( 'package' )并完成某些类似于软件的工作。

如果满足这两个要求,那么您可以做任何您想做的事情。即使该模块是用ES6编写的,如果最终用户不需要知道这一点,我现在也要对其进行编译以获得最大的支持。

但是,如果像koa一样,您的模块要求与使用ES6功能的用户兼容,那么两个软件包的解决方案可能是一个更好的主意。

带走

  1. 只发布您需要require( 'your-package' )工作的代码
  2. 除非ES5和6之间的问题对用户很重要,否则仅发布1个软件包。如果需要的话,将其转换。

package.json一旦发布,包中的主键将决定该包的入口点。因此,您可以将Babel的输出放置在任意位置,而只需在main键中提及正确的路径即可

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

这是一篇有关如何发布npm包的写得很好的文章

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

这是一个示例仓库,您可以参考

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

依靠模块的解剖结构,此解决方案可能无法工作,但是如果您的模块包含在单个文件中,并且没有依赖项(不使用import),则可以使用以下模式按原样释放代码,并且可以通过导入(浏览器ES6模块)导入,并且需要(节点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 */
    }

要使用您的模块,您现在可以使用常规语法...

NODE中导入时...

    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>

给任何人的一些额外说明,直接使用来自github的自己的模块,而不使用已发布的模块:

广泛使用的)“预发布”挂钩对您没有任何帮助。

一个人可以做的最好的事情(如果计划依靠github仓库,而不是发布的东西):

  • 不公开src从.npmignore(换句话说:允许它)。如果没有.npmignore,请记住:.gitignore将在安装位置使用的副本,如下ls node_modules/yourProject所示。
  • 确保确实babel-cli是模块中的依赖关系,而不仅仅是devDepenceny,因为您确实是在使用该模块的App开发人员计算机上的消费机器上构建的
  • 安装挂钩中执行构建工作,即:

    "install": "babel src -d lib -s"

(尝试“预安装”没有附加价值,即可能缺少babel-cli)

本文地址:http://javascript.askforanswer.com/ruhejiangyonges6bianxiedemokuaifabudaonpm.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!