
Gutenberg 仓库 Workspace 开发指南基于 npm workspaces 的内部工作区新建、注册与日常依赖管理【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg导读Gutenberg 仓库不仅发布packages/*下的wordpress/*npm 包还通过 npm workspaces 为主体结合根 package.json、tsconfig.json 与各工作区真实的package.json源码完整讲解为什么内部依赖要落在工作区而非根依赖、工作区分布在哪里、如何从零新建一个工作区、以及日常如何增删依赖与运行脚本。读完你就能按仓库规范安全地扩展这套 monorepo并理解 CI 与本地命令为何要保持一致。为什么依赖应放在工作区而不是根 package.jsonmonorepo 根目录的package.json是仓库的总指挥但任何添加进根devDependencies的依赖都会隐式地对每一个工作区可见。这会让某个工作区到底依赖什么变得模糊不清。当前仓库刻意保持根依赖精简——根 package.json 只保留仓库级工具链husky、lerna、lint-staged、syncpack、patch-package、concurrently、cross-env、wait-on以及wordpress/scripts、wordpress/env、wordpress/eslint-tools、wordpress/monorepo-tools、wordpress/release-tools、wordpress/stylelint-tools等内部工具页面级代码与测试所需的依赖全部下沉到各自工作区。把依赖放进工作区而非根依赖主要有四个好处关注点分离Separation of concerns每个工作区在自己的package.json中声明其真正需要的依赖代码与依赖的对应关系一目了然。根目录更干净Cleaner root根package.json只承载 lint、format、类型检查、git hooks 与 monorepo 编排依赖变更的 review 变得更轻松。更少的合并冲突Fewer merge conflicts贡献者更新某个工作区的依赖时无需触碰根package.json。防止幽灵依赖Phantom dependency preventionnpm 采用提升hoisting安装策略依赖会被提升到根node_modules一个工作区可能碰巧 import 到它从未声明的包。保持根目录精简能让这种依赖关系保持诚实也是未来迁移到隔离依赖方案仓库讨论中的 pnpm 迁移的前提——届时工作区只能看到自己声明的依赖。因此这个依赖该放哪的默认答案永远是工作区而不是根。如果下意识想往根package.json里加依赖先思考它能否放进一个已存在的工作区tools/或test/下已覆盖该场景的例如wordpress/eslint-tools、wordpress/release-tools、wordpress/validation-tools、wordpress/unit-tests或一个新建的工作区tools/下放开发工具test/下放测试基础设施如果没有合适归宿。工作区都分布在哪里当前仓库的工作区分布可以归纳为下表位置用途packages/*对外发布的wordpress/*npm 包管理规范见 管理包Managing Packagestools/*内部开发工具ESLint 配置、发布 CLI、API 文档生成器、校验脚本等不发布到 npmtest/*测试基础设施unit、integration、e2e、performance、storybook-playwright 等storybookGutenberg Storybook 宿主routes/*编辑器路由入口点widgets/*组件面板widget打包产物以仓库实际内容核对tools/下现有agents、docs、eslint、monorepo、pr-meta、react-18、react-19、release、stylelint、validation等工作区test/下现有ai-development、e2e、integration、performance、php、storybook-playwright、unit等。这些 glob 的注册集合就写在根 package.json 的workspaces数组中workspaces: [ packages/*, routes/*, storybook, test/*, tools/*, widgets/*, !test/ai-development ]两点值得注意任何被现有 glob 匹配到的目录例如tools/*只要其内部出现了package.json就会被 npm自动识别为工作区无需额外注册数组中的!test/ai-development是一条排除规则用于把该目录从test/*的匹配中剔除说明test/ai-development虽然放在test/下却是独立管理依赖的根脚本中test:agent-evals使用npm --prefix test/ai-development run eval --单独调用。创建一个新工作区的完整步骤该模式在 #74640Storybook 转换中确立并成为后续迁移的模板。一共六步。第 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: githttps://github.com/WordPress/gutenberg.git, directory: tools/workspace-name }, bugs: { url: https://github.com/WordPress/gutenberg/issues }, devDependencies: {}, scripts: {} }要点永不该发布的包务必设置private: true。仓库中的 tools/monorepo/package.json、tools/validation/package.json、test/unit/package.json 均是此写法尽管它们同时声明了publishConfig.accessprivate字段仍从根上禁止发布只声明该工作区实际 import 或执行的依赖。例如 tools/validation/package.json 只列出校验脚本真正用到的chalk、glob、jsonc-parser、simple-git等要依赖 monorepo 内的另一个工作区使用file:引用。例如 tools/monorepo/package.json 中wordpress/data: file:../../packages/data根 package.json 中wordpress/scripts: file:./packages/scripts、wordpress/monorepo-tools: file:./tools/monorepo也是同一机制——file:让 npm 直接链接本地目录而不是去 registry 拉取。第 2 步可选添加tsconfig.json如果工作区包含 TypeScript应继承共享基础配置{ extends: wordpress/monorepo-tools/tsconfig/base.json, compilerOptions: { rootDir: ./, outDir: ./build }, include: [ ./**/*.ts ] }这里的wordpress/monorepo-tools/tsconfig/base.json是真实存在的共享基座见 tools/monorepo/tsconfig/base.json它开启strict、noImplicitReturns、composite、declaration、declarationMap、isolatedModules等严格选项并约定rootDir与declarationDir其可被引用的路径正是通过 tools/monorepo/package.json 的exports字段./tsconfig/*: ./tsconfig/*暴露出来的。随后需要在根 tsconfig.json 的references数组中为新工作区添加一条项目引用project reference例如{ path: tools/pr-meta }。从仓库现状看根 tsconfig 的 references 覆盖了routes/*、storybook、test/e2e、test/performance、test/storybook-playwright、widgets以及tools/pr-meta等目录可以推断并非每个工作区都要求有 TypeScript 项目引用只有含 TS 源码且需要被类型检查覆盖的工作区才需要。第 3 步注册工作区如需要如果新工作区位于根package.jsonworkspaces已有 glob 覆盖的路径下例如tools/*它会被自动注册。否则需要在根package.json的workspaces数组中新增一条记录。当前仓库对tools/*、test/*、routes/*、widgets/*均已配置 glob因此绝大多数新建工作区无需改数组只有在路径超出既有模式如test/ai-development这类需要隔离的情况时才会动它。第 4 步从仓库根暴露脚本将贡献者应从根目录运行的脚本用npm run --workspace转发scripts: { my-task: npm run --workspace wordpress/workspace-name my-task -- }结尾的--用于把额外的 CLI 参数透传给工作区脚本例如npm run my-task -- --watch。这在根 package.json 中是贯穿全篇的惯例test:unit: npm run --workspace wordpress/unit-tests test:unit --lint:lockfile: npm run --workspace wordpress/validation-tools validate-package-lock --docs:api-ref: npm run --workspace wordpress/docs-tools docs:api-ref --agents:setup: npm run --workspace wordpress/agent-tools setup --storybook:build: npm run --workspace wordpress/storybook storybook:build第 5 步添加 README在工作区目录中放置一个README.md说明该工作区的职责、暴露的脚本以及任何不显而易见的设置。例如test/unit工作区的 homepage 字段就指向其 README见 test/unit/package.json。第 6 步更新 CI 工作流.github/workflows/下的 CI 工作流应通过第 4 步建立的根npm run包装调用工作区而不是cd进工作区目录再执行。这样贡献者在本地运行的命令与 CI 完全一致- run: npm ci - run: npm run my-task仓库实况可以印证这一点在 .github/workflows/unit-test.yml 中Jest 与 Vitest 分区分别通过npm run test:unit -- ...和npm run test:unit:vitest:shuffled -- ...调用最终落到wordpress/unit-tests工作区的脚本见 test/unit/package.json 的test:unit、test:unit:vitest等定义而 CI 从不直接进入工作区目录执行。日常开发中的工作区操作增删某个工作区的依赖始终把依赖变更限定在使用它的工作区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--if-present保证没有定义该脚本的工作区被安静跳过。根 package.json 的prelint:js就是这一模式的范例prelint:js: npm run --if-present --workspaces prelint:js深入验证一个真实工作区的解剖以tools/monorepo为例把整套规范串起来看它叫wordpress/monorepo-toolsprivate: true见 tools/monorepo/package.json符合内部工具不发布的定位它通过file:引用同仓库的wordpress/data包tools/monorepo/package.json是工作区间依赖的标准写法它通过exports暴露./tsconfig/*子路径tools/monorepo/package.json使得其他工作区能用wordpress/monorepo-tools/tsconfig/base.json继承共享 TS 配置根package.json用wordpress/monorepo-tools: file:./tools/monorepo根 package.json把它引入根工具链同时多个根脚本如lint:tsconfig、lint:lockfile通过npm run --workspace wordpress/validation-tools之类的方式调用工作区脚本。这恰好覆盖了新建工作区六步中的每一步package.json、tsconfig基座、file:依赖、根脚本转发以及 CI 中经根脚本统一调用的约定。当你在 Gutenberg monorepo 中新增或修改内部工作区时这套模式就是唯一需要遵循的规范。结语Gutenberg 的 workspace 体系本质上是用 npm workspaces 把一个巨大的 JS/TS monorepo 拆成职责清晰的小单元根package.json只做编排所有功能代码与测试基础设施各自声明依赖、各自暴露脚本。掌握 docs/contributors/code/workspace-development.md 中这套默认放工作区、六步新建、根脚本转发、CI 对齐的约定后你既能安全地为仓库添加新工具或测试工作区也能在提交依赖变更时避免无谓的合并冲突与幽灵依赖问题。【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考