0043. 认识 package-lock.json
- 1. 🔗 npm docs package-lock.json
- 2. 📒 概述
- 3. 📒 理解
package-lock.json
的必要性 - 4. 📒
package-lock.json
文件结构 - 5. 📒
package-lock.json
会自动生成和更新 - 6. 📒 注意事项
1. 🔗 npm docs package-lock.json
- https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json
- 这是 npm 的官方对
package-lock.json
文件的说明。
2. 📒 概述
package-lock.json
是 npm 自动生成的文件,主要作用是 锁定依赖的具体版本,确保在不同环境中安装的依赖完全一致,避免因版本不一致导致的问题。- 在 npm5 以上的版本中,引入了
package-lock.json
文件,该文件旨在跟踪被安装的每个软件包的确切版本,以便产品可以以相同的方式被 100% 复制(即使软件包的维护者更新了软件包)。 - 当运行
npm install
时,package-lock.json
会被更新以记录当前安装的依赖版本。 package-lock.json
的核心作用:- 锁定依赖的具体版本:明确记录每个依赖及其子依赖的确切版本号。
- 生成一致的依赖树:无论在哪台机器上运行
npm install
,都会生成相同的依赖结构。 - 提高安装效率:通过缓存和锁定版本,减少重复下载和解析依赖的时间。
- 在开发过程中通常无需关注
package-lock.json
的内容,但在以下场景中查看会有所帮助:- 排查依赖版本问题。
- 优化依赖结构。
- 进行安全审计。
- 使用工具(如
npm audit
)检查依赖的安全性时,package-lock.json
提供了所有依赖的完整列表和版本信息。 - 通过查看文件内容,可以快速定位存在安全漏洞的依赖及其具体版本。
- 使用工具(如
- 最佳实践:
- 始终将
package-lock.json
提交到版本控制系统中。 - 避免手动修改
package-lock.json
,通过npm install
或npm update
更新依赖。 - 定期清理无用依赖,并使用工具(如
npm audit
)检查依赖版本的安全性。
- 始终将
3. 📒 理解 package-lock.json
的必要性
package-lock.json
文件的出现解决了package.json
一直存在的特殊问题,在package.json
中,可以使用 semver(语义化版本)表示法设置要升级到的版本(补丁版本或次版本)。- 在 Node.js 项目中,依赖管理是通过
package.json
文件完成的。然而,package.json
中的依赖版本通常使用语义化版本范围(如^1.2.3
或~1.2.3
),这会导致在不同环境中安装的依赖版本可能不同。例如:- 开发者 A 安装了
1.2.5
。 - 开发者 B 安装了
1.2.8
。 - 部署到生产环境时安装了
1.2.10
。
- 开发者 A 安装了
- 这种差异可能导致 —— 行为表现不一致 的问题。
- 开发环境与生产环境不一致:某些功能在开发环境中正常,但在生产环境中出现问题。
- 团队协作问题:团队成员之间使用的依赖版本不同,导致代码行为不一致。
- 为了解决这些问题,npm 引入了
package-lock.json
文件,确保在不同环境中安装的依赖完全一致,避免因版本不一致导致的问题。
🤔 如果直接将整个 node_modules
推送到仓库中,那是不是就没必要用 package-lock.json
了呢?
- 直接推送
node_modules
是行不通的。 - 即使直接提交
node_modules
在某些情况下,可以解决依赖一致性问题,但由于其体积庞大、缺乏灵活性、难以维护等问题,因此可以认为这种做法是不可行的。node_modules
文件夹体积庞大node_modules
文件夹通常包含大量文件和子依赖,大小可能达到数百 MB 或更多。- 推送到代码仓库会导致仓库体积迅速膨胀。
- 拉取代码时耗时增加,尤其对大型项目或分布式团队不友好。
- 增加存储成本(如 GitLab、GitHub 等平台对存储空间有限制)。
- 缺乏灵活性
- 不同操作系统(如 Windows、macOS、Linux)可能对某些依赖有特定的编译需求。
- 某些依赖需要根据目标环境动态生成二进制文件(如
node-gyp
编译的模块)。 - 比如你在 Windows 环境下直推送了
node_modules
,但是在你同事的 macOS 设备上拉下来是没法正常工作的。
- 难以维护
- 当依赖更新时,开发者需要手动删除旧的
node_modules
文件夹并重新安装依赖,再提交到仓库。 - 团队成员频繁更新依赖会引发大量冲突和冗余提交。
- 当依赖更新时,开发者需要手动删除旧的
package-lock.json
的优势- 记录依赖树的完整信息,包括每个依赖的具体版本号、下载地址和校验值(
integrity
字段)。 - 能够在不同环境中精确还原依赖树,无需提交庞大的
node_modules
文件夹。 - 开发者只需运行
npm install
,即可根据锁定的版本信息自动安装一致的依赖。
- 记录依赖树的完整信息,包括每个依赖的具体版本号、下载地址和校验值(
- 最佳实践
- 不要提交
node_modules
,将其添加到.gitignore
文件中。 - 始终提交
package-lock.json
,确保依赖一致性。 - 使用 CI/CD 工具,通过
npm ci
命令(基于package-lock.json
快速安装依赖)确保生产环境与开发环境一致。
- 不要提交
- 使用
package-lock.json
文件结合.gitignore
忽略node_modules
是更高效、更灵活的最佳实践。
4. 📒 package-lock.json
文件结构
package-lock.json
是一个 JSON 格式的文件,其内容通常包括两个主要部分:- 顶层字段
- 依赖信息
json
{
"name": "example-project",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {},
"dependencies": {}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
name
和version
:项目名称和版本号,与package.json
中的一致。lockfileVersion
:锁定文件的版本号,用于标识package-lock.json
文件的格式。目前常见的值及其含义如下:1
:旧版格式,默认用于 npm v5 和 v6。主要记录依赖树的层级结构,依赖解析效率较低。2
:新版格式,默认用于 npm v7 和 v8。引入了packages
字段,提供更完整的依赖树信息,显著提升了依赖解析效率。3
:最新格式,默认用于 npm v9 及以上版本。进一步优化性能,特别是支持隐藏锁文件(node_modules/.package-lock.json
),并包含更多元数据以支持复杂场景。
requires
:指示是否需要解析依赖关系。packages
:记录所有依赖及其子依赖的具体信息(npm v7 及以上引入)。dependencies
:记录依赖树的层级结构(npm v6 及以下使用)。
建议团队使用的 npm 版本一致
- 虽说
lockfileVersion: 3
向后兼容lockfileVersion: 2
,但建议团队成员统一使用相同版本的 npm,以避免因格式差异导致的问题。
json
"node_modules/vitepress": {
"version": "1.6.3",
"resolved": "https://registry.npmmirror.com/vitepress/-/vitepress-1.6.3.tgz",
"integrity": "sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@docsearch/css": "3.8.2",
"@docsearch/js": "3.8.2",
"@iconify-json/simple-icons": "^1.2.21",
"@shikijs/core": "^2.1.0",
"@shikijs/transformers": "^2.1.0",
"@shikijs/types": "^2.1.0",
"@types/markdown-it": "^14.1.2",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/devtools-api": "^7.7.0",
"@vue/shared": "^3.5.13",
"@vueuse/core": "^12.4.0",
"@vueuse/integrations": "^12.4.0",
"focus-trap": "^7.6.4",
"mark.js": "8.11.1",
"minisearch": "^7.1.1",
"shiki": "^2.1.0",
"vite": "^5.4.14",
"vue": "^3.5.13"
},
"bin": {
"vitepress": "bin/vitepress.js"
},
"peerDependencies": {
"markdown-it-mathjax3": "^4",
"postcss": "^8"
},
"peerDependenciesMeta": {
"markdown-it-mathjax3": {
"optional": true
},
"postcss": {
"optional": true
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
version
:依赖的具体版本号。resolved
:依赖的下载地址(通常是 npm 的 CDN 地址)。integrity
:依赖的完整性校验值(通常是 SHA-512 哈希值),用于确保依赖未被篡改。dependencies
:该依赖的子依赖及其版本信息。dev
:布尔值,表示该依赖是否为开发环境依赖。如果为true
,则该依赖仅在开发环境中使用,不会被打包到生产环境中。license
:该依赖的许可证类型(如MIT
、Apache-2.0
等),用于声明该包的法律使用许可。bin
:定义该依赖提供的可执行文件及其路径。例如,"vitepress": "bin/vitepress.js"
表示可以通过命令行运行vitepress
来调用bin/vitepress.js
文件。peerDependencies
:同行依赖,列出当前包需要的宿主环境依赖。这些依赖通常由宿主项目提供,而不是由当前包直接安装。例如,markdown-it-mathjax3
和postcss
是 VitePress 需要的同行依赖。peerDependenciesMeta
:对peerDependencies
的元信息补充说明。例如:- 如果某个同行依赖是可选的,则会在
peerDependenciesMeta
中标记为"optional": true
。 - 在示例中,
markdown-it-mathjax3
和postcss
被标记为可选依赖,这意味着即使宿主项目没有安装这些依赖,VitePress 也可以正常工作。
- 如果某个同行依赖是可选的,则会在
- 通过这些字段,
package-lock.json
提供了关于依赖的全面信息,包括其来源、版本、许可证、可执行文件以及与其他包的关系等。这些信息不仅有助于确保依赖的一致性,还为开发者提供了清晰的依赖管理视图。 - 补充说明:
- 依赖信息是
packages
或dependencies
字段中的内容,具体是啥,得看你的 npm 版本。
- 依赖信息是
5. 📒 package-lock.json
会自动生成和更新
- 生成:当你运行
npm install
时,如果项目中没有package-lock.json
文件,npm 会自动生成它。 - 更新:当添加、删除或更新依赖时,
package-lock.json
会自动更新以反映最新的依赖树。例如:
bash
npm install express
npm uninstall lodash
npm update axios
1
2
3
2
3
- 清理和重置:如果
package-lock.json
出现冲突或损坏,可以通过以下命令重新生成:
bash
rm package-lock.json
npm install
1
2
2
6. 📒 注意事项
- 提交到版本控制系统
- 建议将
package-lock.json
提交到 Git 等版本控制系统中,以便团队成员和 CI/CD 环境能够复现相同的依赖树。 - 如果不提交,可能会导致团队成员安装的依赖版本不一致。
- 如果你的项目是使用 Git 作为版本管理工具,你要做的事儿很简单,不要在
.gitignore
文件添加package-lock.json
忽略项即可。
- 建议将