跳至主要內容

nodejs 与 nvm、npm、pnmp、yarn、corepack 的关系

Mr.zha0cai大约 15 分钟

Nodejs

Run JavaScript Everywhere

Node.jsopen in new window® is a free, open-source, cross-platform JavaScript runtime environment that lets developers create servers, web apps, command line tools and scripts.

Node.js 是由 Ryan Dahlopen in new window 用 C++ 开发的,Node.js 不是库,是一个运行环境,或者说是一个 JS 语言解释器。

以前 JS 只能运行在浏览器中,Node.js 出现之后,不管是服务器上,还是我们自己的的笔记本上,只要安装了 Node.js 就可以运行 JS 代码了。

用法open in new window

node [options] [V8 options] [script.js | -e "script" | - ] [arguments]

常用命令:

  • node <filename>​:运行指定的 JavaScript 文件。
  • node:启动 Node.js REPL(交互式解释器)。
  • node --inspect <filename>​:以调试模式运行指定的 JavaScript 文件。
  • node --version​:查看已安装的 Node.js 版本。
  • node --help​:获取 Node.js 命令行帮助信息。

nvm

nvm,全称是 Node Version Manager,是用来管理 node.js 的版本的。

因为 Node.js 在不断的被完善,分版本迭代更新。

不同的 node 项目所依赖的 node 版本可能不相同,本机也支持安装多个 node 版本,所以可以通过 nvm 来管理 node 的版本。

常用命令:

> nvm --help // 帮助指令

> nvm list [available]   // List the node.js installations. Type "available" at the end to see what can be installe

> nvm install <version> [arch] // The version can be a specific version, "latest" for the latest current version, or "lts" for the

> nvm current    // Display active node.js version.

> nvm use [version] [arch]    // Switch to use the specified version. Optionally use "latest", "lts", or "newest".
                              // "newest" is the latest installed version. Optionally specify 32/64bit architecture.
                              // nvm use <arch> will continue using the selected version, but switch to 32/64 bit mode.

> nvm [--]version    // Displays the current running version of nvm for Windows. Aliased as v.

======== e.g.
> nvm list available

|   CURRENT    |     LTS      |  OLD STABLE  | OLD UNSTABLE |
|--------------|--------------|--------------|--------------|
|    21.7.1    |   20.12.0    |   0.12.18    |   0.11.16    |
|    21.7.0    |   20.11.1    |   0.12.17    |   0.11.15    |
|    21.6.2    |   20.11.0    |   0.12.16    |   0.11.14    |

安装的 nodejs 会在你选择的目录下,我安装的如下图。

image

Package Manager

npm

概述

在没有 npm 之前,一个前端项目想要使用其他项目的代码,即把别人写的 javascript 代码引入到项目中直接用,避免重复造轮子,提高开发效率,需要跑到其他项目对应的官网上去下载对应的代码放到自己的项目里,导致如果该项目需要依赖其他很多的项目,然后就要访问不同的网址去下载对应的代码

  • 去 jQuery 官网下载 jQuery
  • 去 BootStrap 官网下载 BootStrap
  • 去 Underscore 官网下载 Underscore
  • ……

于是由一个拥有三大美德的程序员 Isaac Z. Schlueteropen in new window (以下简称 Isaaz)给出一个解决方案:用一个工具把这些代码集中到一起来管理吧!那就是 npm,全称是 Node Package Manager,是以 JavaScript 编写的软件包管理工具,用来安装 node 项目所需要的一堆依赖包。

安装及使用

Node.js 内置了 npm,直接用就行。

image

