commitlint 与 Lerna 集成指南:@commitlint/config-lerna-scopes 共享配置的演进、实现与迁移
2026/9/21 1:38:23 网站建设 项目流程
  • 开发工具
  • Lint
  • 代码质量

【免费下载链接】commitlint

📓 Lint commit messages

项目地址:https://gitcode.com/gh_mirrors/co/commitlint
点击查看免费下载

导读

@commitlint/config-lerna-scopes是 commitlint 官方提供的共享配置包,用于在 Lerna monorepo 中把scope-enum规则的值自动绑定为仓库内所有 package 的名称,从而保证提交信息的 scope 一定是真实存在的包名。本文以该包的 CHANGELOG 为主线,结合仓库内源码、测试与 fixtures,完整还原它的工作机制、历代 Lerna 版本兼容策略、Node 版本与模块体系的变更,以及官方推荐的迁移路径,读完即可在自己的 Lerna 仓库中直接启用并对升级影响心中有数。

一、这个配置包解决什么问题

在一个典型的 Lerna monorepo 中,改动通常发生在某个子包内,提交信息需要写清楚改动属于哪个包。手动维护一份 scope 枚举列表既不实时、也容易漏包,而本包的做法是:运行时动态扫描仓库,把所有 package 名作为scope-enum的合法取值

从当前实现(index.js)看,该配置包只导出一个对象:

export default { utils: { getProjects }, rules: { "scope-enum": (ctx) => getProjects(ctx).then((packages) => [2, "always", packages]), }, };

scope-enum规则以三元组[severity, modifier, value]形式返回:严重级别2(error)、修饰符always(必须匹配)、取值packages(动态计算出的包名数组)。测试index.test.js分别断言了这三项,例如expect(severity).toBe(2)expect(modifier).toBe("always"),并验证该规则在缺少 context 时也不会抛错。

包名提取逻辑(index.js)还有一个细节:scoped 包名(@scope/pkg)会被去掉 scope 前缀,只保留短名。也就是说,名为@myorg/ui-kit的包,合法 scope 是ui-kit

name.charAt(0) === "@" ? name.split("/")[1] : name

二、在 Lerna 仓库中启用

2.1 安装

该包在package.json中声明了peerDependencieslerna(且标记为optional,见 package.json),这意味着即使仓库里没有安装 Lerna 也不会阻塞安装,只是动态扫描需要lerna.json与实际的包目录存在。以 npm 为例:

npm install --save-dev @commitlint/cli @commitlint/config-lerna-scopes

2.2 配置

commitlint.config.js中直接extends该配置:

export default { extends: ["@commitlint/config-lerna-scopes"], };

commitlint 会加载该包导出的规则,用仓库内真实的包名动态校验提交信息的scope。合法提交示例:

feat(ui-kit): add new button variant fix(api): correct timeout handling

2.3 底层扫描流程

getProjectsindex.js)的执行路径如下:

  1. 读取context.cwd(默认process.cwd());
  2. 尝试调用@commitlint/config-workspace-scopesgetPackages检测 npm/yarn workspaces;
  3. 若检测到原生 workspaces,则直接使用 workspace 包名并打印弃用警告(详见下文迁移章节);
  4. 否则读取lerna.jsonpackages声明,将每个 glob 模式归一化为指向package.json的 glob(normalizePatternsindex.js);
  5. 用 Node 的fs.promises.glob递归匹配(同时排除node_modulesbower_components),读取并解析所有package.json,最终提取包名并排序。

