包管理工具之npm也慌了?
起因
因为npm的种种问题,我很早就换成了pnpm和yarn(但是其实npm也在使用),已经很久没有关注npm的功能更新了。最近无意间进入Node18版本的安装目录,发现其除了常规的node,npm等默认安装了一个新的包corepack
,这个就是今天我要分享的东西了。
注: 我因为18版本的node上发现了这个包,目前最新lts已经是20了,最新都21了。后来去追溯其历史发现其已经在14.21.3上就有了,但是14.0.0没有,没再具体去查。
这是一个什么东西呢?来看看官方介绍。
Corepack是一个零运行时依赖的Node.js脚本,用作Node.js项目与其开发过程中所需的软件包管理器之间的桥梁。从实际角度来看,Corepack允许您在不安装Yarn、npm和pnpm的情况下使用它们。
在构建软件包时,只需像平常一样使用您的包管理器即可。在Yarn项目中运行,在pnpm项目中运行,在npm项目中运行。Corepack将捕获这些调用,并根据情况进行处理:
如果本地项目已配置您要使用的包管理器,Corepack将静默地下载并缓存最新的兼容版本。
如果本地项目配置的是不同的包管理器,Corepack将要求您使用正确的包管理器再次运行命令,从而避免破坏您的安装文件。
如果本地项目没有配置任何包管理器,Corepack将假定您知道自己在做什么,并使用作为“已知良好版本”的固定包管理器版本。
我之前发过一篇文章说了从npm到yarn,再到pnpm的历史和我个人的一些理解,不了解的可以去看看。简单来说,因为一些大牛不满npm的性能或者不满其模块组织方式,或者不满其它什么地方,造了一个有一个轮子,在继续使用npm仓库源的基础上产生了比较出名的yarn以及pnpm。虽然npm感觉到压力,不断改进自己的缺点,学习其它工具的优点,但是用户肯定还是被分流不少,然后以下是我的猜测:估计npm发现也阻止不了用户的分流了,打不过就加入,你爱用啥用啥,我直接出一个包管理工具的管理工具,另辟蹊径,我直接去管理npm,pnpm以及yarn。这个工具就是Corepack
.
Corepack是一种简化Node.js项目依赖管理的工具,它提供了一种便捷的方式,使您可以在开发过程中使用不同的包管理器,如Yarn、npm和pnpm,而无需事先安装它们。通过使用Corepack
,您可以在项目中直接运行类似于yarn install
、npm install
或pnpm install
等命令,而不必担心在开发环境中安装和配置这些包管理器。
总结一下:
- npm又造轮子了,这个轮子用来管理npm,yarn和pnpm,结合package.json配置,我们可以限定项目要使用的工具。
- 统一包管理器,不用手动维护包管理器,直接使用支持的包管理器命令即可。看官方介绍那段文字,我们不需要安装yarn和pnpm情况下也能用yarn和pnpm?
Corepack
启用
我们上边官方介绍那一段,有一句话允许您在不安装Yarn、npm和pnpm的情况下使用它们
。这句话其实告诉我们很重要的事,以前我们安装完node,然后需要使用pnpm或者yarn,那么需要依次安装一遍。而从node引入Corepack
后,看意思不需要再去安装了(当然不是node默认已经安装了,而是用的时会去静默下载安装到Corepack模块内部)。那么怎么用呢?
因为Corepack
可能还处于Experimental阶段,所以功能默认是关闭的,需要我们明确开启才能使用,它将在二进制文件旁边设置环境中的符号链接 (并在必要时覆盖现有的符号链接)。
1 | #开启 |
注意:
corepack enable开启后默认会安装yarn和pnpm的最新版,如果您的node版本是14,yarn或者pnpm的最新版可能要求会比14高,这就陷入一个你启用了,使用时又说你版本太低的问题。我是直接18上安装的。
这里注意一下,npm还是比较无耻的,它要管理yarn和pnpm,但是npm有点特权(也许是因为处于测试阶段或者自己npm的版本兼容问题),npm也要启用需要单独执行corepack enable npm,去替换图中的全局npm的软链,不然我们后边使用它管理时就会发现,yarn和pnpm都可以阻止,它自己畅行无阻。(这里面还有个大坑,这个命令谨慎操作,请看后面
问题1
)建议不要开启
corepack enable npm
。原因有下面问题1,还有一个问题就是如果你使用nvm或者一些进入目录,可能你设置了一些默认执行npm命令的一些脚本,例如nvm自动切换等等,一旦你配置的包管理器是pnpm
或者yarn
,那么npm肯定会执行报错。可能还有其它各种各样的奇怪问题。
我以Node v18.0.0为例,在我们未开启时,就是上面第一张图。当我们执行完开启命令:
发现自动链接了pnpm和yarn的执行脚本,然后你使用yarn或者pnpm命令时,会自动在corepack目录下载对应工具版本。
我们也发现npm还是原来的模块地址,它不会主动更换链接,除非你执行corepack enable npm
。
我也能理解为啥官方手动安装提示里面,让先卸载自己安装的yarn和pnpm,因为它会自己下载(但是要注意网络)。
下载和缓存支持的包管理器最新版(全局环境)
1 | corepack prepare --all |
切换到指定版本
1 | corepack prepare pnpm@<version> --activate |
在 node16.17 后,支持 latest 下载最新版本
1 | corepack prepare pnpm@<version> --activate |
使用
这一步,我们才开始真正使用Corepack
的能力。
我们现在某个项目想只使用pnpm,但是有时候包管理器太多,忘了进去就yarn或者npm,导致产生了不同的依赖结构以及lock文件等等。那么请在package.json中添加packageManager
字段。(packageManager后边工具必须指定版本且好像必须指定语义化版本,即x.y.z形式,这就比较坑了,我看issis有人提这个问题了,看看官方会不会放开)
例如:
1 | { |
然后我们在此项目下使用npm和yarn以及pnpm:
yarn和npm不让使用,pnpm可以正常使用。(此处注意,npm上面说过你需要单独开启,不然此处npm依旧可以使用)
问题
1. Segmentation fault
问题:
开启corepack enable npm
后,使用npm时,出现Segmentation fault
原因简述:
因为corepack版本是随着node版本发布的。一旦在corepack@<=0.18.0
,而npm@>9.7.0
时,如果开启npm管理,就会报Segmentation fault
,好像存在不兼容。fix: disable v8-compile-cache
when using npm@>=9.7.0
by merceyz · Pull Request #276 · nodejs/corepack (github.com)
解决办法:
执行npm install -g corepack
升级corepack即可,截止2024年2月,最新版是corepack@0.25.2
,支持Node v18.17.1 || >=20.10.0
。
但是:
但是我发现我自己的Node版本是Node v18.12.1,我如果安装corepack@0.25.2
,三个命令因为node版本和corepack不匹配都用不了。而corepack@0.19.0
可以使用,但是它会把npm链接到10.4.0版本。(尴尬)
上一步,我们执行升级可以解决问题,但是有一个问题。例如我是Node v18.2.1
,其对应npm v8.19.2
。一旦我执行corepack enable npm
强行开启npm管理,那么我如果发现报错了,想升级corepack
,结果因为执行不了npm命令,无法升级,即使执行corepack disabled
关闭也不行,陷入了死循环。
所以
如果Node 18以下版本建议还是别开启corepack enable npm
了,太折腾了,开启yarn和pnpm即可。
如果版本是18,建议直接使用18的最新版本Node v18.19.1。
提示最推荐直接使用Node最新版,毕竟corepack
随着版本也在更新发布。
2. node v14开启corepack后使用yarn报版本问题
原因简述:
因为corepack默认安装了yarn和pnpm的最新版,而最新版yarn或者pnpm的node版本要求可能高于14。
解决办法: 利用以下命令切换适合的版本
1 | corepack prepare yarn@x.y.z --activate # 切换数字版本 |
3. 开启corepack后,执行失败Internal Error
其实会去网络下载pnpm和yarn,如果也开启npm,同理会去下载npm,可能会因为网络下载失败。
多试几次,或者看看官方缓存策略,官方环境变量里面可以设置访问url地址,但是发现国内用的淘宝镜像地址因为是重定向模式,目前无法用。环境变量
4. 如果没网环境呢
在有网机器上,把管理器缓存导出到tgz文件,在没有网的环境中导入,如下:
1 | # 导出 |
ni
我们通过corepack
可以限制我们使用什么管理器,但是还能不能再方便点,这边在corepack
的基础上推荐一个其它工具ni
ni - 使用正确的包管理工具
上面,我们使用corepack
以及配合在package.josn
中添加的packageManager
限定字段,让我们可以在某个项目中指定使用哪个包管理器,一旦使用其它的就会报警告并停止执行。那么,有没有一个工具,自动去识别我的设置,默认执行我的包管理器呢?
那么, ni可能适合你。它会根据你项目中的锁文件或者packageManager
配置,自动识别管理工具。corepack
目前只支持npm、pnpm以及yarn,而ni是支持前面三个基础上,还支持bun(新的工具,认命了,毁灭吧)。
安装
1 | npm i -g @antfu/ni |
使用
ni其实相当于利用它自己的命令替换几个包管理器对应的命令,所以如果要让它默认执行,其实相当于你要用它的替代命令。
首先,我们要有一个的前提。ni假定您使用锁文件(必须得有,现在新版不管npm还是pnpm,还是yarn执行依赖加载时其实都会产生,所以除非自己刻意处理,一般不会有问题)。
在它运行之前,它将在你的项目目录检测你的当前包管理器(或packageManager字段),yarn.lock
、pnpm-lock.yaml
、package-lock.json
、bun.lockb
、packageManager
。然后默认去运行相应的包命令
那么命令都有啥?
ni
- install
1 | ni |
以上面安装依赖命令为例,我们直接在项目目录输入ni执行,它会根据自己检索到的lock文件或者配置,使用对应的包管理工具去执行下载,下面的命令同理。以我上面配置过packageManager
的项目为例,直接执行ni,可以看到直接使用pnpm开干了。
1 | ni vite |
1 | ni @types/node -D |
1 | ni --frozen |
1 | ni -g eslint |
nr
- run
1 | nr dev --port=3000 |
1 | nr |
1 | nr - |
nlx
- download & execute
1 | nlx vitest |
nu
- upgrade
1 | nu |
1 | nu -i |
nun
- uninstall
1 | nun webpack |
1 | nun -g silent |
nci
- clean install
1 | nci |
如果不存在相应的管理器,则此命令将在此过程中全局安装它。
na
- agent alias
1 | na |
1 | na run foo |
问题
执行顺序
我们上边说了,ni会去检测项目目录的lock文件,然后选择使用哪个工具。但是,如果几个包管理工具锁文件都有呢?
经过验证:
- 如果
package.josn
设置了packageManager
参数,那么以其指定的工具为准。 - 如果没有
packageManager
限定工具,会从pnpm->yarn->npm依次检索lock文件。
- 如果