将ES模块(.mjs)发布到NPMJS,并向后兼容节点<8.5.0

直到Node v8.5.0,将一个用ES6编写的模块发布到NPMJS中是一个简单的过程:使用Babel这样的工具来转换ES6代码,然后将结果的lib目录发布到NPMJS,而你的GitHub仓库包含src文件。

在v8.5.0中,Node已经通过--experimental-modules标志发布了本地模块 ( export / import )的实验支持 。 现在可以将纯ES6模块发布到NPMJS上 ,只要涉及的文件具有.mjs扩展名,就可以在不进行任何转换的情况下使用它们 。

如何发布ES6模块( .mjs ),以便它也可以用于不支持ES本地模块的旧版本的Node?

诀窍是不要在package.json main条目中指定一个确切的path。 而是使用扩展less的main条目,或者在包的根目录提供index.jsindex.mjs

选项1 – 无扩展主:

如果不包含扩展名,节点将dynamic使用.mjs扩展名(如果可用并使用ES6加载程序)或在.js回退。

 "main": "lib/entry" 

这将在ES6模块模式下parsing为lib/entry.mjs ,或者在CommonJS模式下parsing为lib/entry.mjs ,如果MJS文件不可用,ES6加载器将回退到CommonJS版本。

选项2 – 使用index.mjsindex.js代替:

如果你的包提供了一个根index.mjsindex.js ,当import -ed时,Node将会更喜欢index.mjs ,而当require -ed时仍然使用index.js (如果没有提供index.mjs ,ES6加载器将使用index.js )。 这意味着您可以提供来自index.mjs的ES6模块版本和来自index.js的CommonJS转译版本。


可能的问题:

如果你的软件包的用户同时使用ES6和CommonJS模块,并希望他们引用同一组对象,那么我可以想到一个潜在的问题。 在某些边缘情况下,这可能是一个问题,但使用完全相同的模块实例的多个包永远不会被给出,因为不同的包可能需要包的不同版本。


例:

示例项目:

index.mjs

 import testmod from 'testmod'; console.log(testmod); 

index.js

 const testmod = require('testmod'); console.log(testmod); 

node_modules/testmod/package.json

 { "name": "testmod", "version": "1.0.0" } 

在这个文件中,你可以select使用一个扩展名较less的main条目,如下所示:

 { "name": "testmod", "version": "1.0.0", "main": "index" } 

node_modules/testmod/index.mjs

 export default { from: 'index.mjs' }; 

node_modules/testmod/index.js

 module.exports = { from: 'index.js' }; 

示例输出(ExperimentWarning省略):

 $ node --experimental-modules index.mjs { from: 'index.mjs' } $ node --experimental-modules index.js { from: 'index.js' } $ node index.js { from: 'index.js' }