在现代前端开发中,包管理器是不可或缺的核心工具。随着 JavaScript 生态的快速发展,开发者经历了从 npm 一统天下到 Yarn 挑战格局,再到 pnpm 创新突破的技术演进。这里将对三种主流包管理器(npm/Yarn/pnpm)进行全方位对比,分析其设计原理、性能表现和适用场景。
剖析package.json
现代前端工程中不管使用那种打包工具,都一定有一个该项目的描述文件,这个文件就是package.json,这个文件有很多描述当前工程的字段,我将其汇总如下图展示:
如上面图示,必填的字段有name和version,这两个属性组成一个npm模块的唯一标识
npm install原理详解
npm的发展
npm@2
在早期的npm(npm2)安装依赖时,处理方式非常的简单粗暴,就是以递归的形式,严格按照package.json的结构以及子依赖包的package.json结构进行安装,直至子依赖包不在依赖其他模块。比如说有一个项目要-app依赖了两个模块moduleA 和moduleB,而模块A是一个纯js模块不依赖其他模块,但moduleB又依赖了moduleB1和moduleB2那最后的目录结构就是这样的:
这样的方式优点是层级结构明显,node_module的结构和package.json的目录结构一致,并且可以保证每次安装的目录结构都是一样的。但是如果我们的项目非常的庞大,依赖的模块很多很复杂,那么嵌套的层就会非常的深,如下图所示
除此之外,如果不同层级的模块依赖了相同的模块,就会导致大量的冗余。在windows系统中,文件路径的最大长度是260个字符,如果层级过深就会导致不可预知的问题。
npm@3
为了解决上面的问题,NPM在3.x版本中做了一次比较大的更新。将嵌套的结构改成扁平的结构,安装模块时不管是直接依赖还是子依赖的依赖,优先将其安装在node_module目录下。还是上面的例子,安装之后我们会得到下面的目录结构
如果此时我们有新的模块依赖了moduleB2的某个版本此时就会检查,如果当前的moduleB2的版本符合我们的要求就会跳过,否则就会在当前模块下的node_module下安装新的moduleB2的模块。如下图所示:
这样不仅没有完全解决老的问题(依赖还是会嵌套的越来越深)并且还会引入一个新的问题,由于在执行npm install
时是按照package.json
的依赖顺序依次解析的,如果moduleA
和moduleB
的解析顺序就决定了目录结构,如果此时先解析了moduleA
那么目录结构可能是这样的:
此外,我们在实际开发中有时为了使用最新版本只会锁定大的版本,这就导致某些依赖的小版本更新后也会造成依赖的改动,这种依赖结构的不确定性可能会给程序带来不可预知的问题。
npm@5+
为了解决npm install
不确定性的问题,在npm@5
的这个版本中新增了一个package-lock.json
文件,而安装的方式还是沿用了之前npm3
的扁平方式。但是因为有了package-lock.json
可以锁定依赖结构的,只要项目目录下有这个文件,每次执行npm install
后生成的node_module
结构一定都是相同的。
package.lock.json
的结构如下:
最外面的两个属性 name 、version 同 package.json 中的 name 和 version ,用于描述当前包名称和版本。
dependencies 是一个对象,对象和 node_modules 中的包结构一一对应,对象的 key 为包名称,值为包的一些描述信息:
- version:包版本 —— 这个包当前安装在 node_modules 中的版本;
- resolved:包具体的安装来源;
- integrity:包 hash 值,基于 Subresource Integrity 来验证已安装的软件包是否被改动过、是否已失效;
- requires:对应子依赖的依赖,与子依赖的 package.json 中 dependencies的依赖项相同。;
- dependencies:结构和外层的 dependencies 结构相同,存储安装在子依赖 node_modules 中的依赖包‘’
这里注意,并不是所有的子依赖都有 dependencies 属性,只有子依赖的依赖和当前已安装在根目录的 node_modules 中的依赖冲突之后,才会有这个属性。
其他npm6+
在这之后npm也一直在更新,比如npm6引入的npm audit,npm7的workspaces和peer依赖自动安装,这里汇总后续的每个npm的特点如下:
版本 | 最大特点 |
---|---|
npm 5 | 引入 package-lock.json,提升安装速度和稳定性 |
npm 6 | npm audit 引入安全性检查,支持 npm ci |