首页
/ Cypress Monorepo 工程手册:AGENTS.md 中的工作区划分、命令矩阵、代码规范与 CI/CD 门禁全解

Cypress Monorepo 工程手册:AGENTS.md 中的工作区划分、命令矩阵、代码规范与 CI/CD 门禁全解

2026-09-05 14:19:35作者:申梦珏Efrain

本文以 Cypress 仓库根目录的 AGENTS.md 为骨架,完整拆解这座 monorepo 的工作区结构、开发命令体系、架构分层与代码规范,并逐条对照根目录 package.json、共享 ESLint 配置 packages/eslint-config/src/baseConfig.ts、postinstall 脚本 scripts/run-postInstall.js 等真实源码,说明文档中每条约定背后的实现依据。读完本文,你可以独立配置出与贡献者完全一致的开发环境、按仓库规范运行测试与构建,并理解每条 lint 规则、运行时 API 下限和 CI 门禁的具体含义。

一、AGENTS.md 在仓库中的定位

AGENTS.md 是 Cypress monorepo 的“协作总纲”。Cypress 是面向现代 Web 的开源端到端与组件测试框架,这座 monorepo 同时承载:桌面版与 CLI 主包(cypress)、在浏览器内执行测试的 JavaScript driver、基于 Electron 的测试运行器、一批对外发布的 npm 包(组件测试适配器、webpack/Vite 集成、插件),以及用于构建和发布全部产物的内部工具链。

AGENTS.md 的价值在于:它把“如何装环境、如何跑测试、各包是什么、代码风格怎么约束、PR 和 CI 有什么门禁”压缩到单文件,并且每一条都能在仓库中找到可验证的出处。下文按文档原始脉络逐节展开,并补充源码级证据。

二、工作区划分:六大目录与 workspace 配置

