-
前言
pnpm-lock.yarm:我就是童脸狼,表面上单纯天真,实际上圆滑 通透。你不可能算计得了我,因为从一开始你 就被我布局了。我是棋手,而你只是棋子,若 你违逆我,你会知道什么是残酷和黑暗。当我 重临世界之日,诸逆臣皆当死去!
咳咳,言归正传,pnpm-lock.yarn差不多就是这样,看样子不起眼,其实这是一个不可忽视的文件,也是一个非常巧妙的设计,笔者也是最近在学习工程化,注意到了这个文件。
pnpm-lock-yarm是什么?
yarm文件
判断一个男人什么档次,就看他开什么车,开玛莎拉蒂一般是总裁,开红旗一般是当官的,像笔者这样开单车的一般是穷B。。。判断一个文件干什么的,先看后缀。
YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,通常用于配置文件、数据交换等场景。YAML 文件(通常使用
.yaml或.yml扩展名)是一种用于表示结构化数据的文本文件,它非常适合配置文件、数据存储以及与程序之间的数据交换。YAML 文件基本语法
-
键值对:YAML 使用键值对来表示数据。键和值之间用冒号
:隔开。name: "John" age: 30 -
嵌套结构:YAML 使用 缩进 来表示数据的层级关系,通常使用 2 个空格来缩进。注意,YAML 不允许使用制表符(Tab),必须使用空格来缩进。
person: name: "John" age: 30 address: street: "123 Main St" city: "New York" -
列表:列表(数组)使用连字符
-来表示,每个元素占一行,缩进表示元素属于同一个列表。fruits: - Apple - Banana - Orange -
注释:YAML 中的注释以
#开头,注释内容不会被解析。# This is a comment name: "John" # Inline comment -
字符串和数字:YAML 中的字符串可以不用加引号,但如果字符串中有特殊字符(如空格),则需要加引号。数字直接写就可以,YAML 会自动解析为整数或浮动类型。
string: "Hello, World" age: 30 height: 5.9 -
多行字符串:YAML 支持多行字符串,使用
|或>来表示不同的格式:|:保留换行符。>:将换行符转换为空格,适合长文本。
description: | This is a multi-line string. It preserves the newlines. summary: > This is a multi-line string. But newlines are replaced by spaces.
pnpm-lock-yarm的作用
pnpm-lock.yaml文件是 pnpm 包管理工具生成的一个 锁定文件,它在项目中起着重要的作用,类似于package-lock.json(在 npm 中)和yarn.lock(在 Yarn 中)。它的作用是确保所有开发者、CI/CD 环境和生产环境中安装的依赖版本一致,从而避免不同开发环境中的依赖版本差异导致的问题。pnpm-lock.yaml文件是 pnpm 包管理工具生成的一个 锁定文件,它在项目中起着重要的作用,类似于package-lock.json(在 npm 中)和yarn.lock(在 Yarn 中)。它的作用是确保所有开发者、CI/CD 环境和生产环境中安装的依赖版本一致,从而避免不同开发环境中的依赖版本差异导致的问题。1. 锁定依赖版本
pnpm-lock.yaml文件的最主要作用是 锁定依赖的具体版本。在你的package.json中,依赖通常是通过 版本范围(如^1.0.0、~1.0.0)来指定的,这意味着包管理工具(如 pnpm)会选择符合该版本范围的 最新版本。但是,由于这个版本范围可能会随着时间的推移而变化,为了确保团队中的每个成员、CI/CD 和生产环境中的依赖版本保持一致,pnpm-lock.yaml文件会记录下 实际安装的每个依赖的具体版本。示例:
假设
package.json中的某个依赖指定为lodash: "~4.17.0"。运行pnpm install后,pnpm 会选择一个符合这个版本范围的最新版本(比如4.17.21)。然后,这个具体版本会被锁定在pnpm-lock.yaml中,确保后续所有人安装的都是4.17.21而非4.18.0或其他版本。lodash@^4.17.0: version: 4.17.21 resolution: "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity: sha512-xyz... engines: node: ">=0.10.0"2. 确保依赖一致性
pnpm-lock.yaml文件确保了 跨开发环境的依赖一致性。假设团队中的开发者 A 和 B 都在使用相同的package.json,但是他们的本地node_modules中的依赖版本不同(可能是因为不同的安装时间或者网络问题),那么pnpm-lock.yaml就可以保证在每个开发者机器上都安装完全相同版本的依赖。这样做避免了 “它在我机器上可以正常工作,但在其他机器上不行” 这样的情况。- 当开发者 A 执行
pnpm install时,pnpm 会参考pnpm-lock.yaml文件来安装所有依赖,并锁定为具体版本。 - 当开发者 B 执行
pnpm install时,pnpm 会自动按照pnpm-lock.yaml中记录的具体版本来安装依赖。
3. 加速安装过程
pnpm-lock.yaml使得依赖安装过程更加 高效。因为pnpm可以直接读取锁文件中记录的依赖树结构和版本信息,避免了每次都需要重新解析和计算依赖的版本。这样可以显著提升安装速度,尤其是在大项目中。同时,
pnpm-lock.yaml还可以缓存和复用已经安装的依赖(尤其是在 CI/CD 环境中),进一步提高安装效率。4. 管理嵌套依赖(子依赖)
pnpm-lock.yaml还负责记录项目中所有 直接依赖 和 间接依赖(子依赖、嵌套依赖)的具体版本信息。例如,如果你安装了lodash,而lodash本身又依赖了其他包,pnpm-lock.yaml会记录所有的依赖层级及其具体版本。场景:
- 安装
lodash: 你在项目中运行了命令pnpm add lodash,这会将lodash安装为你的直接依赖。 lodash的子依赖:lodash本身依赖其他包,如lodash.merge,可能会有多个版本或不同的包版本需求。- 生成的
pnpm-lock.yaml:pnpm-lock.yaml会记录这些信息。它不仅会记录你直接安装的lodash的具体版本,还会记录lodash.merge的具体版本及其任何其他子依赖。
示例:
假设
lodash版本是4.17.21,而它依赖lodash.merge版本是4.6.0,在pnpm-lock.yaml中可能会看到类似这样的内容:dependencies: lodash: 4.17.21 lodash.merge: 4.6.0 lockfileVersion: 5 packages: /lodash/4.17.21: resolution: "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" dev: false dependencies: lodash.merge: 4.6.0 /lodash.merge/4.6.0: resolution: "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz" dev: false 这样确保了项目中的每个子依赖也是固定版本,避免了不同开发者机器上依赖版本不一致的问题。
5. 支持树形结构和多版本依赖
由于
pnpm使用一种独特的 符号链接结构(而非像 npm 那样将所有依赖复制到node_modules),pnpm-lock.yaml也需要记录 多版本依赖 的情况。例如,如果两个直接依赖都依赖于不同版本的某个库,pnpm-lock.yaml会确保这两个版本能够并存,并且能够正确地安装到不同的文件夹中。lodash@4.17.21: dependencies: lodash@4.17.21: version: 4.17.216. CI/CD 环境的一致性
在 CI/CD 流程中,
pnpm-lock.yaml文件确保了你在本地开发时安装的依赖版本与在生产环境或 CI/CD 环境中安装的版本完全一致。即使在不同的机器和不同的时间运行pnpm install,只要pnpm-lock.yaml保持不变,依赖版本就能保持一致。与package.json的关系?
聊pnpm-lock.yaml文件,就绕不开package.json,就像通辽不能失去耶路撒冷一样
package.json是什么?
package.json是 Node.js 项目的一个核心文件,用于管理项目的元数据(如项目名称、版本、描述等),以及项目所需的依赖、脚本命令、配置等。它通常位于 Node.js 项目的根目录下。以下是
package.json文件中的一些常见字段:1. name
- 项目名称。通常是一个小写字母的字符串,多个单词可以用连字符
-隔开。 - 示例:
"name": "my-project"
2. version
- 项目的版本号,遵循 Semantic Versioning (语义化版本) 规范。
- 示例:
"version": "1.0.0"
3. description
- 对项目的简短描述,通常是一个字符串。
- 示例:
"description": "A simple Node.js application"
4. main
- 指定项目的入口文件,通常是一个 JavaScript 文件,告诉 Node.js 从哪个文件开始执行。
- 示例:
"main": "index.js"
5. scripts
-
定义可通过命令行运行的脚本命令。常用的有
start,test,build等。 -
示例:
"scripts": { "start": "node index.js", "test": "mocha" }
6. dependencies
-
项目运行时所依赖的包。这里列出的包会在执行
npm install时自动安装。 -
示例:
"dependencies": { "express": "^4.17.1" }
7. devDependencies
-
开发时所依赖的包,通常是构建工具、测试框架等,项目在生产环境中不需要这些包。
-
示例:
"devDependencies": { "webpack": "^5.0.0", "babel": "^7.0.0" }
8. engines
-
指定项目支持的 Node.js 版本,确保开发者使用的 Node.js 版本与项目兼容。
-
示例:
"engines": { "node": ">=14.0.0" }
9. author
- 项目的作者信息。
- 示例:
"author": "Jane Doe <jane@example.com>"
10. license
- 项目的许可证信息,表明项目的版权和使用条款。
- 示例:
"license": "MIT"
示例
package.json{ "name": "my-project", "version": "1.0.0", "description": "A simple Node.js application", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo "Error: no test specified" && exit 1" }, "dependencies": { "express": "^4.17.1" }, "devDependencies": { "webpack": "^5.0.0" }, "author": "Jane Doe", "license": "MIT" }与pnpm.lock.yaml的联系?
看到这里,有些朋友可能就会疑惑了,为什么package指定依赖版本范围,pnpm.lock指定特定版本?为什么不能package直接指定依赖版本?这不是脱裤子放屁?别急,听我解释完他们工作的原理,你就清楚了
首先,package指定一个特定的范围,然后pnpm根据这个范围和内部算法,找到一个最适合你这个项目的版本,例如:a项目中,package里声明这么个依赖:
"express": "~4.17.1"意思是范围在4.17.随意,可以是4.17.3,也可以是4.17.6,而pnpm内部有一个算法,计算出指定范围内,4.17.1最适合(这个版本对你的项目兼容性最好,冲突最少,支持的功能最全),就在pnpm-lock锁定版本4.17.1,然后不管什么人把项目从远程拉过来,pnpm install,都是下载4.17.1版本的express,减少了冲突如果没有pnpm.lock.yaml
在前面提到,pnpm内部有算法,会算出范围内最合适的版本,如果没有pnpm-lock,可能会因为环境(开发者的node版本,时间区别)导致pnpm内部算法算出来不同最兼容的版本
场景:
一个项目依赖express,小A的node版本是16.XX,而小B的node版本是17.XX,pnpm install时,小A项目中pnpm根据内部算法自动下载了4.17.3版本的express,开发完后往远程push,小B把代码拉取下来,执行pnpm install,因为环境不同,pnpm算法自动下载了4.17.1版本的express,版本不同,这时候就非常容易出现版本冲突,导致小B的代码不能正常执行,假如有pnpm-lock.yaml文件,既省去了pnpm内部第二次计算最兼容版本的时间,还不会出现不同开发者依赖不一致的情况。
总结
pnpm.lock.yaml实际上是对package 里的依赖版本 起到了补充的作用,减少了冲突发生的概率
-