仓库内 fixtures 覆盖了多种形态:basicpackages/*)、nested(嵌套两级目录)、modules(混合普通包与命名空间目录)、scoped@packages/**)、emptyno-packages-declaration(无packages声明)。对应的测试断言了每种形态的预期结果,例如嵌套仓库返回["nested-a", "nested-b", "nested-c"]index.test.js),scoped 仓库返回["scoped-a", "scoped-b"]index.test.js)。当lerna.json中没有packages声明时返回空数组(index.js),对应测试为work with no declared packages

三、从 CHANGELOG 看版本演进与兼容策略

CHANGELOG 完整记录了该包从 v3.0.0(2017-07-10)到 v21.2.0(2026-06-30)的变更,以下是关键节点:

3.1 Lerna 版本支持路线

版本节点变更内容说明
v3.0.x(2017-07)支持非标准 Lerna 仓库(support non-standard lerna repos最早的动态包名扫描能力
v4.1.1(2017-10)修复新版 Lerna 的包列表获取(fix package list get with recent lerna versions紧跟 Lerna API 变化
v9.0.0(2020-05)修正lernapeerDependencies中的声明依赖关系规范化
v11.0.0(2020-09)移除对 Lerna v2 的支持(BREAKING CHANGES)进入 Lerna v3+ 时代
v12.1.0(2021-03)继续支持 Lerna v3兼容策略保持
v15.0.0(2021-11)升级到 Lerna v4(BREAKING CHANGES)测试改用 npm bootstrap 简化
v19.7.0(2025-01)支持 Lerna 7 和 8兼容最新 Lerna 主版本

3.2 工作区(workspaces)支持与转向

v12.0.0(2021-01)新增了对 yarn workspaces 的支持。从当前源码看,这一能力仍然保留但已被标记为过渡性getProjects会先探测 npm/yarn 原生 workspaces,命中时直接返回 workspace 包名,并输出三行警告:

It seems that you are using npm/yarn workspaces instead of lernas "packages" declaration. Support for workspaces will be removed in a future major version of this package. Please make sure to transition to "@commitlint/config-workspace-scopes" in the near future.

测试index.test.jsfixtures/transition-to-workspace-scopes(该 fixture 的 package.json 声明了"workspaces": ["./packages/*"])验证了警告输出与返回值["workspace-package"]

3.3 模块体系与运行时要求

  • v13.0.0(2021-05):最低 Node 版本提升到 12;
  • v17.0.0(2022-05):最低 Node 版本提升到 14,移除 Node 12 支持;
  • v18.0.0(2023-10):最低 Node 版本提升到 18,移除 Node 14/16 支持;
  • v19.0.0(2024-02):迁移到纯 ESM(BREAKING CHANGES),测试框架从 Jest 迁移到 vitest;当前 package.json 中"type": "module"即为该变更的落地;
  • v21.0.0(2026-05):最低 Node 版本提升到v22,移除 Node 18/20 支持;当前 package.json 中"engines": { "node": ">=22.12.0" }即为该变更的落地。

3.4 依赖与健壮性修复

  • v19.8.0(2025-03):移除已废弃的@lerna/project依赖(#4284),并用node:前缀引用内置模块以绕过require.cache调用(#4302);当前源码第 1-3 行的node:pathnode:fs/promises导入即是这一演进的体现;
  • v12.1.1(2021-04):忽略没有name字段的包(ignore packages without names);这与源码中if (name)的判断完全对应(index.js);
  • v17.6.2(2023-05):修复 Lernapackage.json的解析(lerna package.json resolution);
  • v17.6.3(2023-05):补充缺失依赖;
  • 多个版本(v9.0.0、v16.2.4、v18.6.1 等)持续更新semver依赖。

四、关键源码实现细节

4.1 glob 模式归一化

lerna.json中的packages通常写作packages/*@packages/**或带package.json结尾的形式。normalizePatterns用正则pattern.replace(/\/?$/, "/package.json")保证每个模式最终都指向package.jsonindex.js),例如:

  • packages/*packages/*/package.json
  • @packages/**@packages/**/package.json

4.2 去重与排序

由于不同 glob 模式可能重叠命中同一package.json,源码用Array.from(new Set(...))去重,最终结果经.sort()排序输出([index.js](https://link.gitcode.com/i/c70cbd00d89685676af34d7577353faf#L53-L59, L92)),保证规则取值稳定、可预期,也方便 diff 审查。

4.3 context 注入

scope-enum规则接收 commitlint 传入的 lint context,getProjects从中读取cwdindex.js)。这意味着该配置同样适用于 CI 或非标准目录结构:只要把 context 的cwd指向仓库根目录,就能在任意位置触发正确的包名扫描。测试通过fn({ cwd })传入各 fixture 目录验证了这一点。

五、迁移到 @commitlint/config-workspace-scopes

对于使用 npm/yarn 原生 workspaces 而非 Lernapackages声明的仓库,官方明确建议转向独立的@commitlint/config-workspace-scopes。两个包的机制几乎一致:都通过utils.getPackages扫描package.json并返回[2, "always", packages]形式的规则;区别在于前者读取lerna.jsonpackages,后者读取根package.jsonworkspaces字段(index.js),且后者会用node:前缀与globSync实现同步扫描,并自动过滤无name的包(index.js)。

迁移只需两步:

npm install --save-dev @commitlint/config-workspace-scopes
export default { extends: ["@commitlint/config-workspace-scopes"], };

迁移前请确认根package.jsonworkspaces字段确实存在且格式正确(必须是非空数组),否则getPackages会直接返回空数组(index.js),导致scope-enum无任何合法取值。

六、升级前需要知道的事

结合 CHANGELOG 中的 BREAKING CHANGES,升级到当前 v21.x 系列时重点检查:

  1. Node 版本:当前版本要求node >= 22.12.0,Node 18/20 已不再支持(v21.0.0 起);
  2. 模块体系:包已是纯 ESM("type": "module"),require()引入将不再可用,配置文件需使用 ESM 语法;
  3. Lerna 版本:本包面向 Lerna v4 及更新版本(v19.7.0 起支持 v7/v8),若仍停留在 Lerna v2 需先升级 Lerna;
  4. workspaces 用户:若仓库实际使用 npm/yarn workspaces,运行时会出现过渡警告,且未来主版本将移除该能力,建议尽快迁移到@commitlint/config-workspace-scopes
  5. scope 命名规则:scoped 包只取短名(@myorg/pkgpkg),提交时 scope 不要带@myorg/前缀。

七、相关资源

  • 配置包入口与实现:@commitlint/config-lerna-scopes/index.js
  • 测试与 fixtures:@commitlint/config-lerna-scopes/index.test.js@commitlint/config-lerna-scopes/fixtures
  • 演进记录:@commitlint/config-lerna-scopes/CHANGELOG.md
  • 推荐迁移目标:@commitlint/config-workspace-scopes/index.js及对应 fixtures
  • 包元数据(依赖、engines、peerDependencies):@commitlint/config-lerna-scopes/package.json
  • 开发工具
  • Lint
  • 代码质量

【免费下载链接】commitlint

📓 Lint commit messages

项目地址:https://gitcode.com/gh_mirrors/co/commitlint
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询