package.json 差异比较
开发工具
正在载入
正在加载工具
工具代码会在打开时按需载入,请稍候。
本工具的全部运算都发生在你的浏览器中,输入内容不会发送到任何服务器。
关于这个工具
将两份 package.json 作为结构化声明进行比较。工具按包名汇总 dependencies、devDependencies、optionalDependencies 和 peerDependencies,再单独列出 scripts、engines 及其他顶层元数据。每项变化都保留前后值,并标为新增、删除、修改或移动,方便审核清单编辑。工具不启动包管理器、不执行脚本文本;解析和比较都在当前浏览器页面内完成。
常见用途
- 审核合并请求中构建工具从开发依赖移到运行依赖,同时修改版本范围的变更。
- 提交前检查构建或测试脚本、Node.js 运行环境声明、packageManager、overrides 和包入口元数据。
- 按类别筛选当前审核的内容,同时生成包含全部声明变化、输出顺序确定的 JSON 摘要。
使用方法
- 1.粘贴变更前后的 package.json,或载入示例。两侧都必须是严格 JSON 对象;不接受注释、尾逗号或解码后重复的键。
- 2.点击比较,检查统计及前后值,再按变化类型或字段类别筛选。较大结果每页显示 100 项;标为移动的依赖也可能同时修改了声明字符串。
- 3.复制或下载完整 JSON 前阅读秘密信息提示。筛选不会移除导出行;修改任一输入或切换界面语言会清除旧结果。
可复现的清单比较示例
格式与普通键顺序
{
"before": "{\n \"config\": {\n \"b\": 2,\n \"a\": 1\n },\n \"dependencies\": {\n \"beta\": \"2.0.0\",\n \"alpha\": \"1.0.0\"\n }\n}",
"after": "{\n \"dependencies\": {\n \"alpha\": \"1.0.0\",\n \"beta\": \"2.0.0\"\n },\n \"config\": {\n \"a\": 1,\n \"b\": 2\n }\n}"
}{
"error": null,
"counts": {
"added": 0,
"removed": 0,
"changed": 0,
"moved": 0
}
}两份清单的声明相同。调整普通键顺序不会产生变化;这里的输出展示错误和计数摘要。
新增、删除和修改依赖
{
"before": "{\n \"dependencies\": {\n \"demo\": \"^1.0.0\"\n },\n \"devDependencies\": {\n \"old\": \"1.0.0\"\n }\n}",
"after": "{\n \"dependencies\": {\n \"demo\": \"^2.0.0\"\n },\n \"optionalDependencies\": {\n \"extra\": \"~1.2.0\"\n }\n}"
}{
"error": null,
"counts": {
"added": 1,
"removed": 1,
"changed": 1,
"moved": 0
}
}新增 extra,删除 old,demo 的 SemVer 范围字面文本改变。仅比较声明,不推断已安装版本。
移动与声明修改同时发生
{
"before": "{\n \"devDependencies\": {\n \"demo\": \"^1.0.0\"\n }\n}",
"after": "{\n \"dependencies\": {\n \"demo\": \"^2.0.0\"\n }\n}"
}{
"error": null,
"counts": {
"added": 0,
"removed": 0,
"changed": 0,
"moved": 1
}
}demo 仍存在,但从 devDependencies 移到 dependencies,且范围改变。只计一项移动,完整报告保留两侧分区映射。
脚本、运行环境与包管理器
{
"before": "{\n \"scripts\": {\n \"build\": \"vite build\"\n },\n \"engines\": {\n \"node\": \">=20\"\n },\n \"packageManager\": \"npm@10.8.0\"\n}",
"after": "{\n \"scripts\": {\n \"build\": \"tsc && vite build\",\n \"test\": \"node --test\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"npm@11.0.0\"\n}"
}{
"error": null,
"counts": {
"added": 1,
"removed": 0,
"changed": 3,
"moved": 0
}
}新增 test 脚本,build 命令、Node.js 运行环境声明和 packageManager 值分别修改,不执行任何命令。
条件键优先级与数组顺序
{
"before": "{\n \"exports\": {\n \".\": {\n \"import\": \"./a.js\",\n \"default\": \"./b.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ]\n}",
"after": "{\n \"exports\": {\n \".\": {\n \"default\": \"./b.js\",\n \"import\": \"./a.js\"\n }\n },\n \"files\": [\n \"README.md\",\n \"dist\"\n ]\n}"
}{
"error": null,
"counts": {
"added": 0,
"removed": 0,
"changed": 2,
"moved": 0
}
}exports 条件顺序和 files 数组顺序改变,计两项元数据修改。这种保守的结构比较不判断实际运行行为是否改变。
非仓库及别名声明
{
"before": "{\n \"dependencies\": {\n \"demo\": \"^1.0.0\"\n }\n}",
"after": "{\n \"dependencies\": {\n \"demo\": \"file:../demo\",\n \"alias\": \"npm:demo@^2.0.0\",\n \"local\": \"workspace:*\",\n \"source\": \"github:example/demo#main\"\n }\n}"
}{
"error": null,
"counts": {
"added": 3,
"removed": 0,
"changed": 1,
"moved": 0
}
}新增别名、工作区和 Git 项;demo 改成本地文件声明。语法标签不会触发下载、文件系统读取或包解析。
拒绝解码后重复的键
{
"before": "{\"name\":\"demo\",\"na\\u006de\":\"other\"}",
"after": "{}"
}{
"error": {
"side": "before",
"code": "duplicateKey"
},
"counts": {
"added": 0,
"removed": 0,
"changed": 0,
"moved": 0
}
}name 与 na\u006de 解码为同一个键。比较在变更前输入处停止,不使用被覆盖的值或局部结果。
清单审核的常见误区
- 粘贴锁文件、JavaScript 对象、带 JSONC 注释或尾逗号的内容,而非严格 package.json JSON。
- 把声明分类或范围修改理解为实际安装版本、升级建议或安全结论。
- 把移动数当作分区编辑次数:它按受影响的包名计数,每个包只计一次。
- 以为筛选显示能脱敏或排除导出的变化;完整报告仍保留原始值,包括秘密信息。
- 忽略 exports/imports 的条件顺序,或误以为差异中展示的脚本已被执行。
限制与说明
- 这是有边界的声明比较,不是 npm schema 校验器、依赖解析器或已安装版本比较。不读取锁文件、不获取包、不查询注册表、不执行脚本,也不判断兼容性、漏洞或升级降级。含义相同但写法不同的版本范围仍可能显示为修改。
- 每侧最多 262,144 个 UTF-8 字节、32 层深度和 20,000 个 JSON 值。拒绝任意层级的重复键、无效 JSON、非对象根值、非有限数字、不安全整数及无法保持十进制值往返转换的数字。依赖分区、scripts 和 engines 的值必须是字符串;出现时 name、version、packageManager 必须为字符串,overrides 必须为对象。任何错误都会停止比较,不返回局部差异。
- 依赖按四个支持的分区汇总。包名仅存在一侧时为新增或删除;存在于两侧但所属分区改变时只计一项移动,即使声明字符串同时变化,或包仍留在其他分区。分区相同但字面值不同为修改。空的依赖、脚本、运行环境分区等同于缺失分区;overrides 和 peerDependenciesMeta 作为元数据比较,不展开成已解析依赖。
- 忽略普通对象键顺序和 JSON 格式,保留字符串内容与数组顺序。exports 和 imports 内所有嵌套对象的键顺序都会保留,因为条件优先级可能受影响。其他元数据按顶层字段比较;嵌套编辑展示整个字段的结构化前后值。声明类型仅用于提示,包括未知语法,不校验或解析包目标。 exports/imports 内任意层级的整数索引对象键都会被拒绝,避免 JavaScript 自动换序而掩盖条件顺序的变化。
- 本工具不上传或持久保存输入。JSON 导出原样保留变化字段的值,包括私有 URL、脚本命令和秘密信息,不做脱敏。无论筛选条件或当前页如何,都导出全部变化。报告被复制、保存或分享后,不再由页面控制。
常见问题
依赖修改是否表示已经升级?
不是。工具只比较声明文本。^1.0.0 变成 ~1.5.0、latest 变成 next,或仓库范围变成本地路径,都不能确定实际安装版本。锁文件与包管理器解析不在本工具的比较范围内。
移动依赖与删除后新增有什么不同?
同一包名会跨四个依赖分区合并查看。两侧都存在但所属分区改变时只标一项移动。两侧分区映射同时显示声明变化;一个包存在于多个分区时,不会悄悄合并为单一值。
为什么只调整 JSON 顺序有时也会出现差异?
忽略格式和普通对象键顺序,但数组保持顺序,exports/imports 内嵌套对象也保持键顺序,因为条件匹配优先级可能依赖它。因此即使值不变,条件换序也会显示。
是否支持 workspace、别名、Git 和本地路径?
这些声明保留为字面字符串,并标注为工作区、npm 别名、Git 或本地文件路径;精确版本、SemVer 范围、URL、发布标签及未知语法也会分类。工具不访问、不执行、不解析任何目标,分类不代表有效性或安全保证。