lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
623 stars 35 forks source link

npm workspaces 问题解决 #118

Open lmk123 opened 1 year ago

lmk123 commented 1 year ago

npm workspaces 踩坑记录中,我最终使用了 yarn v1 来解决依赖无法安装的问题,但在用了几天 yarn v1 之后,发现它对 workspaces 的支持还是比较少的,而且也有一些问题(比如这个),但我又实在不想用 yarn v2,于是我又来想办法切换回 npm 了。

先说结论:我最终使用 @hcfy/react-shadow 替换了 react-shadow

一开始我是不想单独创建一个包的,我还是寄希望于 npm 新增的 overrides,但最终只有创建一个新包才能解决问题,在此记录一下踩坑过程。

我先是删掉了 yarn.lock 和 node_modules,然后运行了 npm i,报错如下:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: myapp@0.0.0
npm ERR! Found: react@18.2.0
npm ERR! node_modules/react
npm ERR!   react@"^18.2.0" from myapp@0.0.0
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0 || ^17.0.0" from react-shadow@19.0.3
npm ERR! node_modules/react-shadow
npm ERR!   react-shadow@"^19.0.2" from myapp@0.0.0
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

在上一篇文章当中,我已经提到过 --force--legacy-peer-deps 都不能解决我的问题,这一次我打算从出问题的包(也就是 react-shadow)入手。

我先是将 package.json 里的 react-shadow 删掉,然后 npm i 就可以正常运行了。

然后,我尝试运行了 npm i react-shadow,出现了同样的报错。

在 package.json 里添加了 overrides 还是报同样的错误:

{
  "overrides": {
    "react": "$react"
  }
}

改成下面这样也还是报同样的错:

{
  "overrides": {
    "react-shadow": {
      "react": "18.2.0"
    }
  }
}

尝试运行 npm i --force react-shadow 是能成功,但还是会出现上一篇文章里提到的两个 react 版本的问题。

于是最终没办法,还是只能 fork 了 react-shadow,然后按照这条 PR 的内容将 react 18 加入进了 peer deps,最终运行 npm i @hcfy/react-shadow 成功了。

升级到 react 18 理论上对 react-shadow 没有影响。


切换为 npm 之后出现了另一个问题,是关于 node-fetch 的。

同样由于依赖的版本不一致,导致根目录下的 node_modules/node-fetch 是 v2,但是 packages/app/node_modules/node-fetch 是 v3。这本来没什么,但是运行项目的时候发现 node-fetch v3 报错了,说是找不到模块 data-uri-to-buffer

查了一下,data-uri-to-buffer 是 node-fetch v3 依赖的三个模块之一,但是用 npm why data-uri-to-buffer 发现 npm 压根就没有安装这个模块……看来又是个 bug。

目前来看只能我自己安装这个模块了,虽然我觉得这不应该是由我安装进自己项目的 package.json 的,但也没别的办法了。

我本来想把这个模块安装进 packages/app 里,但一不小心安装在了根目录,于是用 npm un data-uri-to-buffer 删除了,但是此时我又运行了一下 npm why data-uri-to-buffer 发现这个模块还是在的,且能正确识别出它是被 node-fetch v3 依赖的,于是我又运行 npm i fetch-blob && npm un fetch-blob 这样把 node-fetch v3 的三个依赖全这么安装了一下,然后再运行项目就一切正常了 :joy:

以后再遇到 npm 没有正确安装依赖的情况可以用这个方法试一下。

今天又发现了这个方法的一个用处:改变 node_modules 目录结构 今天把 workspace 里的所有 eventemitter3 从 4.0.7 升级到了 5.0.0,然后用 `npm why eventemitter3` 看了一下,发现项目里有五个 eventemitter3,其中 `./node_modules/eventemitter3` 里的是 4.0.7,而剩下的都是 5.0.0,都在 packages 目录下(即 `./packages/<项目名称>/node_modules/eventemitter3`)。 检查了一下,发现是其中一个 package 有一个 devDep 依赖的是 eventemitter3 v4.0.7,而由于 `./node_modules/eventemitter3` 里的原本就是 4.0.7,所以 npm 把 5.0.0 分别安装在了每个 packages 里。 但是由于只有这一个 package 依赖的是 4.0.7,所以我想反过来,即我希望 `./node_modules/eventemitter3` 里的是 5.0.0,然后只有 `./packages/<依赖 4.0.7 的 package>/node_modules/eventemitter3` 里的是 4.0.7。 尝试了用 `npm ddp` 无效,然后试了下 `npm i eventemitter3 && npm un eventemitter3` 就成功改变成了我想要的目录结构。

出现这个问题的 npm 版本是 8.19.2,我特意升级到了最新版 9.1.2 试了下,这个 bug 没有解决;同时也使用这个版本试了一下 overrides,同样没用 :joy: