Gutenberg 仓库是一个 npm workspaces monorepo。除了位于 packages/ 目录下已发布的 @wordpress/* 包之外,该仓库还包含用于开发工具的内部工作区(tools/*)、测试基础设施(test/*)以及相关项目(storybook、widgets/*、routes/*)。
本指南将说明如何添加或修改这些内部工作区,以及为什么依赖项应放在工作区中而不是根目录的 package.json 文件中。
为什么要使用工作区,而不是根依赖
添加到根 package.json 中的任何内容都会隐式地对仓库中的每个工作区可用,这使得很难分辨哪个工作区实际上需要某个特定的依赖项。保持根目录精简有以下几个好处:
- 关注点分离。 每个工作区声明其运行所需的依赖项,使代码与依赖项之间的关系更加明确。
- 更干净的根目录。 根
package.json仅包含全仓库范围的工具(lint、format、type-check、git hooks、monorepo 编排)。当根目录较小时,审查依赖项变更会更容易。 - 更少的合并冲突。 贡献者可以在不触及根目录的情况下更新某个工作区的依赖项。
- 防止幻影依赖。 该仓库使用 npm 的隔离安装策略(在
.npmrc中设置install-strategy = "linked",于 #83847 中采用)。依赖项存储在node_modules/.store/中,并仅符号链接到声明了它们的工作区中,因此工作区无法导入它从未声明过的依赖项。根依赖是例外:Node 仍然可以通过向上查找至根node_modules来找到它们,这也是保持根目录精简的另一个原因。
对于“这个依赖项应该放在哪里?”这个问题,默认答案是一个工作区,而不是根目录。如果你发现自己想要修改根 package.json,请考虑该依赖项是否可以存在于:
tools/或test/下的一个现有工作区,该工作区已经涵盖了用例(例如,@wordpress/eslint-tools、@wordpress/release-tools、@wordpress/validation-tools、@wordpress/unit-tests)。- 如果没有现有的合适工作区,则在
tools/下创建一个新工作区(如果是测试基础设施,则在test/下创建)。
工作区的位置
| 位置 | 用途 |
|---|---|
packages/* | 已发布的 @wordpress/* npm 包。参见 Managing Packages。 |
tools/* | 内部开发工具(ESLint 配置、发布 CLI、API 文档生成器、验证等)。未发布到 npm。 |
test/* | 测试基础设施(单元、集成、e2e、性能、原生、storybook-playwright)。 |
storybook | Gutenberg Storybook 主机。 |
routes/* | 编辑器路由入口点。 |
widgets/* | 小部件捆绑包。 |
注册的工作区通配符集合位于根 package.json 的 "workspaces" 数组中。一旦匹配现有通配符(例如,tools/*)的任何目录中包含 package.json,它就会被自动拾取。
创建一个新的工作区
此模式确立于 #74640(Storybook 转换),并作为后续转换的模型。
1. 在工作区目录中添加 package.json
对于未发布到 npm 的内部工具:
{
"name": "@wordpress/<workspace-name>",
"version": "0.0.0",
"description": "<short description>",
"private": true,
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/tools/<workspace-name>",
"repository": {
"type": "git",
"url": "git+https://github.com/WordPress/gutenberg.git",
"directory": "tools/<workspace-name>"
},
"bugs": {
"url": "https://github.com/WordPress/gutenberg/issues"
},
"devDependencies": {},
"scripts": {}
}
注意事项:
- 对于永不应发布的工作区,请使用
"private": true。 - 仅列出该工作区实际导入或执行的依赖项。
- 要依赖于 monorepo 中的另一个工作区,请使用
file:引用(例如,"@wordpress/scripts": "file:../../packages/scripts")。
2. (可选)添加 tsconfig.json
如果工作区包含 TypeScript,请扩展共享基础配置:
{
"extends": "@wordpress/monorepo-tools/tsconfig/base.json",
"compilerOptions": {
"rootDir": "./",
"outDir": "./build"
},
"include": [ "./**/*.ts" ]
}
然后在根 tsconfig.json 中为新工作区添加项目引用。
3. 注册工作区(如果需要)
如果新工作区位于根 package.json 中通配符已覆盖的路径下(例如,tools/*),它将自动注册。否则,请在根 package.json 的 workspaces 中添加一个条目。
4. 从仓库根目录暴露脚本
使用 npm run --workspace 转发贡献者应从仓库根目录运行的任何脚本:
"scripts": {
"my-task": "npm run --workspace @wordpress/<workspace-name> my-task --"
}
尾部的 -- 会将额外的 CLI 参数转发给工作区脚本(例如,npm run my-task -- --watch)。
5. 添加 README
在工作区目录中包含一个 README.md,描述工作区的功能、它暴露的脚本以及任何非显而易见的设置。
6. 更新 CI 工作流程
.github/workflows/ 下的 CI 工作流程应通过步骤 4 中添加的根 npm run 包装器调用工作区,而不是 cd 进入工作区目录。保持 CI 与根脚本一致意味着贡献者在本地运行与 CI 相同的命令。
- run: npm ci
- run: npm run my-task
日常工作流中使用工作区
在工作区中添加或删除依赖项
始终将依赖项更改限定在使用它们的工作区内:
npm install <package> --workspace @wordpress/<workspace-name>
npm uninstall <package> --workspace @wordpress/<workspace-name>
这些命令会更新工作区的 package.json 和根 package-lock.json,而不会触及根 package.json。
运行工作区脚本
从仓库根目录:
npm run <script> --workspace @wordpress/<workspace-name>
或者,如果存在根级转发脚本(见上述步骤 4):
npm run <root-script>
在所有工作区中运行脚本
要在定义它的每个工作区中运行相同的脚本:
npm run --if-present --workspaces <script>
根 prelint:js 脚本就是这种模式的一个示例。