Nub 在原生 Node 上运行你的代码并为你提供正确版本。固定一个版本、运行文件,匹配的 Node 被下载和缓存而无需第二个命令——隐式路径覆盖常见情况,所以你很少手动管理版本。nub node 子命令覆盖自动路径达不到的:运行前预热缓存、列出已安装的、回收磁盘和记录固定。

自动提供

在项目中放置 .node-version.nvmrc(或 package.json 中的 engines.node 范围)然后运行 nub。如果该 Node 已在你的机器上则按原样使用;如果没有,Nub 从 nodejs.org 下载匹配的原生构建——SHA-256 验证并缓存在 ~/.cache/nub/node 下——然后运行你的代码。Nub 自身提供固定版本而非交给 nvmfnmmise;当树上任何地方都没有固定时,它使用 PATH 上已有的 node

$ echo {{NODE_VERSION}} > .node-version
$ nub index.ts
Using Node.js {{NODE_VERSION}} (resolved from .node-version)
Installing from nodejs.org... (24 MB)
Installed in 8.0s
# ...你的脚本运行,确切在你固定的 Node 上

在完全没有 Node 的新机器上——你先安装了 Nub——裸 nub file.ts 仍能运行。无固定且 PATH 上无 node 时,Nub 提供最新发布版本并在其上运行你的代码,下载前重用缓存中已有的最新版本。无论何时想要可重现版本就固定一个(nub node pin <version>);在那之前,每次运行拾取最新。

$ nub app.ts          # 新机器:无固定,PATH 上无 Node
Using Node.js {{NODE_VERSION}} (resolved from latest)
Installing from nodejs.org... (30 MB)
Installed in 5.1s
# ...你的脚本运行

以下内容是关于有意识地执行这些步骤之一而非让它在下次运行时发生。关于完整提供故事——~/.cache/nub 布局、每调用垫片——参见运行文件 → Node 版本

版本优先级

两个问题决定运行哪个 Node:固定哪个版本,然后该二进制文件从哪来。两者都按固定顺序解析。

固定哪个版本

与 Corepack 的垫片一样,nub 自身按需自动安装 Node 版本。当你用 nub 运行文件时,它推断你项目期望的 Node 版本,然后提供和缓存它。Nub 从工作目录向上遍历到最近的固定,最高优先级在前:

  1. NODE_EXECUTABLE — Node 二进制的绝对路径。硬覆盖:它跳过固定文件读取、缓存、nvm 和任何下载,直接使用该二进制文件。其版本仍被检测,所以 Node 下限检查和层级分派仍适用。这是唯一的版本管理覆盖。
  2. package.json#/devEngines/runtimenode 条目(精确或范围)。声明非 Node 运行时的 devEngines.runtime 默认拒绝;onFail: "warn" 打印通知并回退,onFail: "ignore" 静默回退。
  3. .node-version
  4. .nvmrc
  5. package.json#/engines/node — 解释为解析范围而非精确固定:Nub 解析到满足它的最新可用版本。
  6. 树上任何地方都没有固定PATH 上的 node,或完全没有 node 时的最新发布。

此解析的 Node 版本被自动安装并缓存以供将来运行。

$ echo {{NODE_MAJOR}} > .node-version
$ nub hello.ts
Using Node.js {{NODE_VERSION}} (resolved from .node-version)
Installed in 9.8s
Hello world!

在单个目录中,.node-version 优先于 .nvmrc(它是工具中性的标准)。发现向上遍历目录树到最近的固定并跳过位于已安装依赖(node_modules 下)中的固定文件——依赖自身的 CI 固定从不驱动你的项目。package.json 字段(devEngines.runtimeengines.node)从工作区根清单读取(当上方存在一个时),否则最近的 package.json——monorepo 在根处一次性固定其 Node。

二进制文件从哪来

一旦版本固定,Nub 按顺序找到它的二进制文件:

  1. PATH 上的 node,如果其版本满足固定——所以 fnm / Volta / mise 自动切换就能工作。
  2. Nub 自身的下载存储~/.cache/nub/node/<version>/)。
  3. nvm 安装的版本(nvm 扫描)。
  4. 从 nodejs.org 下载匹配的原生构建——SHA-256 验证并缓存——否则报错。

nub node install

现在将版本提供到缓存中,而非在下次 nub <file> 时。用例是在设置步骤中预热 CI 缓存(GitHub Action 为你做这件事),或在你离线前获取 Node。

nub node install {{NODE_MAJOR}}          # 最新 {{NODE_MAJOR}}.x
nub node install lts         # 最新 LTS 线
nub node install 20.11.0     # 精确版本
nub node install 20 22       # 同时多个

别名和范围以与固定相同的方式解析——ltslatestlts/<codename>、裸主版本({{NODE_MAJOR}})或 major.minor22.13),或精确版本。无参数时,nub node install 读取你项目的固定并提供它:

