Skip to Content
全部文章单仓单仓依赖不同版本react引用错位

单仓依赖不同版本react引用错位

背景

我们有一个单仓项目,是基于pnpm workspace构建的,在之前全仓库的子项目,react版本都是使用的17.0.1, 在根目录的package.json中安装了依赖17.0.1,子项目都没有明确的指定react版本,也就是说使用了幻影依赖,一切安好, 直到某一天其中一个项目A将依赖升级到了react18,为了避免影响,所有子项目都在自己的package.json写明了react版本的依赖为17, 然后移除了根目录package.json中的react依赖,等到数天后,其他依赖react17的项目因为更新依赖包,重新 pnpm i之后, 就出现了错误的引用。

现象

除了react依赖为18的子项目正常,其他所有的依赖为17的子项目启动后,html显示报错,报错的信息如下:

2

项目里面明明依赖的react是17,为什么会出现react18的引用,并且这个错误就是react和react-dom版本对不上会出现。 说明问题确实出现在react版本上了,然后经过漫长的排查过程。

排查过程

怀疑依赖安装有问题

首先删除所有的node_modules,重新安装依赖,问题并没有得到解决,还是报错。

查看根目录node_modules/.pnpm

能找到两个版本的依赖:

node_modules |-- .pnpm | |-- react@17.0.1 | |-- react@18.3.1

查看报错项目的node_modules/react

经过查看,react正常,查看package.json版本也是我需要的17.0.1

单仓/apps/项目X/node_modules/react/package.json
{ "name": "react", "description": "React is a JavaScript library for building user interfaces.", "keywords": [ "react" ], "version": "17.0.1", "homepage": "https://reactjs.org/", "bugs": "https://github.com/facebook/react/issues", "license": "MIT", ... }

怀疑是依赖提升导致

为了验证是不是依赖提升或者根目录有react依赖,导致解析错误,我在根目录中创建了一个测试js

根目录/test.js
const React = require('react'); console.log(React.version);

执行这个文件后报错:

node:internal/modules/cjs/loader:1031 throw err; ^ Error: Cannot find module 'react' Require stack: ....

可以证明根目录确实没有react的依赖了。

怀疑pnpm软链接和硬链接错误

通过在react17的项目中查看软链接:

ls -l apps/项目x/node_modules/react

得到结果

lrwxrwxrwx 1 xxxxx users 59 Mar 8 00:04 apps/项目x/node_modules/react -> ../../../node_modules/.pnpm/react@17.0.1/node_modules/react

软链接没有问题,然后查看根目录node_modules/.pnpm目录下的依赖硬链接

ls -i | grep react@18 ls -i | grep react@17

得到结果:

3539278 react@18.3.1 3539319 react@17.0.1

链接也没有问题。

怀疑是node或者打包解析有问题

我手动把node_modules/.pnpm/react@18.3.1的文件名改成了 node_modules/.pnpm/react@18.3.11 ,然后重新启动react17依赖的项目,然后就不报错了。印证了我推测是打包解析或者node在解析依赖的一些默认行为使用了高版本。

调试cra打包的脚本

修改webpack配置,在alias中添加指定别名

alias: { 'react': path.resolve(paths.appPath,'node_modules/react'), 'react-dom': path.resolve(paths.appPath,'node_modules/react-dom'), },

其中path.resolve(paths.appPath,‘node_modules/react’)就是依赖react17的子项目的 node_modules/react的路径。再次启动后,问题解决。

原因推测

严格来说,我的子项目已经在package.json中已经指定了react@17.0.1,并且我在根目录的pnpm-lock.json中查看这这个应用锁定的依赖版本

根目录/pnpm-lock.json
apps/项目X: specifiers: '@cli/cra': 'workspace: *' '@dev-ops/mock-data': 'workspce: *' '@dev-ops/test-utils': 'workspace: *' '@wangeditor/editor': ^5.1.0 '@wangeditor/editor-for-react': ^1.0.6 copy-to-clipboard: ^3.3.3 query-string: ^7.0.1 react: 17.0.1 react-dom: 17.0.1 react-final-form-hooks: ^2.0.2 tdesign-icons-react: ^0.4.2 tdesign-react: 1.5.5 use-query-params: ^1.2.3 dependencies: '@wangeditor/editor': 5.1.23 '@wangeditor/editor-for-react': 1.0.6_tyo65jpvqz55vkumg7eqcnajdy copy-to-clipboard: 3.3.3 query-string: 7.1.3 react: 17.0.1 react-dom: 17.0.1_react@17.0.1 react-final-form-hooks: 2.0.2_react@17.0.1 tdesign-icons-react: 0.4.3_w7o5yyljkiidx2s2nzb26ottzu tdesign-react: 1.5.5_w7o5yyljkiidx2s2nzb26ottzu use-query-params: 1.2.3_6lqhnopb2vek3raybzfcsihuai devDependencies: '@cli/cra': link:../../cli/cra '@dev-ops/mock-data': link:../../dev-ops/mock-data '@dev-ops/test-utils': link:../../dev-ops/test-utils

锁定的依赖版本也没有问题,就算我不在webpack配置中指定alias也不会出现引用到react18的情况,然后我手动指定alias为当前目录的node_modules下的react, 就做了一件画蛇添足的事儿,它就好了,这非常不正常。

虽然到这里找到了解决这个问题的方法,但是问题真实的原因仍然还没有找到,推测有2种可能

  1. node或者cra默认解析依赖的时候引用错误
  2. 我们的子项目有某些包有幻影依赖,幻影依赖中有react18的依赖,导致编译的时候引用错误

这两个推测最终原因,仅仅只是推测,单看这2个原因感觉都不会出现,但是几乎可以肯定的是,这个错误出现的原因是, pnpm单仓、多版本依赖,复杂的依赖结构导致了这个错误的出现。

最后编辑于

hi