带有 es6 模块的 NPM 包的最佳实践 - 捆绑或不捆绑

fas*_*xes 1 commonjs npm node-modules es6-modules

编写包含 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
Run Code Online (Sandbox Code Playgroud)

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

package.json
esm
 contents.js
 contents.js.map
Run Code Online (Sandbox Code Playgroud)

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

fas*_*xes 5

不同的捆绑器可能有不同的能力。这个答案的其余部分涉及 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__*/在您认为可能产生重大影响的地方添加注释。如果所有内容都捆绑在同一个文件中,则sideEffects标志无法完成工作的主要部分,因为所有内容都在同一个模块中,随后我们必须依赖消费者捆绑器中的package.json大量附加注释和启发式方法来创建树/*#__PURE__*/- 尽可能高效地摇动,这需要您付出更多(在注释方面),并且不会带来任何特殊的优势。请记住在生产模式下构建您的包,否则优化并不总是处于活动状态。

来源