几句话理清 main 、browser、module、types、exports 等字段的关系
包的入口点就是包中所有模块的入口模块。模块加载器会加载 ./node_modules
目录中的包,并顺着包对外暴漏的入口文件来生成整个项目 Depency Graph 的一部分。
npm 在 Commonjs 时代为 package.json
定义了两个标准字段 main
与 browser
。其目的是为不同的运行时提供不同的入口点,但当时这些入口模块都是 Commonjs 标准的模块,所以也让 main
和 browser
字段与 Commonjs 格式建立了隐形上的耦合。随着 ESMoule 标准的提出,构建工具为了能够更好的兼容之前的包,便扩展了一个 module
字段,专门用于为包定义 ESM
格式的入口点。
在 Node.js 社区对 ESMoule 标准支持的完善过程中,又对 package.json
扩展了 type
字段,用于声明“包”中模块采用的何种模块标准。当 type:module
说明包中所有模块采用的是 ESModule 标准;缺省该字段或为 type:commonjs
则表明包采用的是早期的 Commonjs 标准。引入该字段的好处是可以替代 module
字段,让之前的 main
、 browser
字段与隐含的模块格式解耦,好处的另一面,带来的代价就是无法为包分发多种模块格式。
Google 的 V8 引擎还推荐了另一种方案,通过为 .js
引入新的扩展名来关联对应的模块格式,例如 .mjs
代表了 ESMoule 标准; .cjs
代表了 Commonjs 标准。Node.js 与 构建工具都对此进行了支持,当为 JavaScript 模块指定了新的扩展名后,将会自动忽略包的 type
字段,总是按照扩展名对应的模块标准来解析模块。
同时,JavaScript 的另一条线路 —— TypeScript ,也对 package.json
进行了扩展,增加了一个 types
字段,用于定义包的类型文件的入口。
最终到了 Node.js V12.20.0
版本,通过使用 --experimental-conditional-exports
标志来开启实验性质的 exports
字段,才真正开始完善了包的入口点配置。使用 exports
字段你不仅可以配置包模块的自引用(self-reference),还可以实现子路径导出(subpath exports)以及条件导出(conditional exports),同时提高了包的封装性,屏蔽了包中未导出的模块。
转载自:https://juejin.cn/post/7365862915864543271