Node.js Corepack

内容分享23秒前发布
0 0 0

Node.js Corepack

TL;DR

Node.js 默认提供 npm 包管理器,Corepack 为您提供 Yarn 和 pnpm,而无需安装它们

提出问题

Node.js 除了本身自带的 npm 包管理器,还有很有多的包管理器,列如 Yarn 和 pnpm 等等,不过上面三个是最最流行的方案。

参与不同项目,尤其是为开源项目贡献代码,会遇到两个问题:

  1. 代码都拉下来了结果发现还要安装对应的包管理器,等下载下来贡献代码的热烈都没了。
  2. 项目是 pnpm 的项目却使用了 npm 来安装。
  3. 项目使用 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.2v16.15.1 版本:

Node.js Corepack

我们可以查看,对应版本 Node.js 支持的全局命令,盲猜也知道 v14.18.2 应该没有 corepack 命令,而 v16.15.1 应该比 v14.18.2 多一个全局命令,即 corepack 命令。

编辑器里观察:

Node.js Corepack

通过目录树观察:

.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

结论:

  1. v14.18.2 版本的 Node.js 只有三个全局命令,分别为 nodenpmnpx
  2. v16.15.1 版本的 Node.js有四个命令,分别为 corepacknodenpmnpx

目前我们要使用 v16.15.1 版本来玩转 corepack 命令了。

Note*
由于 Node.js Corepack 还没有稳定,处于实验状态,所以需要我们手动启用,Node.js 更新很快的,信任过不了多久,安装完 Node.js 默认就启用 Node.js Corepack 功能了。

先检查下全局有没有 yarn 和 pnpm 命令:

Node.js Corepack

接下来输入命令启用 corepack,安装 yarn 和 pnpm(并不是安装,由于 Yarn 和 pnpm 已经在本地了,这里真实情况是创建全局命令,缘由下面解释):

corepack enable

再次观察 ~/.nvm/versions/node/v16.15.1/bin 文件夹,我们发现多了四个快捷命令:

Node.js Corepack

整个过程没有下载任何东西,corepack 只是简单的创建了四个快捷命令,此时全局就可用 pnpm 和 yarn 命令了,默认安装的版本如下。

Node.js Corepack

今天是北京市时间 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 就会抛出错误使用错误。

Node.js Corepack

如果把 packageManager 改为 "yarn@1.22.15",使用 pnpm 安装,项目也会抛出错误。

Node.js Corepack

Note
如果你不想遇见这个问题,在启用 corepack 的情况下,使用 Ni 神器。

Node.js Corepack 默认无法拦截 npm

这里有一个坑,无论 "packageManager" 的值为 pnpm 还是 yarn 的项目,都可以使用 npm 命令。

Node.js Corepack

这就奇怪了,Corepack 可以拦截 Yarn 和 pnpm,但是却没有办法拦截 npm,难道说遇到 bug 了。

这并不是 bug,这是由于 Corepack 这么处理实则是有缘由的,就是为了能让 npm 作为全局包管理器在任何项目完美运行,当然如果你想拦截也是可以的,需要通过 corepack enable npm 解决。

Node.js Corepack

包管理版本不匹配(静默下载)

好了,目前假定 packageManager 为 pnpm@6.32.23 ,我们本地 pnpm 的版本为 6.11.0,安装一个 lodash 包。

  1. 断开网络情况下

Node.js Corepack

  1. 联网情况下

pnpm 会静默下载 pnpm@7.32.23 版本,然后安装成功。

Node.js Corepack

yarn 同理。

应该使用 Corepack 吗

增强功能,能使用就是用吧,而且最近看许多技术文档能支持的都支持了,列如:

  1. https://pnpm.io/installation#using-corepack
  2. https://github.com/antfu/contribute#corepack
  3. 等等

其他 corepack 命令介绍

使用 corepack --help 打印 corepack 详情:

Node.js Corepack

启停用 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 把此版本设置为默认。

Node.js Corepack

生产环境需要离线的包管理器

许多生产环境没有网络访问权限,我们可以先下载下来然后使用本地的包管理器。

Node.js Corepack

王者组合

接下来介绍包管理器的天花板,请出王者组合 Corepack 配合 Ni。

Corepack 的好处我们清楚了,目前是不同包管理器命令的差异怎么解决,Ni 就是为此而生,二者搭配,王者无敌

总结

Corepack 是一种增强包管理器的,好处是不用下载 Yarn 和 pnpm,搭配 "packageManager" 还能避免包管理器的混用,所以安装 Node.js 之后别忘了下面三个步骤:

  1. corepack enable
  2. corepack enable npm
  3. 安装 Ni
© 版权声明

相关文章

暂无评论

none
暂无评论...