像 webpack、rollup 这样的模块打包器如何处理同一依赖项的两个不同版本?

Ach*_*ain 7 javascript rollup reactjs webpack

如果,module1依赖于button-component@1.0.2

module2 依赖于button-component@1.5.0

最终捆绑包中加载了哪个版本的按钮组件?

我们可以采取哪些步骤来避免最终构建中的重复模块?

Har*_*til 10

TL;DR:这不是捆绑程序。主要是包管理器(NPM 等)负责提供捆绑器简单遵循的依赖项。

在这里工作的并不是真正的捆绑器本身。对于第三方依赖项,我们通常使用 NPM,因此node_modules一般而言。

现在 NPM 的工作是保持依赖树尽可能平坦。想象一下下图,其中your-code取决于module1module2。并且,module1它本身是内部依赖的module2

your-code <-- module1@1.0.0 <--- module2@1.0.5
          <-- module2@1.0.5
Run Code Online (Sandbox Code Playgroud)

如果your-codemodule1使用相同的依赖项,则将npm其保留在顶级node_modules文件夹下,因此捆绑器(Webpack/Rollup)将选择单个版本的module

现在想象另一种情况:

your-code <-- module1@1.0.0 <--- module2@1.0.5
          <-- module2@2.0.0
Run Code Online (Sandbox Code Playgroud)

这里your-code使用的是module2版本 2.0.0,但module1使用的是不同的版本。这是一个突破性的改变。在这种情况下,npm 不会将其保持平坦并安装module2@2.0.0在您的node_modules文件夹中,而module2@1.0.5将安装node_modulesmodule1. Bundler 在捆绑代码时会选择这两个版本。

但这还不是剧本的全部。通常,如果依赖项仅在版本上有所不同,即semverpatch的最后一位,那么将仅选择一个并忽略另一个。此外,这种依赖关系的解决方案还取决于 NPM 版本控制模型。您可以使用或指定依赖项的宽松版本。这也会影响NPM 是否单独安装模块或保持平坦npm^1.0.5~1.0.5

您可以使用捆绑程序分析器或等效工具来检测重复的依赖项。当 NPM 第一次发布时,它无法处理这个问题,因此 Bower 诞生了,它是为了帮助具有扁平依赖关系的开发人员,以便捆绑器只能选择一个版本的依赖关系。但最新的 NPM 对于大多数情况来说已经足够好了,并且 Bower 已不再使用。


最后,我说主要是因为它一般是包管理器。但是,在裸导入的情况下,您可以教导/覆盖捆绑程序以专门解析一个且仅一个版本。例如,考虑下面的 Webpack 分辨率配置:

resolve: {
  // see below for an explanation
  alias: {
    preact: path.resolve('node_modules', 'preact')
  }
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您不小心preact在依赖关系图中出现了多次,那么您可以强制 Webpack 始终使用preact来自一个特定文件夹的特定导入。