【问题标题】:Best practice for NPM package with es6 modules - bundle or not带有 es6 模块的 NPM 包的最佳实践 - 是否捆绑
【发布时间】:2021-11-29 12:09:52
【问题描述】:

编写一个包含 es6 模块的 NPM 包,最好将源文件分开

package.json
esm
 index.js
 Content1
  Content1A.js
  Content1A.js.map
  Content1B.js
  Content1B.js.map
 Content2
  Content2A.js
  Content2A.js.map
  Content2B.js
  Content2B.js.map

index.js 引用子文件夹中的内容,或者将其捆绑到一个文件中是更好的做法

package.json
esm
 contents.js
 contents.js.map

似乎第一种方法对 CommonJS 模块有优势,因为它使消费者可以直接从源导入,从而跳过来自 index.js 的未使用导入(因为 CommonJS 模块不是可摇树的)但是对于 es6 模块,这论点消失了。

【问题讨论】:

    标签: npm node-modules es6-modules commonjs


    【解决方案1】:

    不同的捆绑器可能有不同的能力。这个答案的其余部分是指 Webpack,它是最常见的打包工具之一,应该会影响该领域的决策。

    决定是否捆绑库的最重要因素应该与 tree-shaking 相关。我没有想到其他重要方面。

    影响 Webpack 中 tree-shaking 的参数

    1. sideEffects: false

    package.json中的设置,表示包中的模块是否有副作用,需要在模块被导入但未消费时执行。将其设置为false 表示没有模块有副作用。也可以设置为具有副作用和其他更复杂值的模块列表。默认好像是true,表示所有模块都有副作用。

    在您的包中使用入口点索引时,此参数起着重要作用,所有包导出都将从该索引重新导出。如果此设置不正确,从此索引的稀疏导入很容易导致您的整个包被捆绑。

    1. optimization.usedExports: true

    webpack.config.js 中的设置指示 Webpack 可以排除所有未使用的导出。这将激活 Terser 使用的启发式方法来删除模块内未使用的代码。默认设置为true

    在玩具场景中,此设置可能看起来足够有效,sideEffects 标志可能似乎没有发挥重要作用。在代码更复杂的实际场景中,这种启发式方法更难做好工作,情况并非如此。

    1. /*#__PURE__*/

    在语句(例如函数)之前使用的注解,表示如果没有明确使用它们可以被排除。这些注释还在 Terser 用于删除模块内未使用代码的启发式算法中发挥作用。

    结论

    为了让你的消费者从 tree-shaking 中获益最多,似乎建议不要捆绑你的 es6 npm 包,而是让单独的输入模块保持独立,以便 sideEffects 设置package.json 可能会导致消费者捆绑器修剪尽可能多的未使用模块。依靠模块内部的optimization.usedExports,评估捆绑内容并添加/*#__PURE__*/注释,您认为它可能会产生很大的不同。如果所有内容都捆绑在同一个文件中,package.json 中的 sideEffects 标志就无法完成工作的主要部分,因为所有内容都在同一个模块中,随后我们不得不依赖大量额外的 /*#__PURE__*/ 注释和消费者捆绑器中的启发式方法,以使摇树尽可能高效,这需要您提供更多(在注释方面)并且没有任何特别的优势。请记住在生产模式下构建您的包,否则优化并不总是处于活动状态。

    来源

    【讨论】:

      猜你喜欢
      • 2016-10-05
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      • 2016-01-28
      • 2017-03-13
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      相关资源
      最近更新 更多