约束
此页面记录了新的基于 JavaScript 的约束。基于 Prolog 的旧约束仍然受支持,但应视为已弃用。其文档可以在 此处 找到。
概述
约束是对一个非常基本需求的解决方案:您有很多 工作区,并且需要确保它们使用其依赖项的相同版本。或者它们不依赖于特定软件包。或者它们使用特定类型的依赖项。无论确切的逻辑是什么,您的目标都是相同的:您希望自动对所有工作区强制执行某种规则。这正是约束的用途。
我们可以强制执行什么?
我们的约束引擎目前支持两个主要目标
- 工作区依赖项
- 任意 package.json 字段
它目前不支持以下内容,但未来可能会支持(欢迎提交 PR!)
- 传递依赖项
- 项目结构
创建约束
通过在项目的根目录(存储库)中添加一个 yarn.config.cjs
文件来创建约束。此文件应导出一个带有 constraints
方法的对象。此方法将由约束引擎调用,并且必须使用提供的 API 定义要对项目强制执行的规则。
例如,以下 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`);
}
},
};
声明式模型
尽可能使用声明式模型定义约束:声明预期状态应是什么,Yarn 检查它是否与现实相符。如果不符,Yarn 将抛出一个错误(在不带参数调用 yarn constraints
时),或尝试自动修复问题(在调用 yarn constraints --fix
时)。
由于采用此声明式模型,您无需自己检查实际值。例如,此处的 if
条件是多余的,应将其删除
module.exports = {
async constraints({Yarn}) {
for (const dep of Yarn.dependencies({ ident: 'ts-node' })) {
// No need to check for the actual value! Just always call `update`.
if (dep.range !== `18.0.0`) {
dep.update(`18.0.0`);
}
}
},
};
TypeScript 支持
Yarn 提供类型,使编写约束变得更容易。要使用它们,请将依赖项添加到您的项目
$ yarn add @yarnpkg/types
然后,在您的 yarn.config.cjs
文件中,导入类型,特别是 defineConfig
函数,该函数会自动键入配置方法
/** @type {import('@yarnpkg/types')} */
const { defineConfig } = require('@yarnpkg/types');
module.exports = defineConfig({
async constraints({Yarn}) {
// `Yarn` is now well-typed ✨
},
});
您还可以手动检索类型,如果您将一些规则提取到帮助器函数中,这会很有用
/** @param {import('@yarnpkg/types').Yarn.Constraints.Workspace} dependency */
function expectMyCustomRule(dependency) {
// ...
}
您可以给类型设置别名,以便更轻松地使用它们
/**
* @typedef {import('@yarnpkg/types').Yarn.Constraints.Workspace} Workspace
* @typedef {import('@yarnpkg/types').Yarn.Constraints.Dependency} Dependency
*/
/** @param {Workspace} dependency */
function expectMyCustomRule(dependency) {
// ...
}
将所有内容放在一起
本节重新组合了一些约束示例。我们正在考虑稍后将其中一些作为内置帮助器提供,尽管它们往往包含一些对每个团队/公司来说都是独一无二的逻辑。
限制工作空间之间的依赖关系
此代码确保项目中的任何两个工作空间都不能在其 dependencies
或 devDependencies
字段中列出相同的软件包,但具有不同的关联引用。
// @ts-check
/** @type {import('@yarnpkg/types')} */
const {defineConfig} = require(`@yarnpkg/types`);
/**
* This rule will enforce that a workspace MUST depend on the same version of
* a dependency as the one used by the other workspaces.
*
* @param {Context} context
*/
function enforceConsistentDependenciesAcrossTheProject({Yarn}) {
for (const dependency of Yarn.dependencies()) {
if (dependency.type === `peerDependencies`)
continue;
for (const otherDependency of Yarn.dependencies({ident: dependency.ident})) {
if (otherDependency.type === `peerDependencies`)
continue;
dependency.update(otherDependency.range);
}
}
}
module.exports = defineConfig({
constraints: async ctx => {
enforceConsistentDependenciesAcrossTheProject(ctx);
},
});