常用指令

  • npm init -y​​:初始化一个新的 Node.js 项目,根据 guide 生成一个 packagejson 的文件,项目的配置信息。(-y​​ 或者 --yes​​: 这个选项表示在初始化项目时,自动使用默认选项,而不需要用户交互确认。)

  • 查看当前 npm 版本: npm -v​​​

  • 安装需要的包

    npm install 包名 --save​​

    npm install 包名 -g​​​​ : 全局安装,安装后在命令行任意目录下可直接使用包命令

    --save​ 会在 package.json​ 中保存到 dependencies​ 这个依赖项中,在 npm 5 以后的版本不用加上这个参数也会自动加入到 dependencies​ 这个依赖项中。

  • 更新包: npm install 包名 @latest​​​

  • 卸载包: npm uninstall 包名​​​

  • 换源:npm --registry 源地址​​​

pnpm

概述

快速的,节省磁盘空间open in new window的包管理工具。

  • 快速:pnpm is up to 2x faster than npm
  • 高效:node_modules 中的文件为复制或链接自特定的内容寻址存储库
  • 支持:monorepos:pnpm 内置支持单仓多包
  • 严格:pnpm 默认创建了一个非平铺的 node_modules,因此代码无法访问任意包

安装及使用

官方地址

1. pnpm 是 pnpm 的普通版本,需要 Node.js 来运行。
npm install -g pnpm

2. @pnpm/exe 与 Node.js 一起打包成可执行文件,因此可以在未安装 Node.js 的系统上使用。
npm install -g @pnpm/exe

3. 升级版本
pnpm add -g pnpm

​​

常用命令

pnpm add <pkg> | pnpmopen in new window

1. 与 npm 不同,pnpm 验证所有选项。例如, pnpm install --target_arch x64 将失败,因为 --target_arch 不是 pnpm install 的有效选项。

npm install      == pnpm install
npm i <pkg>      == pnpm add <pkg>
npm run <cmd> == pnpm <cmd>

可以看到只下载了一次,但是项目上确实也存在 node_modules\gitbook-plugin-search-pro

image

可能就是因为这个目录链接起来的,具体看官网介绍:

使用 npm 时,依赖每次被不同的项目使用,都会重复安装一次。 而在使用 pnpm 时,依赖会被存储在内容可寻址的存储中,所以:

  1. 如果你用到了某依赖项的不同版本,只会将不同版本间有差异的文件添加到仓库。 例如,如果某个包有 100 个文件,而它的新版本只改变了其中 1 个文件。那么 pnpm update​ 时只会向存储中心额外添加 1 个新文件,而不会因为仅仅一个文件的改变复制整新版本包的内容。
  2. 所有文件都会存储在硬盘上的某一位置。 当软件包被被安装时,包里的文件会硬链接到这一位置,而不会占用额外的磁盘空间。 这允许你跨项目地共享同一版本的依赖。

因此,您在磁盘上节省了大量空间,这与项目和依赖项的数量成正比,并且安装速度要快得多!

image

PS D:\.pnpm-store> tree /f
卷 新加卷 的文件夹 PATH 列表
卷序列号为 5CC2-54DE
D:.
└─v3
    └─files
        ├─04
        │      3e4a27e1d3903298fc32769e0f28b7283ce02a68afb89f9663e7e0625ad3c3c3b613e18eb256b1fdd078a345325f287ecbf0f5d1f979661984d2ae0ac5652b-exec
        │      5b086f61936e1bf0d918b81d321c1b2399f46d9bf3b50fef077214194f5de39b0dd188059b3ce45908febf9f068459626be2fd29ce55c83278e224b8af897d
        │
        ├─05
        │      97a1fc9027497bec956281428ee644ea9a1e0b6b851ed7a276dc1daa685a1cd35661e64e820049a25308c5adaf2c66474151f891b5b6caf27dd8636781750c

yarn

概述

“Yarn 是由 Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 ,正如早期官方文档open in new window中写的,Yarn 是为了弥补 npm 的一些缺陷而出现的。”这句话让我想起了使用 npm 时的坑了:

  • npm install​ ​的时候巨慢。特别是新的项目拉下来要等半天,删除 node_modules,重新 install 的时候依旧如此。
  • 同一个项目,安装的时候无法保持一致性。由于 package.json 文件中版本号的特点,下面三个版本号在安装的时候代表不同的含义。

