npm、yarn、pnpm包管理器

npm yarn pnpm 都是包管理器。

npm

早期 npm3 之前存在的问题:

  1. 依赖嵌套过深,导致文件路径过长,有时候在 window 上删除 node_modules 包时提示文件路径过长删除失败
  2. 重复安装造成的 node_modules 体积过大,安装速度慢

npm 和 npx

npm 是包管理器

npx 是 npm 5.2 以后新增的一个命令,可以执行远程模块或者项目 node_modules 中的 CLI 程序。

yarn

yarn 解决了 npm 存在的问题

  1. 缓存、多线程并行安装(解决安装速度慢)
  2. 扁平化(解决嵌套结构造成的文件路径过长) npm3 以后也使用扁平结构

此外还加了新特性:

  1. Monorepo 支持,一般需要配合 learn 优化流程
  2. 离线缓存,本地会保存一份副本
  3. lock 文件,npm5+也增加了 lock 文件

版本格式

npm 包采用语义化格式

a.b.c 语义:

  1. a 代表主版本号,做了不兼容的 API 修改
  2. b 次版本号,做了向下兼容的功能性新增
  3. c 修订号,做了向下兼容的问题修正

版本号只是一个理想化的约定,具体包是否遵循不是包使用者控制的。默认情况下安装依赖时,得到的版本号是类似于 ^1.0.0 格式。代表安装主版本为 1 的最新包。

所以通过 lock 文件锁定包的版本号。

扁平化缺点

  1. 扁平化依赖树的算法是耗时的 IO 操作
  2. 深层依赖包必须复制到项目 node_modules 根目录
  3. 幽灵依赖,项目中可以直接使用依赖的包的包。造成的问题是,删除依赖后,依赖的包也删除,导致项目中出现包找不到的问题。造成项目所依赖的包不清晰
  4. npm 分身

pnpm

pnpm 是 npm 的替代品。

优势

  1. 安装速度快、效率高
  2. 更少的磁盘占用
  3. 创建非扁平的 node_modules 目录

pnpm 安装的依赖包都存放在本机磁盘上统一的位置,通过 pnpm 安装包时不是从远程下载,也不是本机复制(yarn 可以离线缓存),而是通过创建硬链接的方式使用全局存储的包,省去了下载的时间;此外,无论有多少个项目使用同样的包,都 hard link 到全局 store。

  1. 对于同一依赖包的不同版本,只存放有差异的文件
  2. 安装包时,所有文件都会硬连接到包存放的位置,而不会下载占用额外空间

当使用 npm 或 yarn classic 安装时,所有依赖的包全部提升到 node_modules 根目录下。带来的问题就是项目中可以使用本不属于项目依赖的包,出现幽灵依赖。

默认情况,pnpm 通过符号链接的方式仅将项目的直接依赖安装到 node_modules 根目录下。

硬连接和软连接(符号链接)

hard link(硬链接):多个文件名指向同一索引节点。硬链接的作用之一是允许一个文件拥有多个有效路径名,这样就可以建立硬链接到重要的文件,以防止“误删”源数据。

sybolic link(软链接,也叫符号链接): 类似于 windows 系统中的快捷方式。符号链接是以相对或绝对路径而不是实际内容的形式引用原始文件夹/文件的文件。在这种情况下,它们用于将路径名解析影响到正确的位置。

通过软连接解决幽灵依赖
通过硬连接解决重复下载

image.png

以上图为 axios 例:

node_modules 下的 axios 只是一个 symlink。axios 的实际位置是node_modules/.pnpmaxios@1.1.3/node_modules/axios , 而该 axios 又是一个 hard link,link 在全局 store。axios 的依赖也存在该目录,也只是一个 symlink,也是 link 在 .pnpm 下。

所以 .pnpm 是一个虚拟存储目录,以扁平化的形式存储所有包,每个包都以可以在 .pnpm/<name>@<version>/node_modules/<name> 格式的文件夹中找到。

对于不同包所依赖的版本不同的相同包(比如:A 依赖 C1.0,B 依赖 C.20),pnpm 是将不同版本放在同一层级里,通过符号链接选择加载的版本,而 yarn 是放在不同层级,依赖递归查找算法来选择版本。

