包管理工具之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 install、npm install或pnpm 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.lock、pnpm-lock.yaml、package-lock.json、bun.lockb、packageManager。然后默认去运行相应的包命令

那么命令都有啥?

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

相关推荐
寂寞狼牙冷2 分钟前
封装fetch替换axios
前端
用户4611696572818 分钟前
网站 HTTPS 不稳定?证书排查指南
前端
n876530 分钟前
Playwright Java WEB UI 自动化实现框架与逻辑
java·前端·ui
keyipatience31 分钟前
TypeScript学习(1)
前端·javascript·学习·typescript·html·css3
xifangge20251 小时前
基于 JavaScript 实现 CNC 数控切削参数与螺纹公差纯前端核算引擎
开发语言·前端·javascript
wangruofeng1 小时前
2026 Web 技术选型指南,AI 时代如何选择适合项目的技术栈
前端·aigc·ai编程
honkun62 小时前
vue 表格组件 vxe-table 修改滚动条样式,修改滚动条样式,统一宽度、颜色与自动隐藏
前端·javascript·vue.js
爱勇宝2 小时前
研究数字孪生的这半年,做了个 Demo,也有了一些新想法
前端·程序员
不可能片场2 小时前
工程实践 一个缓存把选片从十分钟压到一分钟
前端·electron
前端小万2 小时前
探索副业五个月,最终以放弃告终
前端·后端·面试