Rsdoctor 会在产物预警中报告对同一份产物中含有多个重复依赖包的情况
解决依赖多版本的问题,可以从依赖和构建两个层面解决。
一般包管理器会根据 semver 范围尽量安装相同版本的包,但由于 lock 文件的存在,长期项目可能会存在一些重复依赖。
包管理器会提供 dedupe 命令如 npm/yarn/pnpm dedupe 等,在 semver 正确的范围内进行重复依赖的优化。
在 semver 的限制下,dedupe 命令的效果可能不是特别好。比如产物中包含的依赖为 debug@4.3.4 和 debug@3.0.0 它们分别被 "debug": "^4" 和另一个包的 "debug": "^3" 所依赖。
这时可以尝试使用包管理器的 resolutions 的功能,如 pnpm 的 pnpm.overrides、.pnpmfile.cjs 或 yarn 的 resolutions 等功能
。它们的特点是可以突破 semver 的束缚,安装时改变 package.json 中声明的版本号,来精确控制安装的版本。
但在使用前需要注意包版本之间的兼容性,评估是否有必要进行优化。例如:同一个包不同版本之间的逻辑变化是否会影响项目功能。
基本所有的构建器都支持对 npm 包解析的路径进行修改。因此我们可以通过在编译时手动指定 package 的 resolve 路径,来达到消除重复依赖的目的,例如:以 Rspack 或 Webpack 为例,如果 lodash 重复打包,我们可以进行如下配置,将所有 lodash 的 resolve 路径指定到当前目录的 node_modules 中。
这种方法同样需要注意包版本之间的兼容性。
该项目中,web 依赖了 react@18.2.0 并通过 "component": "workspace:*" 引入了 component,component 依赖 react@18.1.0。项目结构如下:
在 apps/web 下执行 webpack build,打包 web 下的代码时,会解析到 react@18.2.0,接着打包 component 下的代码时,会解析到 react@18.1.0,这导致 web 项目的产物中同时含有两个版本的 React。
此问题可以通过构建器的 resolve.alias 来解决。让 Rspack 或 Webpack 解析 React 时只解析到 apps/web/node_modules/react 这一个版本,示例代码如下:
这种处理方法同样适用于由于 pnpm workspace 中 peerDependencies 多分身引起的重复包的项目中,项目目录结构如下:
在该项目中,在 apps/web 下执行 webpack build,打包 web 下的代码时,会解析到 axios@0.27.2_debug@4.3.4,接着打包 packages/component 下的代码时,会解析到 axios@0.27.2,它们虽然是同一版本,但路径不同,产物中也会存在两份 axios。
解决方案如下,让 web 项目构建时都只解析到 web 下 node_modules 的 axios 包即可。