文档将仓库划分为六个工作区。这一划分与根 package.jsonworkspaces.packages 的声明完全一致(clipackages/*npm/*tooling/*system-testsscripts),因此所有目录都共享同一棵 node_modules 依赖树:

  • cli/ — 用户实际安装的 cypress npm 主包(CLI 入口),并共置组件测试框架适配器(@cypress/react@cypress/vue@cypress/angular@cypress/svelte@cypress/mount-utils)。
  • packages/ — 32 个核心内部包:测试 driver、Electron 应用、HTTP server、proxy、launcher、Vue 前端应用、launchpad、reporter、config、data-context、telemetry、types、errors 等。
  • npm/ — 15 个对外发布的 npm 包:bundler 集成、组件测试适配器、插件与开发工具。
  • tooling/ — 3 个内部构建工具:V8 snapshot 创建、packherd 依赖打包器、electron-mksnapshot
  • system-tests/ — 针对已构建好的 Cypress 二进制运行的完整端到端系统测试套件。
  • scripts/ — 内部构建、发布与 CI 自动化脚本。

三、环境准备:Node、Yarn 与 postinstall 链条

前置条件

文档明确要求:

  • Node:使用 .node-version 指定的版本——当前该文件内容为 24.15.0。可用 node -v 核对,用 nvm use 切换。
  • 包管理器:Yarn 1(yarn@1.22.22),不要使用 npm 或 pnpm。根 package.jsonpackageManager 字段锁定了 yarn@1.22.22+sha512...,且 engines 要求 node >=24.15.0yarn >=1.22.22,与 .node-version 互相印证。
  • Lerna:作为 devDependency 安装(当前锁定为 lerna 8.1.9),由根 package.json 脚本统一编排。
  • Electron:构建二进制时由 @packages/electron 自动处理;根 package.json 中 devDependencies 将 electron 固定为 41.7.0——这也是文档“运行时目标”一节中“捆绑应用所用 Node/V8 下限”的出处。

yarn 安装时到底发生了什么

本地执行 yarn 会自动触发 postinstall。scripts/run-postInstall.jsprocess.env.CI 区分两条执行链:

  • 本地(local)patch-package && yarn workspace @packages/server sync-cloud-validations && yarn-deduplicate --strategy=highest && lerna run rebuild-better-sqlite3 --scope @packages/server && yarn build && yarn build-v8-snapshot-dev
  • CI:相同的前四步但不执行 yarn build 与 V8 snapshot 构建。

这解释了文档中的两条关键提醒:postinstall 全程约需 4–5 分钟(含构建与 V8 snapshot 生成),若 yarn 被中断必须重跑;以及优先使用 yarn --frozen-lockfile(lockfile 未变化时跳过部分流程,失败才回退到完整 yarn)。另外,仓库通过 patches/ 目录与 patch-package 维护十余个第三方依赖补丁(如 node-fetch+2.7.0.patchbytenode+1.3.7.dev.patch),这是 patch-package 步骤不可省略的原因。

四、常用命令全览(附脚本实现对照)

以下命令均出自 AGENTS.md,每条都在根 package.jsonscripts 中找到对应实现。

安装与开发启动

# 安装全部依赖(自动执行 post-install 钩子)
yarn

# 以开发模式启动 Cypress(watch,改动即重建)
yarn dev        # 实现为 gulp dev

# 打开开发 + global 模式的 Cypress GUI
yarn start      # 实现为 cypress open --dev --global

测试

# 按包 scope 运行测试(优先于裸 yarn test)
yarn test --scope @packages/server

# 指定单个 vitest 规格文件(使用 vitest 的包)
yarn workspace @packages/config test -- <path-to-spec>

# 用 glob 模式指定 vitest 规格
yarn workspace @packages/net-stubbing test -- "<glob-pattern>"

# 指定单个 mocha 规格文件(使用 mocha 的包)
yarn workspace @packages/server test-unit -- <path-to-spec>

# 按名称模式过滤 mocha 测试
yarn workspace @packages/server test-unit -- --grep "<pattern>"

# 运行系统测试(完整二进制级 E2E)
yarn test-system    # 实现为 yarn workspace @tooling/system-tests test

# 开发模式下对指定规格 headless 运行 Cypress
yarn cypress:run -- --spec "path/to/spec.cy.ts"   # 实现为 cypress run --dev

# 开发模式下对指定规格运行组件测试
yarn cypress:run:ct -- --spec "path/to/spec.cy.ts"  # 实现为 cypress run --component --dev

值得注意的实现细节:根 scriptstest 的实现是 yarn lerna exec yarn test --scope=cypress --scope=@packages/{...},其中显式排除了 driver 等包(test-unit 则 ignore 了 {driver,root,static,web-config,net-stubbing,network-interception} 等)——不同包使用不同的测试框架与执行方式,这也是文档建议“优先按 scope 运行”的原因。cli/package.json"test-unit": "vitest run" 则印证了 vitest 是 CLI 侧的测试框架。

类型检查

# 全 monorepo TypeScript 类型检查
yarn type-check   # 实现为 yarn lerna exec yarn type-check --scope=@tooling/system-tests && node scripts/type_check

# 仅 Lerna 路径的类型检查
yarn check-ts     # 实现为 yarn lerna run check-ts

Lint 与格式化

# Lint 所有包(no bail,并发度 2)
yarn lint         # 实现为 lerna run lint --no-bail --concurrency 2

# Lint 并自动修复指定 scope
yarn lint:fix     # 实现为 lerna run lint ... --scope=@cypress/{grep,mount-utils,schematic,puppeteer,react,vue,svelte} -- --fix

注意:本项目不使用 Prettier,全部格式化由 ESLint 强制。.prettierignore 内容为 **/*,即排除所有文件,与文档声明一致。

构建

# 完整 monorepo 构建
yarn build                # lerna-build.js + @packages/electron build-binary + lerna run build-cli

# 构建 V8 snapshot(开发)
yarn build-v8-snapshot-dev

# 构建 V8 snapshot(生产)
yarn build-v8-snapshot-prod

# 清理全部构建产物
yarn clean               # lerna run clean --no-bail

# 彻底清理并重装
yarn clean-deps && yarn  # clean-deps 会递归删除所有 node_modules

其中 V8 snapshot 脚本的实现是 node --max-old-space-size=8192 tooling/v8-snapshot/scripts/setup-v8-snapshot-in-cypress.js(dev 版本追加 --env=dev),对应 tooling/v8-snapshot/ 目录,服务于 Electron 启动性能优化。

五、架构:子系统与包的职责映射

AGENTS.md 的 Architecture 一节按子系统把 50 余个包归类。结合目录结构逐组说明:

CLI 与分发

测试运行器与 Driver

  • @packages/driverpackages/driver/):在浏览器内执行用户测试代码的 JS driver,实现所有 cy.* 命令、断言与重试机制。
  • @packages/runnerpackages/runner/):webpack 打包的 runner UI,托管被测应用(AUT)iframe 与 driver 通信层。
  • @packages/apppackages/app/):Cypress GUI / Launchpad 的 Vue 3 前端,桌面应用主界面。
  • @packages/launchpadpackages/launchpad/):项目创建、上手引导与测试文件脚手架 UI。
  • @packages/frontend-sharedpackages/frontend-shared/):applaunchpad 共享的 Vue 组件与设计系统 token。
  • @packages/reporterpackages/reporter/):测试结果报告器 UI(pass/fail 树、日志面板)。

