包管理工具之npm也慌了?

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将捕获这些调用,并根据情况进行处理:

  1. 如果本地项目已配置您要使用的包管理器,Corepack将静默地下载并缓存最新的兼容版本。

  2. 如果本地项目配置的是不同的包管理器,Corepack将要求您使用正确的包管理器再次运行命令,从而避免破坏您的安装文件。

  3. 如果本地项目没有配置任何包管理器,Corepack将假定您知道自己在做什么,并使用作为"已知良好版本"的固定包管理器版本。

我之前发过一篇文章说了从npm到yarn,再到pnpm的历史和我个人的一些理解,不了解的可以去看看。简单来说,因为一些大牛不满npm的性能或者不满其模块组织方式,或者不满其它什么地方,造了一个有一个轮子,在继续使用npm仓库源的基础上产生了比较出名的yarn以及pnpm。虽然npm感觉到压力,不断改进自己的缺点,学习其它工具的优点,但是用户肯定还是被分流不少,然后以下是我的猜测:估计npm发现也阻止不了用户的分流了,打不过就加入,你爱用啥用啥,我直接出一个包管理工具的管理工具,另辟蹊径,我直接去管理npm,pnpm以及yarn。这个工具就是Corepack.

Corepack是一种简化Node.js项目依赖管理的工具,它提供了一种便捷的方式,使您可以在开发过程中使用不同的包管理器,如Yarn、npm和pnpm,而无需事先安装它们 。通过使用Corepack,您可以在项目中直接运行类似于yarn installnpm installpnpm install等命令,而不必担心在开发环境中安装和配置这些包管理器。

总结一下:

  1. npm又造轮子了,这个轮子用来管理npm,yarn和pnpm,结合package.json配置,我们可以限定项目要使用的工具。
  2. 统一包管理器,不用手动维护包管理器,直接使用支持的包管理器命令即可。看官方介绍那段文字,我们不需要安装yarn和pnpm情况下也能用yarn和pnpm?

Corepack

启用

我们上边官方介绍那一段,有一句话允许您在不安装Yarn、npm和pnpm的情况下使用它们。这句话其实告诉我们很重要的事,以前我们安装完node,然后需要使用pnpm或者yarn,那么需要依次安装一遍。而从node引入Corepack后,看意思不需要再去安装了(当然不是node默认已经安装了,而是用的时会去静默下载安装到Corepack模块内部)。那么怎么用呢?

因为Corepack可能还处于Experimental阶段,所以功能默认是关闭的,需要我们明确开启才能使用,它将在二进制文件旁边设置环境中的符号链接 (并在必要时覆盖现有的符号链接)。

bash 复制代码
#开启
corepack enable
corepack enable npm #npm需要单独开启,不建议开启

#关闭
corepack disable
corepack disable npm #npm需要单独关闭,不建议开启,如果开启了,关闭也无法还原初始状态,而是删除了corepack里面的链接

注意:

  1. corepack enable开启后默认会安装yarn和pnpm的最新版,如果您的node版本是14,yarn或者pnpm的最新版可能要求会比14高,这就陷入一个你启用了,使用时又说你版本太低的问题。我是直接18上安装的。

  2. 这里注意一下,npm还是比较无耻的,它要管理yarn和pnpm,但是npm有点特权(也许是因为处于测试阶段或者自己npm的版本兼容问题),npm也要启用需要单独执行corepack enable npm ,去替换图中的全局npm的软链,不然我们后边使用它管理时就会发现,yarn和pnpm都可以阻止,它自己畅行无阻。(这里面还有个大坑,这个命令谨慎操作,请看后面问题1)

  3. 建议不要开启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,因为它会自己下载(但是要注意网络)。

下载和缓存支持的包管理器最新版(全局环境)

sql 复制代码
corepack prepare --all

切换到指定版本

css 复制代码
corepack prepare pnpm@<version> --activate

在 node16.17 后,支持 latest 下载最新版本

css 复制代码
corepack prepare pnpm@<version> --activate

使用

这一步,我们才开始真正使用Corepack的能力。

我们现在某个项目想只使用pnpm,但是有时候包管理器太多,忘了进去就yarn或者npm,导致产生了不同的依赖结构以及lock文件等等。那么请在package.json中添加packageManager字段。(packageManager后边工具必须指定版本且好像必须指定语义化版本,即x.y.z形式,这就比较坑了,我看issis有人提这个问题了,看看官方会不会放开)

例如:

json 复制代码
{
  "name": "test",
  "version": "3.8.6",
  "description": "test",
  "author": "DLLCNX",
  "private": true,
  "packageManager": "pnpm@7.23.0",
  "scripts": {
    "dev": "vite",
    "build:prod": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "pinia": "2.0.22",
    "vue": "3.2.45",
    "vue-cropper": "1.0.3",
    "vue-router": "4.1.4"
  },
  "devDependencies": {}
}

然后我们在此项目下使用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。

解决办法: 利用以下命令切换适合的版本

bash 复制代码
corepack prepare yarn@x.y.z --activate  # 切换数字版本
#或
corepack prepare yarn@1 --activate  # 切换1版本
#或
corepack prepare yarn@stable --activate  # 切换最新版

3. 开启corepack后,执行失败Internal Error