Yarn 是一个成熟的开源包管理器,用于管理 JavaScript 项目中的依赖项。它有助于安装、更新、配置和删除软件包依赖项的过程,最终帮助您更快地实现目标,同时减少干扰。

Migrating from 1.x / npm 有什么好处open in new window?Yarn Modern 有以下优点

  • Stability
  • New features
  • Flexibility
  • Extensibility
  • Future proof

您可能听说过 Yarn Plug'n'Play,并担心您的项目尚不兼容。不用担心! 此迁移将允许您保留 node_modules​ 文件夹。只有当我们完成后,您才需要决定是否要花时间迁移到 Yarn PnP。无论您是这样做还是留在 node_modules​ 上,迁移到 Yarn Modern 都会有很多好处。

安装及使用

就我个人而言,需求不是很大,用 yarn 应该就足够了。

官方文档:

1. 首先启用 Corepack(如果尚未启用);这会将 yarn 二进制文件添加到您的 PATH 中:
corepack enable

2. 然后初始化一个新项目:
yarn init -2

3. 任何时候你想将 Yarn 更新到最新版本,只需运行:
yarn set version stable
yarn install

========
4. 您可能想要测试 Yarn 的最新版本,该版本尚未在候选版本中发布,甚至尚未合并。以下命令将直接从我们的存储库克隆、构建并在您的项目中安装 Yarn:
yarn set version from sources

5. 它接受一个 --branch 标志,您可以使用它来测试特定的 PR:
yarn set version from sources --branch 1211

======= 使用 npm 安装
# 全局安装
npm install -g  yarn

# 全局安装目录
yarn config set global-folder D:\Yarn\yarn_global

# 缓存目录
yarn config set cache-folder D:\Yarn\yarn_cache

# 查看当前源
yarn config get registry

# 修改为淘宝镜像源
yarn config set registry https://registry.npm.taobao.org

// 初始化一个项目
yarn init

// 添加依赖包
yarn add [package]

// 升级依赖包
yarn upgrade [package]

// 移除依赖包
yarn remove [package]

// 安装全部依赖
yarn install (或者 yarn)

常用指令

如果您来自 npm,主要变化是:
--------
1. 运行 yarn 足以运行安装!它是 yarn install 的别名。
2. 添加或更新对单个包的依赖项是通过 yarn add 完成的。
3. 升级整个项目的依赖项是通过 yarn up 完成的。
4. 您的脚本有别名。调用 yarn build 与 yarn run build 相同!
5. 大多数与注册表相关的命令都移到 yarn npm 后面(例如: yarn npm audit 

所有指令请参考官网:CLI Reference | Yarn (yarnpkg.com)open in new window

> corepack enable
> yarn init -2
Corepack is about to download https://registry.yarnpkg.com/yarn/-/yarn-1.22.22.tgz.

Do you want to continue? [Y/n] y
Corepack is about to download https://repo.yarnpkg.com/4.1.1/packages/yarnpkg-cli/bin/yarn.js.

Do you want to continue? [Y/n] y
➤ YN0000: · Yarn 4.1.1

package.json & packagelock.json

package.json

顾名思义 package.json 文件是包的描述文件,每个项目的根目录下面,一般都有一个 package.json​ 文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据),以便发布到 npm registry。

npm install​ 命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。

详情介绍参考:

image

  • 有一个统一的 package 代码仓库 (npm 官网)
  • 编写自己的 package 和 package.json 文件(参考 npm 官方文档介绍)
  • 通过 npm publish 把 package 放到这个仓库里
  • 其他人的项目里想要使用某些 package 就写到 package.json 文件中,然后运行 npm install,就会自动将这些代码下载下来,统一放到 node_modules 目录中。

packagelock.json

