vlt 是一款免费、开源的 JavaScript 包管理器,由当年创建并维护 npm 的团队打造。
自 1.0 版本发布以来,vlt 已成为一个值得认真考虑的选择。它基于 package.json 进行安装,将安装过程拆分为下载阶段和脚本执行阶段,并提供了一套用于查询依赖图的查询语言。真正的阻力来自细节:lockfile、.npmrc 认证、postinstall 脚本,以及最关键的——你的包究竟从哪个 registry 获取。本指南将在一个现有项目上逐一梳理这些问题,并在最后给出明确结论。
核心要点
- 根据当前客户端文档,vlt 没有默认 registry。安装之前,你需要通过
vlt config set registries=npm=…将npm别名指向某个 registry,或者运行vlt setup来使用你的 vlt.io 账户所配置的 registry。 vlt install不会执行任何依赖脚本。随后,vlt build会为所有包含生命周期脚本的包执行这些脚本,并跳过存在已知恶意软件告警的包,除非你使用选择器缩小目标范围。- vlt 会忽略
package-lock.json,重新解析依赖树并生成vlt-lock.json,因此切换后传递依赖的版本可能会发生变化。 vlt query使用:scripts、:malware、:prod等 CSS 风格的选择器,从已解析的依赖图中筛选包。
vlt 包管理器是什么?由谁打造?
vlt 由包管理器客户端和托管 registry 服务两部分组成,出自 npm 的打造者之手。由 Darcy Clarke、Ruy Adorno 和 Luke Karrys 联合署名的 2024 年 11 月发布公告将其定位为免费开源工具。vlt 1.0 于 2026 年 8 月 4 日发布,此后陆续推出了多个 1.x 版本。
对 npm 用户来说,vlt CLI 的用法会很眼熟,但其底层架构截然不同。如果你正在将它与另一个主流 npm 替代方案进行比较,可以参阅 pnpm 如何解决同样的问题。
安装 vlt 并在现有项目中运行
你可以通过官方脚本或 npm 安装 vlt。安装完成后,vlt install 负责获取依赖,vlt build 负责执行依赖的脚本。
# official installer, then configure a registry and account
curl -fsSL https://install.vlt.sh | bash
vlt setup
# or install through npm
npm install -g vlt
cd your-project
vlt install # resolve, download, extract; no dependency scripts run
vlt build # run lifecycle scripts for eligible packages
通过 npm 安装的方式记载于 npm 迁移指南中。在运行 vlt install 之前,必须先配置 registry。配置文档指出,vlt 不附带任何默认值,在你完成设置之前,任何需要访问 registry 的命令都会因配置错误而终止。
你需要处理项目根目录下的两个文件:
vlt.json:项目配置文件,取代.npmrc。vlt-lock.json:vlt 的 lockfile。
根据 npm 迁移指南,vlt 不会读取 package-lock.json,而是从零开始重新解析所有依赖。你可以删除旧的 lockfile,也可以在两个工具并行使用期间保留它。这种方式不如 pnpm 的 lockfile 导入功能那样平滑(详见从 npm 切换到 pnpm)。在合并任何改动之前,请务必对比解析出的版本差异。
| npm | vlt |
|---|---|
npm install | vlt install |
npm ci | vlt ci(vlt install --expect-lockfile 的简写) |
npm rebuild(执行脚本) | vlt build |
npm config set registry=… | vlt config set registries=npm=… |
npm ls | vlt list |
npm explain <pkg> | vlt query '#<pkg>' |
vlt 能否做到无缝替换?
“无缝替换”(drop-in)是需要你亲自验证的,而不是想当然的。2024 年的发布公告称 vlt“在大多数情况下”可以替代你现有的包管理器;1.0 版本的公告则更进一步,直接称该客户端可无缝替换 npm。但这两种说法都出自厂商之口。请在你自己的项目上检查以下五个方面:
.npmrc配置。 文档中并未说明 vlt 会读取.npmrc。registry 和 scope 配置应写入vlt.json的scoped-registries字段下。按照 npm 迁移指南的说明,认证 token 应存放在 vlt 的 keychain 文件或VLT_TOKEN环境变量中。私有 scope 往往是迁移过程中最先出问题的地方。- 带安装脚本的包。 原生扩展(native addon)以及需要下载二进制文件的包,在运行
vlt build之前都无法正常工作(详见下文)。 - Peer 依赖。 安装文档指出,vlt 力求让每个 peer 依赖只保留一份副本。如果依赖树的两个部分所需的 peer 版本互不兼容,vlt 会为各部分分配独立的 peer 上下文。因此,那些在 npm 下报 ERESOLVE 错误的依赖树,在 vlt 下可能可以成功解析,但可能会存在多份 peer 副本。
- Workspaces。 vlt 文档中有专门介绍 monorepo 的页面,请对照检查你的项目结构。
- CI。 先运行
vlt ci,再运行vlt build。
切换包管理器引发的回归问题,可能顺利通过 CI,直到生产环境才首次暴露。某个传递依赖版本的变化,或者本应生成文件的 postinstall 脚本被跳过,都可能表现为浏览器端的运行时错误。借助带有控制台和网络请求捕获功能的会话回放(session replay),可以将这类错误与修改了 lockfile 的那次部署关联起来。
Registry:你的包从哪里来
vlt 客户端没有默认 registry,需要你自行选择。registry 文档指出,安装类命令(vlt install、vlt ci、vlx 等)要求必须设置 npm registry 别名。仅在 vlt.json、命令行参数或 VLT_REGISTRY 中设置普通的 registry 值,对这些命令来说是不够的。另一种方式是运行 vlt setup,它会配置你 vlt.io 账户下的 registry。
运行 vlt setup 会改变你的包来源:它将 npm 别名指向你的账户在 vlt registry 上的镜像。vlt 官网介绍,每一个公共包请求都会在该镜像上经过安全检查,已知的恶意软件会被拦截。这意味着你的信任根(trust root)从 npm 转移到了 vlt。
如果要直接使用 npm 公共 registry,请运行:
vlt config set registries=npm=https://registry.npmjs.org/
在项目目录下运行该命令,会将别名写入项目的 vlt.json。请将该文件提交到代码仓库,以确保整个团队和 CI 使用相同的包来源。
需要注意的一点是:2026 年 4 月提交的一个 issue 反馈,vlt install 会沿用现有 vlt-lock.json 中记录的 registry URL。如果你切换了 registry,请重新生成 lockfile。
Registry 拦截只能阻止已被识别的恶意软件。新发布的恶意版本在被人标记之前,仍可能蒙混过关。有私有托管需求的团队,还可以自行部署 vsr——vlt 推出的兼容 npm、采用 Fair Source 许可的 registry。根据发布公告,vsr 支持本地部署、自托管和托管服务三种使用方式。
安全默认设置:分阶段安装与 vlt build
vlt install 不会执行任何依赖脚本。随后,vlt build 会为所有包含生命周期脚本的包执行这些脚本,但存在已知恶意软件告警的包除外,除非你用选择器缩小了目标范围。build 文档给出的默认目标如下:
:scripts:not(:built):not(:malware)
这里没有交互式的审批提示。批准脚本的方式是编写一条范围更窄的依赖选择器语法(Dependency Selector Syntax)查询:将其作为 build 的目标参数传入,或在安装时通过 --allow-scripts 指定,并将其保存到 vlt.json 中,以便整个团队统一使用。vlt build 发布公告详细介绍了这一模型。
在实践中,分阶段安装意味着:那些需要通过 postinstall 脚本获取预编译二进制文件或编译原生扩展的包,在执行 vlt install 后并未完成构建。任何依赖其二进制文件或生成文件的内容,在运行 vlt build 之前都可能失败。请将 vlt build 加入每一个初始化脚本和 CI 任务中。
这一思路与默认禁用 npm 安装脚本如出一辙。不过,使用方的管控措施只能保护安装环节。在发布方,应当使用 npm pack --dry-run 检查包内容,以免发布了不该发布的文件。
使用 vlt query 查询依赖图
vlt query 使用 CSS 风格的选择器从已解析的依赖图中筛选包,就像 querySelectorAll 从页面中选取元素一样。根据 1.0 版本公告,vlt 提供了 60 多个依赖图伪选择器,其中约 30 个与安全相关。vlt 的 insights 选择器博文指出,这些安全选择器使用的是 Socket 的元数据。
vlt query ':scripts' # packages with install scripts
vlt query ':malware' # packages with known malware alerts
vlt query ':prod' # production dependencies only
vlt query ':scripts' --view=mermaid # render matches as a Mermaid diagram
query 文档列出了支持的输出模式:human、json、mermaid、svg、png 和 count。建议从 :scripts 开始,因为 vlt build 默认就是从这份列表中进行选择的(之后再跳过已构建的包和存在恶意软件告警的包)。根据 vlt 关于 host context 的博文,:host(local) 可以在 vlt 控制台中配置的多个项目之间执行查询。
同样的选择器也适用于 CI:
- run: npm install -g vlt
- run: vlt ci # vlt install --expect-lockfile
- run: vlt build
- name: Report dependencies with malware alerts
run: vlt query ':malware' --view=count
如果希望最后一步在发现问题时让任务失败,可以加上 query 文档中介绍的 --expect-results=0 参数。查询语句在任何环境下都保持一致:它就是你的策略,以一条选择器字符串的形式保存。
结论:值得在业余项目中尝试,但尚不宜作为默认选择
现在就值得在业余项目中试用 vlt。对于生产团队而言,在自身的 CI、私有 registry 认证以及带安装脚本的包都能在 vlt 下顺利运行之前,应继续沿用现有的包管理器。分阶段安装和 vlt query 都很实用,但重新解析 lockfile 以及 registry 的选择需要经过审慎决策。如果你最看重安装速度,建议在自己的代码仓库上与 pnpm 12 的 Rust 重写版本进行对比。
从一个分支开始:显式设置 npm registry 别名,依次运行 vlt install、vlt build 和 vlt query ':scripts',并在任何改动合入 main 分支之前,将 vlt-lock.json 中解析出的版本与旧 lockfile 进行对比。
常见问题
vlt 需要哪个版本的 Node.js?它还会创建 node_modules 文件夹吗?
vlt 包要求 Node.js 22.22 或更高版本。vlt 仍会生成 node_modules 目录,但会在 node_modules/.vlt/ 下使用自己的内部结构,这与 npm 的扁平化依赖树不同。默认情况下,vlt 在 Linux 上会从全局存储中硬链接文件,而在 macOS 和 Windows 上则会逐个解压每个包;可以通过 store-linker 设置修改这一行为。运行时包的解析方式保持不变,因此你的应用代码无需做任何修改。
使用 vlt 时,用什么替代 npx 和 npm run?
vlt exec 用于替代 npx,也可以写作 vlt x 或使用 vlx 快捷命令。它用于运行包的可执行文件,若该包不在 node_modules 中则会下载,但在获取任何新包之前会先征求你的确认。vlxl 则只运行已安装的可执行文件。vlt run(简写为 vlr)用于运行 package.json 中的脚本,并会执行对应的 pre 和 post 钩子。两者都支持通过 --scope 选择器指定目标 workspace。
如何将 npm 的 overrides 迁移到 vlt?
vlt 中与 npm overrides 字段等效的功能是 Graph Modifiers(依赖图修饰器)。你需要在 vlt.json 中定义它们,并以依赖选择器语法(Dependency Selector Syntax)查询的形式编写。这样一来,你不仅可以按包名定位依赖,还可以按路径、workspace 或 semver 范围进行定位。当多个修饰器匹配同一个依赖时,vlt 会采用类似 CSS 优先级(specificity)的规则来决定哪一个生效。
如何在 vlt monorepo 中配置 workspaces?
vlt 会原样读取根目录 package.json 中的 workspaces 字段,因此现有的 npm 或 yarn monorepo 无需任何修改即可使用。如果你需要对 workspace 进行命名分组,或者正在从 pnpm-workspace.yaml 迁移,请使用根目录 vlt.json 中的 workspaces 字段。如果 vlt.json 中存在 workspaces 字段,vlt 将只使用该字段,而忽略 package.json 中的配置,两者不会合并。在 vlt.json 中,该字段的值可以是一个 glob 字符串、一个 glob 数组(如 packages/*),或者一个由命名分组组成的对象,每个分组映射到若干路径或 glob。普通数组会被归入名为 packages 的默认分组。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k