大家好,我是 ConardLi。
10.23
日,Yarn
团队经过一年多的努力,中间经过了 53
个候选版本,终于发布了 Yarn 4.x
的稳定发行版本。
Breaking Change 速览
如果你现在使用的是 3.x
,下面这几点是需要了解的:
- 目前要求
Node.js 18
版本; - 默认情况下,使用
yarn init
创建的新项目将不再启用Zero-Install
; - 使用
yarn init
创建的新项目将使用Corepack
而不是yarnPath
; - 现在默认包含所有官方插件(
typecript、interactive-tools
...)。 yarn workspaces foreach
命令语法略有改动
Corepack
自从 Yarn 2.0
版本以来,官方的建议是使用 yarnPath
设置来在每个项目中安装 Yarn
(可以通过 yarn init -2
或 yarn set version
自动设置)。
另外,过去还建议使用 yarnPath
设置指向一个已签入的二进制文件,但这种模式增加了一些不必要的麻烦,许多人不喜欢将二进制文件添加到他们的代码库中,即使很小。
为此,Yarn
与 Node.js
合作开发了一个名为 Corepack
的项目。
Corepack
是随 Node.js 16
一起提供的工具,它会根据你正在处理的项目自动选择正确的包管理器版本。
现在,Corepack
已经随着 Node 18
和 20
一同发布,Yarn
不再依赖 yarnPath
。yarn init -2
和 yarn set version
命令也已经更新,以便在可能的情况下更新 packageManager
字段。
Corepack
通过package.json
中的标准packageManager
字段可以知道要使用哪个包管理器版本。这个字段通常是通过yarn init -2、yarn set version x.y.z
或更通用的corepack use yarn@x.y.z
来设置的。
Hardened Mode
Yarn
新增了一个模式(Hardened Mode
)来试图保护用户免受一些常见的攻击。
在此模式下运行时,Yarn
将执行两个额外的验证:
- 验证
lock
文件中 存储的解析规则是否与范围所能解析到的版本一致。
当我们在项目中定义了依赖项的范围(例如使用 "^" 或 "~" 等符号指定的版本范围),
Yarn
会根据这些范围来解析并选择合适的版本安装到项目中。但是,有时在解析依赖项时可能会出现问题,例如范围可能无法解析到满足所有依赖项的兼容版本,或者范围太宽松导致安装了过多的依赖项。
- 验证
lock
文件中存储的 npm 包元metadata
是否与远程注册表中的metadata
一致。
这些操作其实就是用来防止某些攻击者可能使用 Yarn
对我们的项目进行 PR
时暗中修改我们的 lock
文件。
我们可以通过
enableHardenedMode
来主动启用Hardened Mode
,但当Yarn
检测到它在公共存储库上的GitHub Pull Request
中运行时,它也会自动启用。可以通过在yarnrc
文件中显式关闭enableHardenedMode
来禁用此功能。
另外,在 Hardened Mode
约束下运行的安装会比平常慢得多,因为它们需要执行许多额外的网络请求,所以不建议默认启用它。
如果需要在特定的 CI Job
中需要启用它,可以通过环境变量将其打开:
export YARN_ENABLE_HARDENED_MODE=1
新的约束引擎
Yarn
是目前唯一实现约束引擎的包管理器,这个功能可让我们定义项目必须满足的一组规则。
假设我们的项目中有两个工作区(Workspaces
):A 和 B,并且它们都依赖于同一个包,比如 "lodash"
。
在以前的版本中,如果工作区 A
依赖于 "lodash@^3.0.0"
,而工作区 B 依赖于 "lodash@^4.0.0"
,Yarn
会允许这种情况,并在安装依赖时分别安装 "lodash@^3.0.0"
和 "lodash@^4.0.0"
。
然而,有时这样的情况会导致冲突和问题。为了解决这个问题,Yarn
引入了 JavaScript
约束引擎。
使用 JavaScript
约束引擎,我们可以定义一些规则来限制工作区之间依赖项的版本关系。例如,可以定义一个规则,要求所有工作区都必须使用相同的 "lodash"
版本。
Yarn
的约束引擎过去由 Tau-Prolog
(一种 JavaScript Prolog
实现)提供支持。与 JavaScript
等命令式语言不同,Prolog
使用一种称为逻辑编程的不同模型 - 如果规则为真,则定义某个事物存在。这是一个非常有趣的模式,与基于规则的 linting
概念很好地结合在一起。但不幸的是,Prolog
被证明使用起来非常复杂,增加了约束的学习曲线,超出了大家可以接受的阈值。
因此,从 Yarn 4
开始,Prolog
约束已被弃用,并且已被基于 JavaScript
的全新引擎所取代,并具有可选的 TypeScript
支持!
比如下面这个简单的例子,yarn.config.cjs
将强制所有 react
依赖项设置为 18.0.0
。
module.exports = {
async constraints({Yarn}) {
for (const dep of Yarn.dependencies({ ident: 'react' })) {
dep.update(`18.0.0`);
}
},
};
下面的约束会强制在所有工作区中正确设置 engines.node
字段:
module.exports = {
async constraints({Yarn}) {
for (const workspace of Yarn.workspaces()) {
workspace.set('engines.node', `20.0.0`);
}
},
};
优化命令行界面
为了更好地传达信息,CLI
界面的的多个部分得到了改进。例如,yarn install
现在会告诉我们添加了哪些新的软件包,以及它们的总重量。另外,它不会再像以前那样打印与同级依赖关系相关的警告,现在只在可操作的情况下打印警告:
另一个例子是 yarn config
命令,它会显示一个新的树形显示,现在还接受任意数量的设置作为位置参数,让我们选择您希望看到的内容:
性能
4.0
在安装速度上明显快于 3.6
。例如,以下是从缓存安装 Gatsby
及其约 350MB
依赖关系树的时间差。性能提高了 3
倍,这是由于新的包元数据缓存显着提高了重复安装的性能:
hyperfine -L v stable,canary --prepare 'rm -rf ~/.yarn/berry/cache' 'cd $(mktemp -d) && yarn init -2 && yarn set version {v} && yarn && yarn add gatsby --mode=skip-build'
目前 Yarn
大多数情况下基本上和 pnpm
的性能接近了。
新的官网
另外,Yarn 的官网也迎来了全新的改版,包括新的命令、配置文档等。
最后
参考:
- https://yarnpkg.com/
- https://yarnpkg.com/getting-started
- https://yarnpkg.com/blog/release/4.0