对于 npm 修改 node_modules​ 树或 package.json​ 的任何操作,都会自动生成 package-lock.json​ 。它描述了生成的确切树,以便后续安装能够生成相同的树,而不管中间依赖项更新如何。

  1. npm 安装,没有 package-lock.json 文件,如果 npm 版本是 5+,会自动生成 package-lock.json。有**的话会默认依据该文件进行安装而不是 package.json。** cnpm 不支持(忽略)依据 package-lock.json 文件安装模块,默认依赖 package.json 进行安装。
  2. 需要更新版本,得去更新 package.json 里的模块版本,然后 npm install,才能同步更新到 package-lock.json
  3. 该功能基于 npm5+

版本范围符号 ^~​ 说明

^​ 表示:允许进行不修改 [major, minor, patch]​ 元组中**最左边的非零元素**的更改。换句话说,这允许版本 1.0.0​ 及以上版本的补丁和次要更新,版本 0.X >=0.1.0​ 的补丁更新,以及版本 0.0.X​ 的无更新。

^1.2.3 := >=1.2.3 <2.0.0-0
^0.2.3 := >=0.2.3 <0.3.0-0
^0.0.3 := >=0.0.3 <0.0.4-0

^1.2.3-beta.2 := >=1.2.3-beta.2 <2.0.0-0 请注意,如果 1.2.3 版本大于或等于 beta.2 ,则允许预发布。因此, 1.2.3-beta.4 将被允许,但 1.2.4-beta.2 不会,因为它是不同 [major, minor, patch] 元组的预发布。

^0.0.3-beta := >=0.0.3-beta <0.0.4-0 请注意,仅当 0.0.3 版本大于或等于 beta 时才允许预发布。因此, 0.0.3-pr.2 是被允许的。

========
解析插入符范围时,缺少的 patch 值会脱糖为数字 0 ,但将允许该值内的灵活性,即使主要版本和次要版本都是 0 
^1.2.x := >=1.2.0 <2.0.0-0
^0.0.x := >=0.0.0 <0.1.0-0
^0.0 := >=0.0.0 <0.1.0-0

缺少的 minor 和 patch 值将脱糖为零,但也允许这些值的灵活性,即使主要版本为零。
^1.x := >=1.0.0 <2.0.0-0
^0.x := >=0.0.0 <1.0.0-0
  • "5.0.3​" 表示安装指定的 5.0.3 版本
  • "~5.0.3​" 表示安装 5.0.X 中最新的版本
  • "^5.0.3​" 表示安装 5.X.X 中最新的版本。

~​ 表示:如果在比较器上指定了次要版本,则允许补丁级别更改。如果不允许,则允许进行较小级别的更改。就是说以第二位的小版本号为主,没有的话才以第一位的版本号为主。

~1.2.3 := >=1.2.3 <1.(2+1).0 := >=1.2.3 <1.3.0-0
~1.2 := >=1.2.0 <1.(2+1).0 := >=1.2.0 <1.3.0-0 (Same as 1.2.x)
~1 := >=1.0.0 <(1+1).0.0 := >=1.0.0 <2.0.0-0 (Same as 1.x)
~0.2.3 := >=0.2.3 <0.(2+1).0 := >=0.2.3 <0.3.0-0
~0.2 := >=0.2.0 <0.(2+1).0 := >=0.2.0 <0.3.0-0 (Same as 0.2.x)
~0 := >=0.0.0 <(0+1).0.0 := >=0.0.0 <1.0.0-0 (Same as 0.x)

~1.2.3-beta.2 := >=1.2.3-beta.2 <1.3.0-0 请注意,如果 1.2.3 版本大于或等于 beta.2 ,则允许预发布。因此, 1.2.3-beta.4 将被允许,但 1.2.4-beta.2 不会,因为它是不同 [major, minor, patch] 元组的预发布。

详见官方说明:

现在 corepack

概述