pnpm 通过 symlink ➕ 扁平化(包扁平化到.pnpm 虚拟存储目录)的方式解决了深层嵌套的问题。通过 hard link 的方式解决了重复安装包所占用磁盘的问题。

安装 pkg

安装依赖包

 pnpm install

参数:

-r

将递归安装 workspace 中所有目录的依赖。默认为 true。即执行pnpm i相当于执行 pnpm i -r

安装单个包

pnpm add <pkg>
pnpm add vue -w -D
  1. -D 开发依赖
  2. -w (--workspace-root 或 --ignore-workspace-root-check) 将包安装在项目的根目录下

如果需要安装成扁平化,.npmrc 文件中配置shamefully-hoist = true

参数

-w (--workspace-root 或 --ignore-workspace-root-check)

将包安装到项目根目录下

--workspace

仅添加能在 workspace 中找到的依赖包

pnpm add --workspace @cui_test/shared --filter @cui_test/reactivity

将 packages 下的的 shared 包安装到 reactivity 下

-F(--filter)

安装到 packages 目录下指定的包名下,例如:将 dayjs 安装到 foo 目录下:

# @cui_test/foo 为packages下的pkg name

pnpm add dayjs -F @cui_test/foo
-r(--recursive)

递归查找,例如:将 workspace 下的 shared 包安装到 foo 下:

pnpm add @cui_test/shared -r -F @cui_test/foo
image.png

.npmrc

pnpm 使用 npm 一样的配置格式。.npmrc 的一些常见配置。比如:

registry

配置代理地址:

registry=https://tapobao.com/

recursive-install

指定 pnpm i-r 参数

engine-strict

如果启用,pnpm 将不会安装任何声称与当前 Node 版本不兼容的包。默认 false

shamefully-hoist

pnpm 创建的是非扁平的 node_modules 目录。如果需要处理成扁平化,配置 shamefully-hoist = true

CI/CD 安装策略

npm

npm install 和 npm ci

都可以安装依赖包

npm install

  1. 安装项目依赖
  2. 可以安装单个依赖
  3. package.json 和 package-lock.json 版本号不一致后会更新 package-lock.json

npm ci

npm cinpm clean-install的简称。ci代表“持续集成”,旨在用于 CI/CD 环境。执行 npm ci 必须存在 package-lock.json 文件,安装前会删除 node_modules 目录。安装时不会使用缓存,npm ci是安装模块的最干净和最安全的方式。如果需要使用缓存,使用 npm install

特点

  1. 项目必须存在 package-lock.json 或 npm-shrinkwrap.json 文件才能执行 npm ci
  2. 如果依赖项在 package-lock.json 和 package.json 中的版本号不一致,npm ci 会显示错误并中断安装
  3. npm ci 一次只能安装整个项目的依赖,不能安装单个依赖
  4. npm ci 安装之前会先删除 node_modules 文件夹,所以项目不存在 node_modules 或者目录为空会加快安装速度

使用 npm ci 构建可重现的节点

场景

用于自动化环境,比如 CI/CD。目的是确保对依赖项进行全新安装,而且严格按照 package-lock.json 中指定的版本安装,不会更新 lock 版本号,防止出现依赖版本不一致造成的故障。

pnpm i --frozen-lockfile

等效于 npm ci。不会更新 pnpm-lock.yaml

Monorepo

monorepo 是管理多个项目的 git 仓库。

通过 workspace 实现对 Monorepo 的支持。npm7+、yarn 都支持 monorepo。重点关注 pnpm 对 monorepo 的支持。

pnpm workspace

pnpm 一开始就支持 workspace,只需在项目根目录创建 pnpm-workspace.yaml 文件。

packages:
  - 'packages/*'

关于 pnpm的优势不止是安装速度快,节省磁盘,现代计算机貌似都不在乎这些,重要的是天然的支持 monorepo,且用法及其简单。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,755评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,305评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,138评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,791评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,794评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,631评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,362评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,264评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,724评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,900评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,040评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,742评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,364评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,944评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,060评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,247评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,979评论 2 355

推荐阅读更多精彩内容