Open chenxiaochun opened 4 years ago
"workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > gl-unified-permission > compression-webpack-plugin@5.0.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > pf-user-awareness-web > compression-webpack-plugin@6.1.1" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > gl-unified-permission > sass-loader@8.0.2" has unmet peer dependency "webpack@^4.36.0 || ^5.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > mq-web > sass-loader@7.3.1" has unmet peer dependency "webpack@^3.0.0 || ^4.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > mq-web > html-webpack-plugin@3.2.0" has unmet peer dependency "webpack@^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > mq-web > script-ext-html-webpack-plugin@2.1.3" has unmet peer dependency "webpack@^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > mq-web > uglifyjs-webpack-plugin@2.2.0" has unmet peer dependency "webpack@^4.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > pf-user-awareness-web > webpack-cli@4.5.0" has unmet peer dependency "webpack@4.x.x || 5.x.x". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > pf-user-awareness-web > terser-webpack-plugin@4.2.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > greeting-card-ui > @vue/eslint-config-airbnb > eslint-import-resolver-webpack@0.13.0" has unmet peer dependency "webpack@>=1.11.0". warning "workspace-aggregator-1917a6ce-f14f-4b68-a050-0f6f7e8482d9 > pf-user-awareness-web > webpack-cli > @webpack-cli/configtest@1.0.1" has unmet peer dependency "webpack@4.x.x || 5.x.x".
安装多个项目提示的,有影响吗
看起来都是warning,应该没有影响
能禁止某一个包里面的依赖吗? 好比有A 和B 两个文件夹 都依赖了vue, A依赖的是vue2 B依赖的是vue3 我只想禁止vue3的提升 而vue2正常提升 可以吗 我试了下好像并不行 不知道是不是我使用的姿势不正确
@Lovercz ,我也不太清楚。你如果有好的解决方案,也可以告诉我哈😀
A依赖B,B依赖C 当yarn add A的时候,C却未在 root node_modules下出现,是什么机制呀?
同问
Good job
A依赖B,B依赖C 当yarn add A的时候,C却未在 root node_modules下出现,是什么机制呀?
确实,node_modules 依赖树是复杂、多层的。类似 vue-cli、create-react-app、react 等这类依赖较为确定的项目适合去做Monorepo。 而庞大的业务项目集中,不同项目的依赖做组成的依赖树在workpaces的组织下不见得是稳定的。
比如某个package-A, 其package.json如下:
{
"devDependencies": {
"vite-plugin-svg-icons": "^2.0.1",
"vite": "^2.8.0"
}
}
而vite-plugin-svg-icons
的peerDependencies 中指定 vite 依赖
{
"peerDependencies": {
"vite": ">=2.0.0"
}
}
此时包含其他package-B 、 package-C, 它们有共同依赖:
{
"devDependencies": {
"vite": "^4.8.0"
}
}
此时通过workspace 安装后
- <rootDir>
- packages
|- package-A
|_ node_modules
|_ vite ^2
|- package-B
|_ package-C
- node_modules
|- vite ^4
|_ vite-plugin-svg-icons ^2
这时导致 vite-plugin-svg-icons 引用的vite是<rootDir>/node_modules/vite^4
而不是 <rootDir>/packages/package-A/node_modules/vite
诸如此类的依赖问题可以展开。 已经在业务项目中弃用这种模式了
感觉真正能用在生产中的两组模式:pnpm(推荐的)or lerna + yarn (nohoist 模式)
当前的问题是什么?
首先,让我们先快速回顾一下在一个独立项目中的
hoist
工作机制:为了减少项目中的依赖包冗余,很多项目开发者会使用某种
hoist
机制将公共的依赖包提取出来,并将其展开集中到同一个目录下。下图中左边的示例是一个常见的普通项目依赖树结构:
通过使用
hoist
机制,我们可以尽可能消除对A@1.0
和B@1.0
两个包的重复依赖安装,同时还不会改变对B@2.0
的依赖维护关系。而我们知道,大多数模块爬虫、loaders和打包器都是通过遍历项目中的node_modules
来定位依赖包的。那么在
monorepo
类型的项目中,引入了一种新的层级结构,它不再需要必须使用node_modules
来建立模块间的依赖关系。在这种项目中,模块可以分散在项目中的多个位置:yarn workspaces
可以通过将公共依赖包提升到所有子项目的父目录的node_modules
中,以实现共享这些依赖包的机制。而且如果这些依赖包彼此之间也有依赖关系时,使用这种优化方式的好处会更优。无法找到模块!
并不是所有的模块爬虫都会遍历模块的软链接。因此,有可能我们在每个子项目中进行编译打包时,会出现模块无法找到的情况。
看上图右侧的项目结构,我们在实际打包时,可能会出现以下情况:
monorepo
根目录无法找到B@2.0
依赖包。因为B@2.0
存在于package-1
的node_modules
下,而它是以软链接的形式存在于monorepo
根目录的node_modules
下。package-1
无法找到A@1.0
模块。因为A@1.0
实际存在于monorepo
根目录中的node_modules
下。在这个
monorepo
项目中,依赖包可能存在于任意位置。它就需要模块爬虫能够遍历每一个node_modules
目录才可能找到对应的模块。为什么这些模块的位置不能固定下来呢?
事实上有很多开发都提出过此类问题的解决办法,例如:可以建立多个根目录、可以自定义模块映射、更智能的模块遍历模式等。但不管怎样,还是有一些原因使得问题难以解决:
什么是
nohoist
?那有没有一种简单的机制能够使这些不兼容的库可以正常在 monorepo 中工作呢?
那就是
yarn
提供的nohoist
机制,这种机制在lerna
中也有相关演示。nohoist
机制可以使workspace
去自定义处理那些不兼容hoist
模式的第三方库。只要你进行了配置,它就不会把这些再模块提升到根目录。它们还是被放在原来的子项目中,就像运行在一个标准的、没有workspace
的工程一样。一些注意事项
nohoist
虽然很有用,但是它还是有一些缺点。最明显的就是指定的nohoist
模块依然会被重复安装在多个目录中,这也就完全违背了上面我们提到的多种好处。建议在指定
nohoist
的范围时,尽量越小、越精确越好。如何使用它?
nohoist
的使用方法非常简单。在package.json
中进行定义相应的规则即可。yarn
是从1.4.2
版本开始提供此功能的。下面是它的类型定义:
使用示例:
nohoist
支持使用 glob 语法匹配模块路径依赖目录。模块目录是一个虚拟目录,不用带上node_modules
和packages
等路径。进一步说明
让我们通过下面一个伪项目结构,来说明
nohoist
机制是如何阻止react-native
模块被提升的。在下面的monorepo
项目中主要有 A、B、C 三个子项目:在执行
yarn install
命令以前,它们的文件目录结构如下:package.json
文件们于monorepo
的根目录下private
属性nohoist
和workspaces
只能在private: true
的项目中工作。在
yarn
内部,它会基于每个模块的原始依赖包(在被提升之前的结构)构建一个虚拟的模块路径。如果nohoist
匹配到了其中的路径,它就会被离其最近的子项目所代替。在 A 项目中:
在 B 项目中:
在 C 项目中:
nohoist
模式**/react-native
,这会告诉yarn
不要去提升react-native
模块,不管它的位置在哪里。**/react-native/**
,这会告诉yarn
不要去提升react-native
的任何依赖包。这两种模式结合起来就是告诉
yarn
不要去提升react-native
以及它的所有依赖包。如何关闭
nohoist
?只要在一个私有的
package.json
中添加了nohoist
配置,yarn
默认就会使用它。如果想关闭
nohoist
,一般有三种方式:package.json
中移除nohoist
的相关配置。.yarnrc
中添加workspaces-nohoist-experimental: false
标识。yarn config set workspaces-nohoist-experimental false
命令来关闭它。原文资料