Corepackopen in new window 从 Node.js 16.9 开始可用, 全新的包管理器的管理器,无需安装 npm、yarn、pnpm,只需要一个 Corepack 即可搞定所有。

正如 IE 的唯一作用是安装 Chrome,npm 的作用也是用来安装 yarn/pnpm

Corepack 是 Node.js 推出的包管理器的管理器。类似于 nvm 可以一行命令安装、切换 Node.js 的版本,Corepack 可以一行命令安装、切换 npm / yarn / pnpm 的版本。

除此之外,Corepack 还有一个特性,能够读取项目的 **packge.json**​ 中的 **pacakgeManager**​ 字段,从而自动切换到对应版本的包管理器。这在多人、多项目协作开发中非常有用,比如 pnpm@7.0.0​ 和 pnpm@8​ 不兼容彼此的 pnpm-lock.yaml​,如果 pnpm 版本不统一,很容易出问题。

安装及使用

开启即可,和 npm 一样 nodejs 默认自带。

corepack 目前内置支持的就上面这三个包管理器。

// 开启,会创建所有支持的包管理器的软链(这是一个代理命令)。
// 默认是不会创建 npm 的,是因为随 node 会自带一个全局的 npm
corepack enable
corepack enable npm # npm 需要单独开启,不建议开启


// 禁用,会移除所有由 corepack 管理的包管理器的代理命令软链
corepack disable
corepack disable npm # 如果开启了,关闭也无法还原初始状态,而是删除了corepack 里面的链接

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

# 这会将全局默认 pnpm 更新到最新版
corepack prepare pnpm@latest --activate # 旧版 Node.js 不支持 pnpm@latest,需要具体到 pnpm@x.y.z

========
"packageManager": "pnpm@9.0.0-beta.2+sha256.013b34133be0fd7f97d8739bd1a64a2b2c4b15af936ef77a14f5db26efb6bef4"

建议不要开启 corepack enable npm​​。原因有下面问题 1,还有一个问题就是如果你使用 nvm 或者一些进入目录,可能你设置了一些默认执行 npm 命令的一些脚本,例如 nvm 自动切换等等,一旦你配置的包管理器是 pnpm​​ 或者 yarn​​,那么 npm 肯定会执行报错,可能还有其它各种各样的奇怪问题。

项目中的使用

如果当前 pwd 是一个项目的根目录,corepack 会根据 package.json 中的 packageManager​ 配置,当你使用相应包管理器时,它下载使用配置的版本,如果使用的包管理器不是配置的包管理器,会给出报错提醒,如下图。

image


无网时的使用

对于一些私有部署或者网络限制环境,可以将 cache 导出到 tgz 文件,在使用的环境中导入,如下。

// 导出
$ corepack prepare --all -o corepack.tgz

// 导入
$ corepack hydrate corepack.tgz

安装完成后,使用 cat​ 可以确认,pnpm <args>​ 现在运行的是 corepack pnpm <args>​。​​

按照官方文档open in new window的说法是不需要再自行安装的,可以参考项目的 Readmeopen in new window

corepack 现在是随 node 每个发布的版本一起安装的,就如同 npm 一样,现在安装完 node 之后,你会发现有两个已经全局默认安装的包。

image

image

// 在对应目录下开启后可以直接使用
> corepack enable
> pnpm -v
8.15.6
> yarn -v
1.22.22

--------
> corepack use pnpm
Installing pnpm@9.0.0-beta.2 in the project...
Already up to date

> corepack pnpm -v
9.0.0-beta.2

问题 1

问题: 开启 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@&gt;=9.7.0 by merceyz · Pull Request #276 · nodejs/corepack · GitHubopen in new window

解决办法:

执行 npm install -g corepack ​升级 corepack 即可,截止 2024 年 2 月,最新版是 corepack@0.25.2​,支持 Node v18.17.1 || >=20.10.0​。

前人栽树