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
包即可。