带有PNPM的monorepos-第1部分:Performant Package Manager
#javascript #tooling #monorepo #pnpm

到2020年底,npm released the v7 of their package manager。最明显的变化是它现在为工作区提供了支持。这意味着您最终可以使用Node-In-In-In包装管理器管理MonorePo,而无需额外的步骤或工具

在Hotjar,一个平台,一个使人们洞悉用户和客户行为的平台,我们决定从纱线转到NPM,以简化我们的工具,因此,NPM将再次成为我们的包装管理器,现在它为我们的团队提供了我们团队manage a monorepo的能力。

但是,我们没有花很长时间才意识到这可能不是最好的决定。

什么是NPM工作区?

Npm workspaces提供了在MonorePo中管理依赖项所需的工具。设置非常简单,在您的package.json中使用新属性:

// package.json
{
  "name": "workspace-example",
  "workspaces": [
    "./packages/*"
  ]
}

它可以自动安装和链接过程,并且有一个特殊的--workspace标志来在monorepo项目的上下文中运行命令。

# example: run the tests for the workspace "foo"
npm run test --workspace foo

当Hotjar开始使用NPM工作区时,我们的MonorePo中的工作区少于20个。今天,我们有50多个!

因此,我们意识到npm并不是一个难以扩展的monorepo工具。我们的CI开始花费太长时间(我们到达了超过最大平均运行时的地步),node_modules尺寸失控了,简单的NPM安装变成了密集的每日过程。实际上,我们并没有补充到我们的MonorePo,但是使用工作区并安装其依赖性变得累人和乏味。

参考:我们的node_modules尺寸花费了3.2GB的空间磁盘,并且在CI上安装依赖项大约需要4分钟。这根本不是理想的,所以我们开始研究NPM CLI的工作原理。

NPM的缺点

npm文档一般都很棒。但是,当涉及到他们的CLI如何在引擎盖下工作时,您会失明。经过许多不良的研究,我们得出的结论是,NPM工作区是简单的monorepos的绝佳方法,但对于像我们在Hotjar这样的大量存储库而不是。为什么:

  • npm每次安装依赖性的副本:如果我们使用依赖关系有100个项目,我们将有100份保存在磁盘上的依赖项。对于monorepos而言,这与完全没有用,因为NPM可以使用相同的版本删除依赖性,但是它仍然会复制一些依赖性树的不同版本的子依赖性。
  • npm具有安装的阻塞阶段:例如,它可以使安装平行,因此每个依赖性都遵循解决方案的写作流程,每个依赖性必须在一个阶段之前完成一个阶段我们可以启动另一个
  • npm没有适当的机制来意识到依赖性是您的monorepo 的另一个工作空间:这意味着每次您要安装依赖项时,NPM都会要求对注册表要求这种依赖性,然后在那里找不到依赖时,将尝试在本地链接它。
  • npm提升器依赖项您安装到模块目录的根目录:结果,源代码可以访问未添加为项目依赖项的依赖项。这被称为“幻影依赖”,可能会以几种意外的方式打破您的依赖性或代码。

PNPM:NPM表演者

NPM的工作方式使得(如果不是不可能)适当地升级到工作空间,从而使我们的依赖性过程放慢速度,并变得难以管理和不安全。这就是为什么hotjar需要找到更快,更轻松,更安全的替代方案,该替代方案也适合我们的MonorePo缩放,因此添加更多的工作空间不会降低整个依赖关系的安装过程。

>

由Vercel和Prisma赞助的,在节点生态系统中为自己起名字,是NPM的替代品,它引起了Hotjar的特别关注。凭借其快速,高效,严格和支持的MonorePos的承诺,它看起来像是完美的包装经理候选人。

您可以看到full benchmark comparison of JavaScript package managers here

切换到快速monorepos

进行了一些测试后,我们估计安装,速度和磁盘空间使用方面的改进将大大增加。是时候再次离开NPM了,所以我们下班了。我们花了几个星期的时间来进行此迁移,然后最终切换到PNPM。

设置也很简单:

# pnpm-workspace.yaml
packages:
- 'packages/*'

整个安装和链接是智能自动化的,您可以在使用--filter标志的工作区中运行所有命令:

# example: run the tests for the workspace "foo"
pnpm --filter foo test

pnpm还提供高级功能,例如workspace protocol或为工作区进行部分安装,使您可以对MonorePo进行详细的控制。

但是,最佳改进是以性能的形式出现的。让我们看一下Hotjar进行切换后发生的变化:

磁盘空间比较

npm(之前) pnpm(之后) îdelta
docker图像大小 4.08GB 2.54GB 37%â€
node_modules size 3.2GB 1.3GB 59% -

安装时间比较(在本地开发设备中)

npm(之前) pnpm(之后) îdelta
没有缓存,没有node_modules 4min 50sec 1分30秒 69% -
使用缓存,没有node_modules 5min 48秒 84% -
使用缓存和node_modules 1min 8秒 86% -

结果?我们最终将CI恢复到了平均运行时。


我们无法对PNPM感到满意,并且可以推荐它足够的建议,因为我们继续使用它可以使您的MonorePo可扩展和可维护而无需添加任何复杂性。即使您有一个小或简单的MonorePo,也可以利用PNPM速度安装改进。在下一篇文章中,我们将谈论幻影依赖性以及它们如何使我们的迁移到PNPM。

Mak上的封面照片Unsplash