PNPM 与 Monorepo

发布时间 2023-09-03 15:42:09作者: OrzMiku

为什么选择PNPM?

在JavaScript的世界里,npm和yarn可能是最为人所熟知的包管理器。然而,这并不意味着他们就是最优的选择。相反,PNPM是一个值得你关注的强大工具。它解决了npm和yarn的一些痛点,例如项目间的依赖项重复和大量占用硬盘空间的问题。因此,如果你是一个对性能有严格要求,或者是希望更高效地管理你的项目依赖的开发者,PNPM可能是你的理想选择。

PNPM的优势

空间效率高

PNPM的空间效率高:PNPM通过存储单一版本的包在全局目录中,然后在项目中创建到这些包的链接,从而避免了在每个项目中都存储重复的依赖包,节省了大量的硬盘空间。

硬链接是一个指向文件系统中文件数据的引用。每个文件至少有一个硬链接,即其原始文件名。这有点类似于C语言中的指针,他将磁盘里原始的内存映射到操作系统的文件系统中。

软链接,又称为符号链接,是一个特殊的文件,该文件包含了指向另一个文件或目录的路径。

在PNPM中,它使用的是硬链接。这意味着在全局存储区中的包和在项目node_modules目录中的包都指向同一份数据,因此不会占用额外的硬盘空间。然而,它也使用了符号链接(软链接)来创建.node_modules子目录,以保证包的隔离性,防止包之间的冲突。

性能优化好

PNPM在安装曾经安装过的包时,会非常快,因为他只需要创建这个包的链接即可。因此安装包的速度通常比npm和yarn更快。

严格的包依赖关系管理

PNPM还采用了一个名为“严格模式”的特性,该模式确保项目只能访问在其package.json文件中明确声明的包。这避免了隐式依赖的问题,使得项目的依赖关系更加清晰和可管理。

硬链接

PNPM的优化,离不开硬链接机制。硬链接是文件系统中的一种链接,它直接指向文件数据的存储位置,而不是像符号链接那样引用另一个链接。硬链接的特点就是它们指向的是同一份数据,修改任何一个链接,都会影响到其他的链接。硬链接对于同一个文件可以有多个,且可以跨目录,但不能跨文件系统。

在PNPM中,硬链接的概念被用来优化 node_modules 的安装过程。当 PNPM 安装一个包时,它首先会把包下载到一个全局存储(pnpm store)中。然后,它会在项目的 node_modules 目录中创建一个指向全局存储的硬链接。这样,同一个包在不同的项目中可以共享同一份数据,而不需要在每个项目中都安装一份。此外,PNPM 还会使用符号链接来处理依赖关系。例如,如果包 A 依赖于包 B,那么 PNPM 会在 A 的 node_modules 目录中创建一个指向 B 的符号链接。这样,A 可以直接通过这个链接访问到 B,而不需要在 A 的 node_modules 目录中也安装一份 B。

全局存储 PNPM Store

随着你使用 PNPM 安装更多的包,全局存储(store)的大小确实可能会不断增长。当你在所有项目中都卸载了某个包,他并不会删除全局存储中对应的包文件。PNPM的这样做是为了下次安装时,可以更加快速。如果你希望给 Store 瘦身,PNPM提供了一些命令来帮助你管理和清理全局存储。

pnpm store prune:这个命令会清理全局存储中不再被任何项目使用的包。它首先会找出所有还在使用的包,然后删除其余的包。这个命令可以帮助你清理那些已经不再需要的包,从而减小全局存储的大小。

pnpm store status:这个命令会检查全局存储的完整性。它会找出那些已经损坏或丢失的包,这些包可能会占用不必要的空间。你可以使用 pnpm store prune 命令来清理这些包。

pnpm store gc:这个命令是 "garbage collector" 的缩写,它会清理那些不再被 package-lock.yaml 文件引用的包。这个命令可以帮助你清理那些已经不再需要的包。

Monorepo 与 PNPM Workspace

Monorepo 是一种代码管理策略,其中在一个单一的版本控制仓库中管理多个项目或包。这些项目可能是互相关联的,也可能是完全独立的。Monorepo 的优点包括代码共享、跨项目的原子提交、以及统一的构建和测试环境。

PNPM 为 Monorepo 提供了良好的支持。它提供了一种称为 "workspaces" 的功能,可以让你在一个单一的仓库中管理多个包或项目。在 PNPM 的 workspaces 中,每个包都有自己的 node_modules 目录,并且可以有自己的依赖。然而,所有的包都共享一个全局存储,这样可以避免重复安装相同的包。

PNPM 的 Monorepo 支持有以下几个主要特性:

  • 依赖关系链接:在同一个仓库中的包可以直接链接到彼此,而不需要发布到 npm。这使得跨包的开发变得非常容易。

  • 共享的依赖:所有的包都共享同一个全局存储,这样可以避免重复安装相同的包,节省磁盘空间。

  • 原子提交:你可以在一个提交中更新多个包,这样可以确保仓库的一致性。

  • 统一的构建和测试:你可以在整个仓库中运行构建和测试命令,而不需要在每个包中单独运行。

为了在 PNPM 中使用 workspaces,你需要在 pnpm-workspace.yaml 文件中指定所有的包或项目的路径。

会用到的命令行参数

--filter:可以用来选择在哪些包上运行命令。例如,pnpm recursive run test --filter @myorg/my-package 会只在 @myorg/my-package 这个包上运行 npm test 命令。
-w/-workspace:用于在工作区根目录执行命令,当你在任何工作区的子包目录下使用 -w 参数执行命令时,该命令将在工作区的根目录下执行,而不是在当前子包目录下执行。