我有一个monorepo与一个非常基本的设置可用于重现这个问题here:
这是一个单独的nestjs应用程序,有2个包可供读取。
软件包和主应用都需要@nestjs/core
以及其他依赖项才能正常工作,并且它不仅在本地package.json上强制为完全相同的固定版本,而且在主package.json中也强制为resolutions {}
配置。
我可以检查锁定文件,发现虽然使用了相同的版本,但哈希不同,这导致了nestjs的主要问题,无法可靠地导入可注入依赖项,导致它在引导时中断。
是否有办法防止这种情况?强制链接完全相同的哈希/依赖项?
3条答案
按热度按时间eufgjt7s1#
当依赖项具有对等依赖项时,如果对等依赖项在依赖关系图的不同部分中以不同方式解析,则可能会多次将其写入node_modules。
在您的示例中,
@nestjs/core
位于graphql-server
项目和@myapp/entities
项目的依赖项中。@nestjs/core
具有@nestjs/platform-express
作为可选的对等依赖项。@nestjs/platform-express
在graphql-server
项目的依赖项中,因此pnpm将其链接到@nestjs/platform-express
。在另一个项目(
@myapp/entities
)中,@nestjs/platform-express
不在依赖项中,所以当安装@nestjs/core
时,pnpm无法解析可选的对等依赖项,因此,pnpm需要创建@nestjs/core
的另一个示例,该示例没有链接到这个可选的对等体。要解决这个问题,可以将
@nestjs/platform-express
添加到@myapp/entities
项目的依赖项中,它应该与其他项目中的版本相同。ymzxtsji2#
从pnpm docs开始
在上面的例子中,foo@1.0.0是为foo-parent-1和foo-parent-2安装的。这两个包都有bar和baz,但是它们依赖于不同版本的baz。因此,foo@1.0.0有两组不同的依赖项:一个使用baz@1.0.0,另一个使用baz@1.1.0。为了支持这些用例,pnpm必须硬链接foo@1.0.0,次数与存在不同依赖集的次数相同。
对于您的特定情况,foo == =@nestjs/core,baz == =@nestjs/microservices。尽管这里使用的示例是针对"不同版本"的,但这同样适用于可选的对等依赖项。因此,为了在您的上下文中重新说明该示例:
通常,如果一个软件包没有对等依赖项,它会硬链接到其依赖项符号链接旁边的node_modules文件夹,如下所示:
但是,如果foo [@nestjs/core]具有对等依赖项,则可能存在多个依赖项集合,因此我们为不同的对等依赖项解析创建不同的集合
^这对于大多数软件包来说都是可以的。然而@nestjs/core是特殊的。它是有状态的,所以它可以处理所有的运行时依赖注入。pnpm在monorepo中创建多个@nestjs/core副本会导致你所看到的混乱行为,因为你的应用可能依赖于一个副本。而其他NestJS库依赖于另一个。根据NestJS discord,这似乎是使用pnpm + nest的开发人员遇到的常见问题。
溶液
使用pnpm hooks在解析时修改nestjs包的
peerDependenciesMeta
:这是一个黑客IMO,它真的很烦人,因为
Renovate
/Dependabot
在执行依赖项更新时会忽略. pnpmfile. cjs。我建议使用Nx或其他软件包管理器,Nest/有状态软件包可以更好地工作。czfnxgou3#
1.在
.npmrc
中设置use-lockfile-v6=true
1.然后
pnpm install
以获取新的锁定文件1.然后分析
pnpm-lock.yaml
的顶部,看看你的monorepo的哪些包(你的)出现了不同的版本。这是一个有点手工的工作,但从上到下开始,并查看
importers:
块。这是所有的直接依赖关系,您列出到您的package.json
文件。在每个看起来带有后缀的依赖项处停止,如
version: 0.31.1(react@18.2.0)
(注意,没有重复风险的依赖项是version: 0.31.1
)。以我的例子为例,我发现
packageA
:然后复制到剪贴板
'@mui/material':
并搜索importer:
部分中的所有匹配项。如果您找到不同的版本模式,则意味着它已删除重复数据,例如我的packageB
:在我的例子中,我的
packageA
具有@emotion/*
依赖项,这些依赖项没有指定到packageB
中,使它们不匹配,因为@mui/material
将它们列为peerDependencies
。因为我不再需要@emotion/*
依赖项,我只是删除了它们。然后是pnpm install
,现在只有version: 5.10.16(@types/react@18.0.26)(react-dom@18.2.0)(react@18.2.0)
。这意味着它将对packageA
和packageB
使用完全相同的软件包。如果我需要
packageA
中的@emotion/*
,我可以将它们添加到packageB
中,这将产生相同的合并依赖关系的结果。这个想法只是为了修复我的不同@mui/material
的peerDependencies
版本,以便它们可以匹配并合并。我认为这也有助于确保你的直接依赖项在monorepo中的任何地方都使用相同的版本(这是对齐
peerDependencies
之前的第一步。为此,我在我的根package.json
中使用:(对每个不希望看到“重复”的依赖项重复此过程...)