其实会去网络下载pnpm和yarn,如果也开启npm,同理会去下载npm,可能会因为网络下载失败。

多试几次,或者看看官方缓存策略,官方环境变量里面可以设置访问url地址,但是发现国内用的淘宝镜像地址因为是重定向模式,目前无法用。环境变量

4. 如果没网环境呢

在有网机器上,把管理器缓存导出到tgz文件,在没有网的环境中导入,如下:

bash 复制代码
# 导出
corepack prepare --all -o corepack.tgz

# 导入
corepack hydrate corepack.tgz

ni

我们通过corepack可以限制我们使用什么管理器,但是还能不能再方便点,这边在corepack的基础上推荐一个其它工具ni

ni - 使用正确的包管理工具

上面,我们使用corepack以及配合在package.josn中添加的packageManager限定字段,让我们可以在某个项目中指定使用哪个包管理器,一旦使用其它的就会报警告并停止执行。那么,有没有一个工具,自动去识别我的设置,默认执行我的包管理器呢?

那么, ni可能适合你。它会根据你项目中的锁文件或者packageManager配置,自动识别管理工具。corepack目前只支持npm、pnpm以及yarn,而ni是支持前面三个基础上,还支持bun(新的工具,认命了,毁灭吧)。

安装

css 复制代码
npm i -g @antfu/ni

使用

ni其实相当于利用它自己的命令替换几个包管理器对应的命令,所以如果要让它默认执行,其实相当于你要用它的替代命令。

首先,我们要有一个的前提。ni假定您使用锁文件(必须得有,现在新版不管npm还是pnpm,还是yarn执行依赖加载时其实都会产生,所以除非自己刻意处理,一般不会有问题)。

在它运行之前,它将在你的项目目录检测你的当前包管理器(或packageManager字段),yarn.lockpnpm-lock.yamlpackage-lock.jsonbun.lockbpackageManager。然后默认去运行相应的包命令

那么命令都有啥?

ni - install
arduino 复制代码
ni

# npm install
# yarn install
# pnpm install
# bun install

以上面安装依赖命令为例,我们直接在项目目录输入ni执行,它会根据自己检索到的lock文件或者配置,使用对应的包管理工具去执行下载,下面的命令同理。以我上面配置过packageManager的项目为例,直接执行ni,可以看到直接使用pnpm开干了。

arduino 复制代码
ni vite

# npm i vite
# yarn add vite
# pnpm add vite
# bun add vite
ruby 复制代码
ni @types/node -D

# npm i @types/node -D
# yarn add @types/node -D
# pnpm add -D @types/node
# bun add -d @types/node
scss 复制代码
ni --frozen

# npm ci
# yarn install --frozen-lockfile (Yarn 1)
# yarn install --immutable (Yarn Berry)
# pnpm install --frozen-lockfile
# bun install --no-save
bash 复制代码
ni -g eslint

# npm i -g eslint
# yarn global add eslint (Yarn 1)
# pnpm add -g eslint
# bun add -g eslint

# 这个使用默认配置,而不是当前的工作目录检索的工具
nr - run
ini 复制代码
nr dev --port=3000

# npm run dev -- --port=3000
# yarn run dev --port=3000
# pnpm run dev --port=3000
# bun run dev --port=3000
shell 复制代码
nr

# 交互式地选择要运行的脚本
# supports https://www.npmjs.com/package/npm-scripts-info convention
bash 复制代码
nr -

# 重新运行最后一个命令
nlx - download & execute
arduino 复制代码
nlx vitest

# npx vitest
# yarn dlx vitest
# pnpm dlx vitest
# bunx vitest
nu - upgrade
arduino 复制代码
nu

# npm upgrade
# yarn upgrade (Yarn 1)
# yarn up (Yarn Berry)
# pnpm update
# bun update
bash 复制代码
nu -i

# (not available for npm & bun)
# yarn upgrade-interactive (Yarn 1)
# yarn up -i (Yarn Berry)
# pnpm update -i
nun - uninstall
arduino 复制代码
nun webpack

# npm uninstall webpack
# yarn remove webpack
# pnpm remove webpack
# bun remove webpack
bash 复制代码
nun -g silent

# npm uninstall -g silent
# yarn global remove silent
# pnpm remove -g silent
# bun remove -g silent
nci - clean install
arduino 复制代码
nci

# npm ci
# yarn install --frozen-lockfile
# pnpm install --frozen-lockfile
# bun install --no-save

如果不存在相应的管理器,则此命令将在此过程中全局安装它。

na - agent alias
arduino 复制代码
na

# npm
# yarn
# pnpm
# bun
arduino 复制代码
na run foo

# npm run foo
# yarn run foo
# pnpm run foo
# bun run foo

问题

  1. 执行顺序

    我们上边说了,ni会去检测项目目录的lock文件,然后选择使用哪个工具。但是,如果几个包管理工具锁文件都有呢?

    经过验证:

    • 如果package.josn设置了packageManager参数,那么以其指定的工具为准。
    • 如果没有packageManager限定工具,会从pnpm->yarn->npm依次检索lock文件。

相关文章

包管理工具之从NPM到PNPM

包管理工具之仓库源管理工具nrm

相关推荐
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui
喝旺仔la6 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui6 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui