原始 package.json
修改后 package.json

Package.json Diff:在线比较 npm 清单文件

将旧版 package.json 粘贴到左侧,新版粘贴到右侧,即可查看依赖、脚本和引擎的具体变更。在浏览器中运行,不上传任何内容。

这个 package.json diff 工具是什么

一个免费的浏览器内工具,用于并排比较两个 npm package.json 文件。将旧清单粘贴到左侧,新清单粘贴到右侧,差异会逐字符高亮显示。文本不会离开您的设备,这一点很重要,尤其是当清单属于私有仓库或未发布产品时。

它专为以下场景而设计:当 Renovate 或 Dependabot 的 PR 落地,您需要了解除版本升级之外还发生了什么变化。是否有人悄悄修改了脚本?engines 字段是否从 Node 18 升级到了 Node 20?某个 peerDependency 是否被收紧了?GitHub 的 diff 视图可以回答部分问题,但当您需要逐一扫描多个 PR 或对比尚未推送的分支时,将两个清单粘贴到干净的双栏视图中更为便捷。

底层使用的是与我们 compare-json 页面相同的 JSON 感知 diff 引擎,针对 npm 和 yarn 工作流进行了定制。两个清单在 diff 运行前都会作为 JSON 解析并格式化,因此空白字符的差异不会污染高亮结果。如果需要对非 JSON 清单格式进行纯文本 diff,请使用我们的 compare-text 工具;pnpm-lock.yaml 则可使用 compare-yaml

diff 的实际工作原理

每个面板都会被解析为 JSON。如果解析成功,清单会以统一的两空格缩进重新格式化,并保留原有的键顺序。如果解析失败(多余的逗号、缺少括号、复制粘贴时截断了内容),工具会回退到纯文本模式并告知您出错的行。当两侧均为有效 JSON 后,diff 会逐字符运行,然后通过语义清理将变更分组为可读的块,例如将版本从 ^18.2.0 升级到 ^19.0.0 会显示为一次编辑,而不是九次字符编辑。

右侧面板的插入内容以绿色显示,左侧面板的删除内容以红色显示。两个面板会同步滚动,因此当您在一侧的 devDependencies 深处找到某处变更时,另一侧会跳转到相同的键。由于 diff 在格式化后是文本级别的,它以人类可读的方式呈现结构变化:删除的依赖以一行的形式消失,版本范围的变化在值内部高亮,新增的脚本出现在您指定的位置。

这个工具有意不做的事:它不是依赖解析器。它不会告诉您某个 caret 范围的升级会拉入哪些传递依赖,某个 peer 是否满足,或新版本是否引入了安全公告。为此,请在本地运行 npm install 后执行 npm audit,或使用 npm 配合 Snyk 或 GitHub Dependabot 警报等感知 lockfile 的服务。这个页面告诉您清单文本说了什么,解析工作由您的包管理器负责。

三步完成 package.json diff

两个文本面板,一次 diff。无需 CLI 参数,无需安装,无需阅读 patch 格式。

  1. 1

    将旧清单粘贴到左侧

    从编辑器、git show main:package.json 或团队成员处复制 package.json 的前一个版本,粘贴到左侧面板。工具会将其解析为 JSON 并格式化;如果 JSON 无效,编辑器会显示解析错误,您可以在 diff 之前修复片段。

  2. 2

    将新清单粘贴到右侧

    对更新后的版本执行相同操作。如果您正在审查 Renovate 或 Dependabot 的 PR,最方便的来源是 PR 分支中的原始文件。两个文件都会以统一的缩进格式化,因此空白字符的编辑不会在 diff 中显示为虚假变更。

  3. 3

    阅读高亮的差异

    左侧以红色删除线显示删除内容,右侧以绿色显示插入内容。先扫描依赖块,再检查脚本区域是否有命令修改,然后检查 engines 和 peerDependencies 字段。单个值内的版本升级会高亮显示变更的字符,一眼便能区分 patch 升级和 major 升级。

适合使用 package.json diff 的场景

审查 Renovate 或 Dependabot PR

机器人在一个上午开了十五个 PR,大多数是例行操作,但其中一个悄悄修改了脚本,或收紧了 peerDependency,或升级了 engines 字段导致 CI 镜像失效。PR 标题写着 "chore(deps): bump foo from 4.1.0 to 4.2.1",您习惯性地信任并合并。将前后两个 package.json 粘贴到 diff 中,五秒内即可确认没有其他内容变动。这是 JS 工程师使用清单 diff 最常见的原因。

合并前比较两个分支

您和同事在各自的特性分支上都修改了 package.json。由于编辑位于不同块中,Git 可以干净合并,但干净合并不等于正确合并。将两个分支的清单粘贴到 diff 中,找出某个分支删掉的脚本、某个分支降级的依赖,或两个分支以不同版本添加了同一个包的冲突。这比在 CI 对合并结果运行 npm ci 后才发现问题要便宜得多。

审计 npm install 在 package-lock.json 中的变更

编辑 package.json 只是变更的一半。另一半是 package-lock.json 中记录的已解析依赖树。运行 npm install 后,将旧 lockfile 和新 lockfile 并排粘贴,查看哪些传递依赖被引入。当 caret 范围拉入深层嵌套依赖的新 minor 版本时,意外新增包的情况很常见。对于原始 lockfile 检查,我们的 compare-json 页面能更好地处理较大的文件;本页面最适合用于清单本身。

回归后检查降级情况

某个版本发布后出现 bug,二分查找后怀疑问题在依赖树中某处。将上一个正常版本的 package.json 粘贴到当前版本旁边,在脑海中略过未变更的块,聚焦于高亮的版本范围。修复方法通常是将某个库降级到上一次绿色构建中固定的版本。找到嫌疑对象后,用精确版本(不带 caret 或 tilde)锁定它,直到上游问题解决。

将本地清单与团队成员的清单进行比较

两位工程师,一次棘手的合并,rebase 结束后出现两个不同的 package.json。lockfile 更是一团糟。将两个清单并排粘贴,查看哪些键存在分歧,然后有意识地解决它们,而不是盲目接受 git merge -X theirs 的结果。当新贡献者的 npm install 拉取了与您不同的依赖树,您怀疑存在清单漂移时,这也是正确的工具。

发布库之前预审 package.json

在运行 npm publish 发布库之前,需要关注的清单字段与应用不同:mainmoduletypesexportsfilespeerDependenciesengines。将即将发布的清单与上一次发布的清单进行 diff。丢失的 peerDependencies 条目、变更的 exports 条件或收紧的 engines 范围,可能以 npm 本身无法警告您的方式破坏消费者。Node.js 包文档 是这些字段含义的参考资料。

值得了解的 package.json 字段

真实 package.json diff 中出现的字段及其含义。在批准 Renovate PR 或合并两个都修改了清单的分支之前,值得快速浏览一下。

TopicWhat this tool does
dependencies vs devDependencies vs peerDependenciesdependencies 随您的包一起发布,任何消费者安装时都会安装。devDependencies 只有在项目根目录运行 npm install 时才会安装,下游消费者不会安装。peerDependencies 是您的库期望宿主提供的包(通常是 React、测试框架、打包工具),npm 7+ 会自动安装它们,除非存在冲突。在这些块之间移动包会改变谁承担安装成本。
Caret (^) 与 tilde (~) semver 范围Caret ^1.2.3 允许任何低于 2.0.0 的版本,是 npm 的默认值,也是最宽松的常见范围。Tilde ~1.2.3 只允许 patch 更新,低于 1.3.01.2.x 与 tilde 等效。* 表示任意版本(生产环境不要使用)。latest 在安装时解析,会产生不可重现的构建,应避免使用。
精确锁定(无范围前缀)"react": "18.2.0" 不带 caret 或 tilde,会锁定到精确版本。结合 lockfile,这能提供最可重现的安装,代价是永远不会自动接收安全补丁。有些团队锁定所有依赖;有些则依赖 caret+lockfile 的组合。两者没有绝对的对错之分,权衡在于更确定的构建与更可能过时的依赖之间。
package-lock.json 的确定性package-lock.json 记录了依赖树中每个包(包括传递依赖)的精确解析版本。npm ci 从 lockfile 安装且不允许修改它;npm install 在范围允许更新版本时可能会修改它。CI 环境始终使用 npm ci;开发环境使用 npm install 没问题,只要您提交产生的 lockfile 变更。
monorepo 的 workspaces 字段workspaces 数组告诉 npm 将兄弟目录视为 monorepo 中的链接包。在根目录运行 npm install 会安装所有工作区,并创建一个单一提升的 node_modules 树。Yarn 和 pnpm 支持各自约定的工作区,pnpm 的提升策略更为保守,能在安装时捕获更多依赖泄露问题。
engines 字段engines.node 声明您的包支持的 Node.js 版本。默认情况下,npm 只在宿主违反此条件时发出警告;在 .npmrc 中设置 engine-strict=true 则会将其变为硬错误。升级 engines 字段对仍在使用旧版 Node 的消费者来说是破坏性变更,而这类变更往往隐藏在 Renovate 的 "chore" PR 中。务必仔细阅读 engines diff。
ES module 的 exports 字段exports 字段控制消费者可以从您的包中导入哪些路径,以及哪些条件(importrequiretypesnodebrowser)解析到哪些文件。添加或移除条目对下游代码来说是破坏性变更。Node.js 包文档 详细介绍了解析规则;除非您明确添加新入口点,否则应将任何 exports diff 视为 major 版本级别的编辑。
package.json 内部的字段顺序package.json 中顶层键没有强制顺序。按照惯例,大多数项目以 nameversiondescription 开头,然后是 scripts,再是依赖。在依赖块内部,按字母顺序排列键是事实标准,大多数包管理器在保存时会对块进行排序。显示条目被重新排列但内容完全相同的 diff,通常是工具差异,而非真正的变更。

Package.json diff:常见问题

这与 npm diff 或 npm-check-updates 有什么区别?

npm diff 是 npm 的内置命令,用于比较 registry 上某个包的两个已发布版本(包括 tarball 和源代码)。npm-check-updates(ncu)报告清单中哪些依赖有更新版本可用。两者都不能显示您磁盘上或两个分支中两个任意 package.json 文件之间的差异。本工具做的正是这件事。用 ncu 了解应该升级什么,用 npm diff 查看 registry 端两个版本之间的变更,用本页面在并排视图中阅读您自己的前后清单。

它会进行安全审计或检查已知漏洞吗?

不会。本页面只对文本进行 diff,不查询 npm registry、GitHub Advisory Database 或任何漏洞服务。安全审计请对已安装的依赖树运行 npm audit,使用 npm audit signatures 验证包来源,或依赖 Snyk、Socket 或 Dependabot 警报。本工具适合用于了解清单发生了什么变化,而不适合判断该变化是否安全可发布。

它能检测传递依赖的变更吗?

仅凭清单无法做到。package.json 只列出直接依赖及其请求的版本范围。完整的已解析依赖树(包括传递依赖)存在于 package-lock.json(或 yarn.lockpnpm-lock.yaml)中。要比较已解析的依赖树,请将两个 lockfile 粘贴进行 diff。由于 lockfile 较大,我们的 compare-json 页面比本页面更适合处理它们。对于 pnpm-lock.yaml,请使用 compare-yaml。本页面针对清单本身进行了优化。

如何比较两个 package-lock.json 文件?

像粘贴清单一样将两个 lockfile 粘贴到面板中。工具会将它们解析为 JSON、格式化并进行 diff。请注意,lockfile 可能有数千行,高亮的 diff 可能会很长。先关注顶层 packages 条目,再关注 version 字段。对于超过约五千行的文件,我们的 compare-json 页面更适合,因为它专门处理大型 JSON 内容。

caret (^) 和 tilde (~) 版本范围有什么区别?

两者都是 semver 范围,允许在不手动编辑清单的情况下进行更新。caret ^1.2.3 允许任何不改变最左侧非零数字的版本,即接受 1.2.31.999.999,但不接受 2.0.0。tilde ~1.2.3 更严格:只允许 patch 更新,接受 1.2.31.2.999,但不接受 1.3.0。caret 是 npm 的默认值,范围更宽松;当某个库的 minor 版本有破坏性变更历史时,可使用 tilde。

