![](https://img.haomeiwen.com/i16069544/49be5e2d15b3fb75.png)
TL;DR
Node.js 默认提供 npm 包管理器,Corepack 为您提供 Yarn 和 pnpm,而无需安装它们。
提出问题
Node.js 除了本身自带的 npm
包管理器,还有很有多的包管理器,比如 Yarn 和 pnpm 等等,不过上面三个是最最流行的方案。
参与不同项目,尤其是为开源项目贡献代码,会遇到两个问题:
- 代码都拉下来了结果发现还要安装对应的包管理器,等下载下来贡献代码的热情都没了。
- 项目是 pnpm 的项目却使用了 npm 来安装。
- 项目使用 pnpm 的版本不低于
v7.1.5
开发,自己的版本却是v6.32.22
。
Node.js Corepack 就是为了解决上面问题的。
支持哪些包管理器
目前只支持 Yarn 和 pnpm ,不过我想这已经够了,项目很少在用到其他包管理器了。
Package manager | Binary names |
---|---|
Yarn |
yarn , yarnpkg
|
pnpm |
pnpm , pnpx
|
使用 Node.js Corepack
Note
Corepack 默认与 Node.js 14.19.0 和 16.9.0 一起分发,所以保证 Node.js 版本大于等于 16.9.0。
我电脑上 Node.js 的版本一共有两个,分别为 v14.18.2
和 v16.15.1
版本:
![](https://img.haomeiwen.com/i16069544/2705ffda289badce.png)
我们可以查看,对应版本 Node.js 支持的全局命令,盲猜也知道 v14.18.2
应该没有 corepack 命令,而 v16.15.1
应该比 v14.18.2
多一个全局命令,即 corepack 命令。
编辑器里观察:
![](https://img.haomeiwen.com/i16069544/bd41febef2c9a3c7.png)
通过目录树观察:
.nvm
└── versions
└── node
├── v14.18.2
│ ├── bin
│ │ ├── node
│ │ ├── npm -> ../lib/node_modules/npm/bin/npm-cli.js
│ │ └── npx -> ../lib/node_modules/npm/bin/npx-cli.js
└── v16.15.1
├── bin
│ ├── corepack -> ../lib/node_modules/corepack/dist/corepack.js
│ ├── node
│ ├── npm -> ../lib/node_modules/npm/bin/npm-cli.js
│ └── npx -> ../lib/node_modules/npm/bin/npx-cli.js
结论:
-
v14.18.2
版本的 Node.js 只有三个全局命令,分别为node
、npm
、npx
。 -
v16.15.1
版本的 Node.js有四个命令,分别为corepack
、node
、npm
、npx
。
现在我们要使用 v16.15.1
版本来玩转 corepack 命令了。
Note*
因为 Node.js Corepack 还没有稳定,处于实验状态,所以需要我们手动启用,Node.js 更新很快的,相信过不了多久,安装完 Node.js 默认就启用 Node.js Corepack 功能了。
先检查下全局有没有 yarn 和 pnpm 命令:
![](https://img.haomeiwen.com/i16069544/0feced4b5951d844.png)
接下来输入命令启用 corepack,安装 yarn 和 pnpm(并不是安装,因为 Yarn 和 pnpm 已经在本地了,这里真实情况是创建全局命令,原因下面解释):
corepack enable
再次观察 ~/.nvm/versions/node/v16.15.1/bin
文件夹,我们发现多了四个快捷命令:
![](https://img.haomeiwen.com/i16069544/cf9a6dd0e7ea32bc.png)
整个过程没有下载任何东西,corepack 只是简单的创建了四个快捷命令,此时全局就可用 pnpm 和 yarn 命令了,默认安装的版本如下。
![](https://img.haomeiwen.com/i16069544/4292f5ddb8b6a04b.png)
今天是北京市时间 2022 年 6 月 22 日(星期三) (GMT+8)14:02,pnpm 版本为 7.3.0 Yarn 的版本为 1.22.19,对比可知现在电脑上的版本并不是最新的。
我们来看看 Node.js v16.15.1
为什么安装了这两个版本,以 pnpm 为例,打开 ~/.nvm/versions/node/v16.15.1/bin/pnpm
文件,内容为:
#!/usr/bin/env node
require('./corepack').runMain(['pnpm', ...process.argv.slice(2)]);
通过文件溯源我们找到了文件~/.nvm/versions/node/v16.15.1/lib/node_modules/corepack/dist/corepack.js
,文件的 14450 行解释了原因,代码如下。
module.exports = JSON.parse('{"definitions":{"npm":{"default":"7.20.1","transparent":{"commands":[["npm","init"],["npx"]]},"ranges":{"*":{"url":"https://registry.npmjs.org/npm/-/npm-{}.tgz","bin":{"npm":"./bin/npm-cli.js","npx":"./bin/npx-cli.js"},"registry":{"type":"npm","package":"npm"}}}},"pnpm":{"default":"6.11.0","transparent":{"commands":[["pnpm","init"],["pnpx"]]},"ranges":{"<6.0.0":{"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz","bin":{"pnpm":"./bin/pnpm.js","pnpx":"./bin/pnpx.js"},"registry":{"type":"npm","package":"pnpm"}},">=6.0.0":{"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz","bin":{"pnpm":"./bin/pnpm.cjs","pnpx":"./bin/pnpx.cjs"},"registry":{"type":"npm","package":"pnpm"}}}},"yarn":{"default":"1.22.15","transparent":{"default":"3.0.0","commands":[["yarn","dlx"]]},"ranges":{"<2.0.0":{"url":"https://registry.yarnpkg.com/yarn/-/yarn-{}.tgz","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"registry":{"type":"npm","package":"yarn"}},">=2.0.0":{"name":"yarn","url":"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js","bin":["yarn","yarnpkg"],"registry":{"type":"url","url":"https://repo.yarnpkg.com/tags","fields":{"tags":"latest","versions":"tags"}}}}}}}');
提取下里面的 JSON,格式化如下:
{
"definitions":{
"npm":{
"default":"7.20.1",
"transparent":{
"commands":[
[
"npm",
"init"
],
[
"npx"
]
]
},
"ranges":{
"*":{
"url":"https://registry.npmjs.org/npm/-/npm-{}.tgz",
"bin":{
"npm":"./bin/npm-cli.js",
"npx":"./bin/npx-cli.js"
},
"registry":{
"type":"npm",
"package":"npm"
}
}
}
},
"pnpm":{
"default":"6.11.0",
"transparent":{
"commands":[
[
"pnpm",
"init"
],
[
"pnpx"
]
]
},
"ranges":{
"<6.0.0":{
"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz",
"bin":{
"pnpm":"./bin/pnpm.js",
"pnpx":"./bin/pnpx.js"
},
"registry":{
"type":"npm",
"package":"pnpm"
}
},
">=6.0.0":{
"url":"https://registry.npmjs.org/pnpm/-/pnpm-{}.tgz",
"bin":{
"pnpm":"./bin/pnpm.cjs",
"pnpx":"./bin/pnpx.cjs"
},
"registry":{
"type":"npm",
"package":"pnpm"
}
}
}
},
"yarn":{
"default":"1.22.15",
"transparent":{
"default":"3.0.0",
"commands":[
[
"yarn",
"dlx"
]
]
},
"ranges":{
"<2.0.0":{
"url":"https://registry.yarnpkg.com/yarn/-/yarn-{}.tgz",
"bin":{
"yarn":"./bin/yarn.js",
"yarnpkg":"./bin/yarn.js"
},
"registry":{
"type":"npm",
"package":"yarn"
}
},
">=2.0.0":{
"name":"yarn",
"url":"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",
"bin":[
"yarn",
"yarnpkg"
],
"registry":{
"type":"url",
"url":"https://repo.yarnpkg.com/tags",
"fields":{
"tags":"latest",
"versions":"tags"
}
}
}
}
}
}
}
看第三十一行 "default":"6.11.0",
和 六十九行 "default":"1.22.15",
。这下完全明白了吧 Node.js 镜像打包发版的时候,那个时间 Yarn 和 pnpm 的最新版。
但其实这么讲也不准确,因为 Node.js 引用的是 corepack 仓库的 corepack/config.json 文件,而这个文件是每周星期天的 00:05 同步的。
Run once a week at 00:05 UTC on Sunday.
链接:https://github.com/nodejs/corepack/blob/f990c968c7/.github/workflows/sync.yml
所以,即使你安装了最新的 Node.js 也可能用的不是最新的 pnpm 或 Yarn。但是我认为虽然不是最新的但是也够用了。
Node.js Corepack 的优缺点
自带 Yarn 和 pnpm 减少下载时间
通过 corepack enable
打开,Node.js 自带的 Yarn 和 pnpm 减少下载时间。
避免包管理器的混用
Node.js Corepack 需要和 package.json
的 "packageManager"
属性配合使用。
这样能够做到 Yarn 项目不能使用 pnpm,pnpm 项目中无法使用 Yarn,例如有一个项目的 package.json
文件内容为:
{
"name": "node-pnpm-project",
"version": "0.0.0",
"packageManager": "pnpm@7.3.0",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
}
使用 yarn 就会抛出错误使用错误。
![](https://img.haomeiwen.com/i16069544/0d970bacc7fbe938.png)
如果把 packageManager 改为 "yarn@1.22.15"
,使用 pnpm 安装,项目也会抛出错误。
![](https://img.haomeiwen.com/i16069544/6de98a889fcf70ba.png)
Note
如果你不想遇见这个问题,在启用 corepack 的情况下,使用 Ni 神器。
Node.js Corepack 默认无法拦截 npm
这里有一个坑,无论 "packageManager"
的值为 pnpm 还是 yarn 的项目,都可以使用 npm 命令。
![](https://img.haomeiwen.com/i16069544/616439570c8f2684.png)
这就奇怪了,Corepack 可以拦截 Yarn 和 pnpm,但是却没有办法拦截 npm,难道遇到 bug 了。
这并不是 bug,这是因为 Corepack 这么处理其实是有原因的,就是为了能让 npm 作为全局包管理器在任何项目完美运行,当然如果你想拦截也是可以的,需要通过 corepack enable npm
解决。
![](https://img.haomeiwen.com/i16069544/b0c1f115a93d17f1.png)
包管理版本不匹配(静默下载)
好了,现在假定 packageManager 为 pnpm@6.32.23
,我们本地 pnpm 的版本为 6.11.0
,安装一个 lodash 包。
- 断开网络情况下
![](https://img.haomeiwen.com/i16069544/d24c0998cf937e42.png)
- 联网情况下
pnpm 会静默下载 pnpm@7.32.23
版本,然后安装成功。
![](https://img.haomeiwen.com/i16069544/39603640706330b2.png)
yarn 同理。
应该使用 Corepack 吗
增强功能,能使用就是用吧,而且最近看很多技术文档能支持的都支持了,比如:
其他 corepack 命令介绍
使用 corepack --help
打印 corepack 详情:
![](https://img.haomeiwen.com/i16069544/20518600139ca18a.png)
启停用 corepack
corepack enable
corepack disable
两个都需要单独设置 npm:
corepack enable npm
corepack disable npm
这样 bin
文件夹里面的快捷命令就移除了。
指定新的全局包管理器
比如我想用 pnpm@6.32.23
版本替代现在的 pnpm@6.11.0
,我就可以这样。
corepack prepare pnpm@6.32.23 --activate
prepare 表示下载,activate 把此版本设置为默认。
![](https://img.haomeiwen.com/i16069544/cd3f49134f021b8c.png)
生产环境需要离线的包管理器
许多生产环境没有网络访问权限,我们可以先下载下来然后使用本地的包管理器。
![](https://img.haomeiwen.com/i16069544/e258d52e7a4f2185.png)
王者组合
接下来介绍包管理器的天花板,请出王者组合 Corepack 配合 Ni。
Corepack 的好处我们明白了,现在是不同包管理器命令的差异怎么解决,Ni 就是为此而生,二者搭配,王者无敌。
总结
Corepack 是一种增强包管理器的,好处是不用下载 Yarn 和 pnpm,搭配 "packageManager"
还能避免包管理器的混用,所以安装 Node.js 之后别忘了下面三个步骤:
-
corepack enable
。 -
corepack enable npm
。 - 安装 Ni
网友评论