服务器与网络

  • @packages/serverpackages/server/):HTTP server,负责测试文件分发、浏览器启动、socket 通信与测试运行编排,约 248 个源文件是其中体量最大的包。
  • @packages/proxypackages/proxy/):拦截测试运行期间所有浏览器流量的 HTTP/S 代理。
  • @packages/net-stubbingpackages/net-stubbing/):cy.intercept 网络打桩实现——请求匹配与响应篡改。
  • @packages/network / @packages/network-tools / @packages/https-proxy:低层网络协议工具、跨包复用的高层网络辅助、用于 TLS 拦截的 HTTPS 代理实现。

配置与数据

桌面与 Electron

  • @packages/electron:Electron 运行时封装、二进制构建工具与自动更新集成。
  • @packages/launcherpackages/launcher/):Chrome、Firefox、Edge、WebKit、Electron 的浏览器检测与启动逻辑。
  • @packages/extension:注入浏览器以启用跨域能力与自动化钩子的 WebExtension。

类型、错误与工具

  • @packages/types:全 monorepo 共享的 TypeScript 类型定义;@packages/errorspackages/errors/):错误定义、错误模板与工具(test 目录含 170 个 .ansi 快照用于校验错误文案);@packages/socket:driver 与服务端通信的 WebSocket 库(浏览器与 Node 两侧);@packages/telemetry:OpenTelemetry 插桩封装;@packages/icons:图标注册表与 SVG 资产;@packages/stderr-filtering:stderr 输出过滤。

构建与 Snapshot 基础设施

  • @packages/v8-snapshot-require / @packages/packherd-require:Electron 中 V8 snapshot 的模块加载、以及 @tooling/packherd 所打包依赖的模块加载器。
  • @packages/web-config / @packages/ts / @packages/eslint-config / @packages/resolve-dist:前端 webpack/PostCSS 配置、共享 tsconfig 与 ts-node 注册器、共享 ESLint 预设、编译产物路径解析。
  • @tooling/v8-snapshot / @tooling/packherd / @tooling/electron-mksnapshot:V8 snapshot 创建工具、把入口可达的全部依赖打包成单一产物的 bundler、面向目标 Electron 版本的 mksnapshot 二进制封装。

对外发布的 npm 包(npm/ 目录)

  • 组件测试适配器@cypress/react@cypress/vue@cypress/angular@cypress/svelte、共享工具 @cypress/mount-utils
  • Bundler 集成@cypress/webpack-dev-server@cypress/vite-dev-server@cypress/webpack-preprocessor@cypress/webpack-batteries-included-preprocessor@cypress/vite-plugin-cypress-esm(浏览器测试中可变 ESM 模块的 Vite 插件)。
  • 插件与开发工具@cypress/grep(按子串/tag 过滤测试运行)、@cypress/puppeteer(用 Puppeteer 增强 Cypress 测试)、@cypress/schematic(Angular CLI 官方 schematic)、@cypress/eslint-plugin-dev(Cypress 开发包共享的 ESLint 规则)。

六、代码规范:每条约定都能在 ESLint 配置中找到出处

文档的 Code Conventions 一节全部由 packages/eslint-config/src/baseConfig.ts 中的规则实现,逐条对照:

