Cypress 发布产物构建指南:npm 包与 Electron 二进制的构建、打包与发布流程
本篇围绕 Cypress 仓库中的构建指南 building-release-artifacts.md 展开,讲清 Cypress 发布产物的两大组成——npm 包与二进制压缩包——各自如何构建、打包与验证。读完你能掌握 yarn lerna run build-cli、yarn binary-build、yarn binary-package、yarn binary-zip 等命令的完整用法与适用平台限制,并能结合 scripts/binary/build.ts、scripts/binary/zip.js 等源码理解产物内部的组装过程。
发布产物的整体结构
Cypress 的 cypress npm 包由两部分组成,二者必须保持同一版本号:
- npm 包
.tgz(由 cli 目录构建)- 包含命令行工具
cypress、TypeScript 类型定义和 Module API; - 最终用户通过 npm/Yarn/pnpm 将其安装到项目的
node_modules目录。
- 包含命令行工具
- "二进制"
.zip(由 packages 目录构建)- 包含 Electron 应用、
ffmpeg,以及 packages 子目录中各包的构建产物(frontend-shared、reporter、web-config不单独打包进去); - 同时包含上述所有包的生产依赖;
- 在
cli安装时或执行cypress install时被下载到系统缓存目录;生产环境下若本地未缓存,会从 Cypress CDN 拉取。
- 包含 Electron 应用、
该指南覆盖了这两种产物的构建方式,并额外提供了打包、冒烟测试、上传与缓存清理等配套流程。
构建 npm 包
指南原文特别提示:以下两步在 CI 中已自动化,按正式发布流程(见 release-process.md)走时不需要你手动执行。
构建一个 npm 包只需要两步:
- 递增根 package.json 中的
version; - 运行
yarn lerna run build-cli。
这两步实际完成的工作:
- 构建
cypressnpm 包; - 将代码转译为 ES5,以兼容常见的 Node 版本;
- 结果输出到 cli/build 目录。
从源码看,build-cli 脚本定义在 cli/package.json 中:
"build": "rollup -c",
"postbuild": "yarn make-bin-executable && yarn sync-build-dist && yarn prepare-package-json && yarn bundle-ct-frameworks",
"build-cli": "rollup -c && yarn postbuild",
即先用 cli/rollup.config.mjs 完成 Rollup 打包,随后依次执行 bin 可执行化处理、产物同步、package.json 准备(cli/scripts/prepare-package-json.ts)与组件测试框架的框架打包(cli/scripts/bundle-ct-frameworks.ts),保证 npm 包内容完整可发布。
构建二进制
同样地,二进制的构建步骤在 CI 中已自动化。npm 包必须有同版本的二进制与之对应,生产环境下若本地未缓存会从 CDN 检索。本地构建的入口命令(见根 package.json 的 scripts):
| 命令 | 作用 | 脚本定义 |
|---|---|---|
yarn binary-build |
构建二进制 | cross-env NODE_OPTIONS=--max_old_space_size=8192 node ./scripts/binary.js build |
yarn binary-package |
打包(electron 打包)二进制 | cross-env NODE_OPTIONS=--max_old_space_size=8192 node ./scripts/binary.js package |
yarn binary-zip |
将构建好的二进制压缩为 zip | node ./scripts/binary.js zip |
yarn binary-smoke-test |
对构建产物做冒烟测试 | node ./scripts/binary.js smoke |
yarn binary-deploy |
build → zip → upload 一条龙 | node ./scripts/binary.js deploy |
yarn binary-purge |
清理某版本各平台的 CDN 缓存 | node ./scripts/binary.js purge-version |
注意 binary-build 与 binary-package 都通过 cross-env 注入了 NODE_OPTIONS=--max_old_space_size=8192,因为构建过程内存占用较高。
平台选择:可以在 Linux 上构建 Cypress 二进制(与 CI 相同的方式)——在 yarn docker 容器内运行 yarn binary-build 和 yarn binary-package。仓库根目录提供了 docker-compose.yml 支撑该容器环境。
macOS 本地构建:需要在钥匙串中拥有代码签名证书(按 Apple 官方代码签名指南申请)。另外,由于公证(notarization)需要 Apple Developer Program 账号,本地构建时通常应设置 SKIP_NOTARIZATION=1 跳过公证。CI 中的代码签名细节见 code-signing.md。
构建阶段内部做了什么(源码级解读)
yarn binary-build 最终调用 scripts/binary/index.js 中 deploy.build,再进入 scripts/binary/build.ts 的 buildCypressApp。其流程与源码注释高度对应:
- 禁止交叉构建:
if (platform !== os.platform())直接抛错,"Attempting to cross-build, which is not supported"——这正是指南要求"在哪个平台构建哪个平台产物、或用 docker 构建 Linux 版"的底层原因(见 scripts/binary/build.ts#L77-L80); - 清理与符号链接:删除
TMP_BUILD_DIR、build/与packages/electron/dist,并将build符号链接到系统临时目录下的cypress-build/<platform>/build(路径常量定义在 scripts/binary/meta.ts 的TMP_BUILD_DIR、buildRootDir); - 构建各子包:把目标
version写回根package.json(保证 V8 快照与版本正确),然后并发执行yarn lerna run build与yarn lerna run build-prod,并发度为min(4, os.availableParallelism()); - 拷贝到 dist:
packages.copyAllToDist把各包产物拷贝进 dist 目录,并拷贝 patches 目录(过滤掉.dev.patch,因为生产安装只会应用生产补丁),同时拷贝yarn.lock保证安装一致性; - 精简生产依赖:剔除
devDependencies、lint-staged等字段后写入 dist 的package.json,postinstall只保留patch-package,再执行yarn --production; - 瘦身:用
del删除各依赖包中的测试目录(如pixelmatch/test、exif-parser/test等)、.ts源文件与开发用补丁; - 写入运行时入口:生成 dist 的
index.js(require('./packages/server/index.js'))与包含electronVersion/electronNodeVersion的package.json; - 构建后自验证:
testDistVersion在 dist 目录执行node index.js --version并与目标版本比对,testStaticAssets校验静态资源,任何不一致都会让构建失败。
yarn binary-package 则调用 packageElectronApp(scripts/binary/build.ts#L237):
- 移除
node_modules/.bin、开发用 Electron 应用目录等打包后无用的内容; - 通过
electron-builder以publish: 'never'、asar: false配置进行应用打包(注释说明因 electron-builder 不会拷贝packages/*/node_modules中的嵌套目录,故不使用 asar); - Windows 路径长度防护:
checkMaxPathLength按"默认缓存位置 + 260 字符上限"检查 dist 内所有相对路径,超限即报错要求提升(hoist)或删除文件(scripts/binary/build.ts#L45-L70); - macOS GateKeeper 校验:当
platform === 'darwin'且未跳过签名时,用spctl -a -vvvv验证应用签名,失败即抛 "Verifying App via GateKeeper failed"(scripts/binary/build.ts#L309-L326); - 最后用
du -d 1统计各包大小并做性能追踪,便于控制 Test Runner 体积。
各平台产物目录约定由 scripts/binary/meta.ts 统一管理:macOS 为 build/mac(M1 为 build/mac-arm64)下的 Cypress.app,Linux 为 build/linux-unpacked(arm64 为 linux-arm64-unpacked),Windows 为 build/win-unpacked(见 meta.buildDir 实现)。
冒烟测试
构建完成后建议跑 yarn binary-smoke-test。对应 scripts/binary/index.js 的 smoke 方法:在无显示环境下自动启动 xvfb(xvfb.isNeeded()),然后执行 testExecutableVersion——调用构建产物的可执行文件加 --version(Linux 沙箱环境会追加 --no-sandbox),断言输出与构建版本一致,再对应用目录执行 scripts/binary/smoke.js 的冒烟测试。
打包(压缩)二进制
yarn binary-zip 的调用链是:deploy.zip → meta.zipDir(platform) 取待压缩目录 → zip.ditto(zipDir, zipPath)。scripts/binary/zip.js 按平台分派三种压缩工具:
| 平台 | 工具 | 命令要点 |
|---|---|---|
| Linux | zip |
cd <父目录> && zip -r9 <dest> Cypress(先 renameFolder 确保顶层目录名为 Cypress) |
| macOS | ditto |
ditto -c -k --sequesterRsrc --keepParent <src> <dest>,保留资源分叉并保留顶层目录 |
| Windows | 7-Zip |
7z a <dest> <src>,整个目录(含顶层 Cypress/)压入 |
其中 Linux 与 Windows 路径在压缩后会执行 checkZipSize(scripts/binary/zip.js#L70-L84):
const MAX_ALLOWED_SIZE_MB = os.platform() === 'win32' ? 295 : 256
zip 超过 256MB(Windows 295MB)直接抛错。源码注释特别叮嘱:修改这个上限前,先查清是什么导致了二进制体积增长,并在 PR 中说明。
发布流水线与 CDN 校验
yarn binary-deploy 走完整管线(scripts/binary/index.js#L417-L435):build → zip → upload。upload 将 zip 上传到 S3 的指定路径(upload.getFullUploadPath),随后通过 scripts/binary/util/upload.js 清理该版本的 Cloudflare 缓存。
发布完成后还有两级 CDN 校验(release 流程):
- 清单校验:
checkManifest拉取download.cypress.io/desktop.json,确认manifest.version与发布版本一致; - 下载校验:
checkDownloads对 5 个平台/架构组合(linux-x64、linux-arm64、darwin-x64、darwin-arm64、win32-x64)逐一HEAD请求确认二进制存在;若有缺失,提示用yarn binary-purge --version <v>清理 Cloudflare 缓存后再用yarn binary-ensure --version <v>复查(见 scripts/binary/index.js#L177-L242)。
实用技巧(指南 Tips 原文)
- 加速打包:设置
V8_SNAPSHOT_DISABLE_MINIFY=1可缩短二进制打包耗时。从源码看,该开关在 V8 快照工具的 tooling/v8-snapshot/src/setup/config.ts#L95 中被读取:const minify = !process.env.V8_SNAPSHOT_DISABLE_MINIFY && env === 'prod',即跳过生产环境对快照的压缩步骤以换取速度; - M1 芯片:在 M1 Mac 上打包后若要实际运行该二进制,需要设置
RESET_ADHOC_SIGNATURE=1来重置临时(adhoc)签名。
小结
Cypress 的发布产物由 npm 包与二进制 zip 双轨构成:npm 包只需递增版本并执行 yarn lerna run build-cli,产出进入 cli/build;二进制则通过 yarn binary-build(构建 dist 并做版本/静态资源自验证)、yarn binary-package(electron-builder 打包、平台签名与 GateKeeper 校验)、yarn binary-zip(平台化压缩并做体积上限检查)三步完成,再配合 binary-deploy、binary-smoke-test 与 CDN 清单/下载校验形成完整闭环。所有环节在 CI 中已自动化,本地执行时按本文命令即可复现;平台限制(不支持交叉构建、macOS 需签名证书、Linux 可走 docker)是实操中最需要留意的约束。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00