大型 lockfile 有大小限制吗?

实际上有。diff 在浏览器中运行,因此非常大的输入(例如来自 monorepo 的两万行 lockfile)可能会根据内存情况导致页面变慢或标签页卡顿。对于典型的应用清单和每侧几千行以内的 lockfile,diff 几乎瞬间完成。对于更大的文件,我们的 compare-json 页面是更好的入口。如果您需要频繁比较超大 lockfile,可考虑在本地运行 git diff package-lock.json 并通过分页器查看,这种方式比任何浏览器工具都更具扩展性。

如何准确看出哪些依赖版本发生了变化?

粘贴两个清单并点击格式化,使两侧的键以相同顺序排列。版本升级随后会在同一行显示为红绿配对高亮:左侧划去旧的 ^18.2.0,右侧以绿色显示新的 ^19.0.0。字符级高亮落在值内部,一眼即可区分 patch 升级和 major 升级。^~ 前缀也会高亮,当范围放宽或收紧而数字本身未移动时,这一点很重要。

这与 npm diff 或 GitHub 文件 diff 有什么不同?

本工具比较的是您剪贴板中的两个 package.json 文件,无需克隆仓库,无需调用 registry,不上传任何内容。GitHub 的 diff 需要两个版本都已提交并推送,当您比较本地分支与团队成员的粘贴内容或未推送的进行中工作时,这种方式就不够用了。npm diff 则完全是另一回事:它比较 registry 上两个已发布包的 tarball,而不是磁盘上的两个清单。当两个文件就摆在您面前时,使用本工具即可。

也可以 diff package-lock.json 或 yarn.lock 吗?

可以。两者都只是文本,而 package-lock.json 是 JSON,因此可以像任何清单一样粘贴并进行 diff。它们体积较大,所以在阅读之前先点击格式化以统一缩进。lockfile diff 本质上会有很多噪音,因为单个依赖升级会在数百行中重写已解析的依赖树和哈希值。真正有用的信号是版本号以及 resolvedintegrity 行;略过周围的噪音即可。对于超过几千行的 lockfile,我们的 compare-json 页面更适合处理其大小。

粘贴来自私有或工作仓库的 package.json 安全吗?

安全。diff 完全在您的浏览器中运行,文本不会被上传、记录或发送到任何地方。这一点很重要,因为 package.json 可能泄露的信息超出预期:publishConfig 中的私有 registry URL、内部 scoped 包名(如 @yourcompany/auth)、description 中未发布的产品名称。在大多数工作场所政策下,将这些内容粘贴到服务器端 diff 网站将是真正的数据处理事件。想要验证?打开 DevTools,粘贴时观察 Network 标签,您会看到没有任何出站请求。

这个工具免费吗?需要注册吗?

免费,无需创建账户。没有试用期,没有席位限制,没有邮件门槛。粘贴两个清单,阅读 diff,关闭标签页。每个按钮——格式化、上传、示例——在首次访问时无需登录即可使用。这是一个专用工具,作为免费工具提供,而非付费漏斗,因此没有隐藏在锁后面的功能层。

隐私保护与工作原理

您的清单不会离开浏览器。diff、JSON 解析、高亮和渲染都在您的设备上运行。我们不会上传文本,不会记录,也不会将其发送给任何第三方服务。对于专有代码而言,这一点尤为重要:在云端 diff 服务中粘贴来自未发布库的 package.json 或私有仓库的 lockfile,本身就可能违反雇主的数据处理政策,特别是当清单包含内部 scoped 包、私有 registry 主机或开发中的产品名称时。验证这一点很简单:打开浏览器 DevTools,切换到 Network 标签,粘贴两个清单并观察。比较时没有任何出站请求。同样的隐私模型适用于我们的其他工具,包括 compare-json、用于 pnpm-lock.yaml 的 compare-yaml 以及用于通用代码审查的 git-diff-online。相关规范请参阅 Yarn 配置参考 和 npm package.json 文档