约定 ESLint 出处
不用 Prettier,格式化全由 ESLint 承担 .prettierignore 排除全部文件;stylistic 插件接管格式
多行尾逗号 @stylistic/comma-dangle: ['error', 'always-multiline']baseConfig.ts#L64
console no-console: 'error'baseConfig.ts#L94
同步 FS 调用告警(existsSync 除外) no-restricted-syntax 用 esquery 选择器匹配 fs.*SyncbaseConfig.ts#L108-L117
return 前必须空行 padding-line-between-statementsbaseConfig.ts#L118-L158
测试中禁 .only mocha/no-exclusive-tests: 'error'baseConfig.ts#L189
类型导入必须 import type @typescript-eslint/consistent-type-importsbaseConfig.ts#L294-L305

其余约定:单引号、无分号(semi: 'never')、2 空格缩进、禁 var、模板字符串优先(prefer-template)、对象简写(object-shorthand)、未用变量以 _ 前缀豁免(argsIgnorePattern: '^_')、TypeScript 基础 strict: truenoImplicitAny: false

提交时的第二道防线:根 package.jsonlint-staged 配置(package.json#L254-L266)对 cli/packages/npm/ 等各目录的 JS/TS/Vue 文件自动执行 eslint --fix,配合 huskyprepare: husky install)形成 pre-commit 检查——这正是文档所说“.only 会被 yarn lint 与 pre-commit ESLint 双重捕获”的机制。对于 fixture 或类型样例中确实需要的 .only,用 eslint-disable-next-line mocha/no-exclusive-tests 并附简短注释。.skip 则必须带 NOTE: / TODO: / FIXME: 注释说明原因。

注释风格:解释 why,只描述现状

文档给出的注释准则:代码自解释时优先不写注释;必须写时解释 why 以及代码本身没有直接表达的信息;不在一个文件里重复同一条注释;只描述当前状态,不描述“以前怎样、改了什么”。

反例(文档原文):

// never wipe the entire jar - the old hack called clearCookies() with no filter
// we no longer need to clear the state here, CDP added automatically clearing
// Firefox previously relied on os-level focus, now we use WebDrive BiDi to focus

正例(文档原文):

// Close any extra pages so they don't leak into other tests
// Firefox doesn't support this in native BiDi, so we pull remote.location from current frame
// `cookie`'s serializer rejects an IPv6 literal Domain (e.g. `[::1]`), crashing
// the proxy. Browsers scope cookies for IP hosts to that host anyway, so omit
// Domain and let the cookie default to host-only.

七、运行时目标:不要假设你正在使用的 Node 版本

这是 AGENTS.md 中最容易被忽视、也最影响“能不能用某 API”的一节。monorepo 中的代码运行在多种运行时里,各有各的 JS / 运行时 API 下限,使用现代 Node/DOM API 前必须先确认目标运行时是否支持:

  1. 开发工具、gulp、构建/开发脚本 — 下限为 .node-version 中的版本(当前 24.15.0)。
  2. 捆绑应用(main / Electron 进程) — 下限为根 package.json 中固定 Electron 版本(当前 electron 41.7.0)内嵌的 Node/V8,需查该 Electron 发行版对应的 Node 版本。
  3. config/plugins 子进程与 cypress CLI — 运行在用户的 Node 上,支持范围由 cli/package.jsonengines.node 定义(当前为 ^22.0.0 || ^24.0.0 || >=26.0.0)。文档特别指出这条下限低于开发/捆绑版 Node,因此是这类代码的真正约束。源码印证:该子进程即 packages/server/lib/plugins/child/require_async_child.ts,由 packages/data-context/src/data/ProjectConfigIpc.ts fork。
  4. 随浏览器分发的 bundle@packages/app@packages/frontend-shared@packages/driver)— 下限为受支持浏览器的最近 3 个大版本。由于 Safari 大约每年才发一个大版本,这条下限回溯的年份最长,是四者中最保守的;@packages/driver 运行在用户 AUT 所在浏览器中。对 WebKit,Cypress 运行的是随 playwright-webkit 依赖打包的 WebKit(当前根 package.json 中固定为 1.61.0),而非用户系统 Safari,因此 WebKit 下限跟随该依赖版本。