# 安装 .node-version / .nvmrc / engines.node 命名的版本
nub node install

已在缓存中的版本是无操作;已在 PATH 上的版本(系统安装、nvmfnm、…)被报告并跳过而非重新下载。

$ nub node install {{NODE_VERSION}}
Node {{NODE_VERSION}} is already available on PATH — skipped

nub node ls

列出 Nub 缓存中的版本,最新在前。你当前目录解析到的版本被标记。

$ nub node ls
 {{NODE_VERSION}}
  22.13.0
  20.11.0

只显示 Nub 自身的下载缓存——ls 不枚举你的 nvm / fnm / 系统安装。 标记仅在解析版本是 Nub 已缓存的一个时出现。

nub node uninstall

通过删除缓存版本回收磁盘。Nub 防止删除你当前目录解析到的版本。

$ nub node uninstall 20.11.0
Removed Node 20.11.0 from the cache

ls 一样,这仅对 Nub 的缓存操作。

nub node pin

为项目写入 .node-version,使该树中后续每个 nub 使用它。这是手动创建固定文件的显式形式。

$ nub node pin {{NODE_MAJOR}}
pinned Node {{NODE_MAJOR}} → /path/to/project/.node-version

一些有意为之的行为:

  • 固定项目,不是子目录。 从项目内任何位置运行,文件落在项目根目录——最近的 package.json 目录——而非你当前的子文件夹。
  • 在工作区中,固定整个仓库。 Node 版本是仓库的属性,不是一个包的,所以在 monorepo 中固定写入工作区根目录。
  • 编辑你已有的固定文件。 如果项目带 .nvmrc 但无 .node-versionpin 原地更新 .nvmrc

无论你给什么规范都原样写入——包括像 lts 的别名——且 pin 离线工作。.node-version 文件是工具中性的约定(nvmfnmvoltaasdf 都读取它),所以固定可移植到你的其他工具。

nub node which

解析这里运行哪个 Node 以及它位于何处。二进制路径到 stdout;» resolved from <source> 说明到 stderr,所以它从不污染捕获值。

$ nub node which
/Users/you/.nvm/versions/node/v{{NODE_VERSION}}/bin/node
» resolved from .node-version ({{NODE_VERSION}})

stdout/stderr 分离意味着 nub node which 在 shell 中可组合——捕获路径,说明不进入变量:

$ NODE=$(nub node which)
» resolved from .node-version ({{NODE_VERSION}})
$ echo "$NODE"
/Users/you/.nvm/versions/node/v{{NODE_VERSION}}/bin/node

无固定时说明读取 » resolved from node on PATH。裸 nub node 改为打印状态块——版本、路径和解析来源在不同行上。

nub node shim

使 node 自身通过 Nub 解析,所以没有安装 Node 的机器也能运行 node。这是全新安装的故事:brew install nub(或 curl 脚本)、nub node shim,现在裸 node file.js 工作——Nub 解析正确版本,缺失时提供它,并运行它。

$ nub node shim
node shim in /Users/you/.nub/node-shim (created)
  `node` now resolves through nub (version management only — no augmentation; run `nub` for that)
  added /Users/you/.nub/node-shim to PATH in /Users/you/.zshrc
  restart your shell, or run: source /Users/you/.zshrc

垫片的 node 运行原生 Node,不变。它解析和提供版本——上方优先级——但不添加其他任何东西:无 TypeScript、无注入全局变量、无自动 .env。裸 node 行为像 nodenub 是添加运行时功能的。所以 node app.ts 按原生 Node 的方式做类型剥离,而 nub app.ts 转译并运行它。

这是可选且可逆的,与 nub pm shim 形态相同。它在 ~/.nub/node-shim 中安装 node 链接并将该目录添加到你的 PATH;因为那在前方,你稍后安装的 Node(brew install node)被遮蔽直到你取消垫片。在 nub upgrade 后重新运行 nub node shim 重新链接。

$ nub node unshim
removed /Users/you/.nub/node-shim
  PATH: removed the node-shim block from /Users/you/.zshrc

镜像和代理

Node 下载遵守 HTTP(S)_PROXYNO_PROXY,TLS 拦截的企业 CA 通过系统信任存储开箱即用。要从内部镜像而非 nodejs.org 获取 Node,设置标准环境变量或 pnpm 使用的 .npmrc 键——Nub 两者都读取,无 Nub 特定配置:

# .npmrc(项目或 ~)
node-mirror:release=https://artifactory.corp.example/node/

NODEJS_ORG_MIRROR 环境变量(nvm/n 约定)优先于 .npmrc 键。镜像也用于 musl 构建——在 Alpine 上指向一个携带 unofficial-builds 布局的镜像。

相关

  • 运行文件 — 提供如何在正常 nub <file> 运行期间触发。
  • FAQ — 支持的 Node 下限和兼容性。