文档的结论:在依赖某个 API 之前,先对照相应下限核实(Node 查 node.green,浏览器查 caniuse/MDN)。

八、Pull Request、Changelog 与 CI/CD 门禁

PR 规范

CONTRIBUTING.md 是 PR 约定(含决定下一版本号的 semantic-release 标题前缀)的唯一事实来源。此外两条硬性要求:

  • 面向用户、随下个版本发布的变化,须在 cli/CHANGELOG.md 增加 changelog 条目,写法遵循 guides/writing-the-cypress-changelog.md(手写精修而非自动生成,条目分 breaking/dependency/deprecation/feat/fix/misc/perf 等区块)。
  • 必须完整填写 Pull Request 模板;不适用的小节写 N/A 而不是删除——模板不完整的 PR 不会被 review。

CI/CD 流水线

  • 主 CI:CircleCI。配置模块化存放在 .circleci/src/(含 pipeline 源文件),编译产物为 .circleci/packed/pipeline.yml;何时需要把分支加入 full-CI 白名单(binary 测试、Windows 任务、V8 snapshot 校验)见 .circleci/AGENTS.md
  • 补充 CI:GitHub Actions 承担安全扫描(Snyk)、SBOM 生成、浏览器版本自动更新与 PR 校验(.github/workflows/)。
  • 基线分支develop——所有 PR 指向 develop,发布分支命名为 release/X.Y.Z
  • 多平台矩阵:Linux x64、Linux ARM64、macOS x64、macOS ARM64、Windows 全部并行。
  • 发布门禁:所有测试必须通过 ready-to-release 聚合 job,之后才会执行 npm-release
  • 外部 PR:需先经过 approve-contributor-pr 人工审批门禁,CI 才会运行。
  • 二进制构建:npm 发布之后单独触发,跨平台二进制组装后经由 CDN 分发。

九、云端开发环境的已知坑

文档最后一段面向 Cursor Cloud 环境给出实操经验,对本地容器化开发同样适用:

  • Node.js >= 22.19.0 与 Yarn 1.22.22 预装;yarn 会触发完整 postinstall(patch-package、yarn-deduplicate、rebuild better-sqlite3、lerna build、V8 snapshot)。
  • Xvfb 已运行于 DISPLAY=:1,Chrome 位于 /usr/bin/google-chrome-stable
  • yarn dev 启动 Electron GUI(global/dev 模式的 Launchpad):先构建 @packages/app@packages/launchpad 的 Vite bundle 再拉起 Electron,GraphQL server 位于 http://localhost:4444/__launchpad/graphql
  • 开发模式 headless 运行:yarn cypress:run -- --project <path> --browser chrome --headless。注意:目标项目的 config 文件不能 require('cypress'),因为它会从项目根目录解析而非仓库内。
  • 测试优先按 scope 运行;@packages/network 等套件需要特权端口(443),在无特权容器中报 EACCES 属预期;@packages/config 有两个断言 cypressBinaryRoot 包含 'cypress' 的用例,在目录名不同的工作区(如 /workspace)会失败——这是已知的路径依赖问题而非代码 bug。
  • 聚焦 lint:yarn lint --scope @packages/<name>
  • 务必从仓库根目录运行 yarn,不要进入子包内执行。

十、小结

AGENTS.md 把 Cypress monorepo 的工程体系收敛为五类信息:六大工作区的职责边界(与根 package.json 的 workspaces 声明一致)、以 Lerna 编排的命令矩阵(每条命令均可在根 scripts 中溯源)、按子系统归类的 50 余个包的架构地图、可由 packages/eslint-config/src/baseConfig.ts 逐条验证的代码与注释规范,以及以 develop 为基线、ready-to-release 聚合 job 为发布门禁的 CI/CD 流程。对需要理解、检索或二次开发这座仓库的工程师与 AI Agent 而言,它是第一份应当通读的地图;本文补充的源码证据(postinstall 链条、ESLint 规则行号、运行时下限出处)则让其中每一条约定都可以被独立验证。

登录后查看全文
热门项目推荐
相关项目推荐