Farm 示例测试指南:用 test-examples 与 test-e2e 精确验证单个示例

📅 发布时间:2026/10/13 14:44:59
Farm 示例测试指南:用 test-examples 与 test-e2e 精确验证单个示例
前端构建构建工具开发工具【免费下载链接】farmExtremely fast Vite-compatible web build tool written in Rust项目地址https://gitcode.com/gh_mirrors/fa/farm点击查看免费下载Farm 是一个用 Rust 编写的现代 Web 构建工具仓库通过examples/目录下的数十个示例工程来持续验证编译核心、Rust 插件与 JS 插件的正确性。本文围绕仓库内的 示例测试指南系统讲解如何用scripts/test-examples.mjs精确构建单个示例或示例区间并深入剖析scripts/test-e2e.mjs的 E2E 编排、preview 产物新鲜度保障与陈旧进程清理机制帮助你快速定位构建失败、缓存回归与浏览器运行时错误掌握从构建验证到浏览器 E2E 验证的完整闭环。适用范围验证一个或一批示例scripts/test-examples.mjs是 Farm 仓库的示例构建验证入口它负责按顺序完成 CLI、runtime、core CJS、JS 插件的构建再逐个构建examples/下的示例工程。本文讲解的核心主题是如何只构建一个示例例如刚改完的rust-plugin-wasm如何从某个示例开始构建到末尾按示例名排序后的区间模式如何跳过 JS 插件构建以缩短非 JS 插件改动下的验证时间以及 E2E 阶段如何保证 preview 模式不会误服陈旧产物、如何清理上一次运行遗留的孤儿进程。该脚本在仓库根目录的package.json中以test-examples脚本注册见 package.json可通过pnpm run test-examples或直接node scripts/test-examples.mjs调用。整个执行逻辑位于 scripts/test-examples.mjs示例的实际构建编排函数buildExamples位于 scripts/build.mjs。前置条件在运行示例测试之前需要满足三个条件从仓库根目录运行脚本内部通过./examples、./packages/core等相对路径定位工程因此必须在仓库根目录执行即本仓库的gh_mirrors/fa/farm目录。依赖已安装执行pnpm install完成依赖安装。仓库使用 pnpm workspace 管理多个包packages/*、js-plugins/*、rust-plugins/*、examples/*根目录package.json中声明了packageManager: pnpm9.4.0与 Node.js20的引擎要求。非 JS 插件改动时使用--skip-build-js-pluginsJS 插件构建会遍历 js-plugins 下所有插件目录逐个执行构建buildJsPlugins见 scripts/build.mjs耗时较长。当你的改动不涉及 JS 插件时跳过该阶段可以显著缩短验证时间。快速开始两种典型用法只构建一个示例node scripts/test-examples.mjs --skip-build-js-plugins --example rust-plugin-wasm从某个示例构建到示例列表末尾node scripts/test-examples.mjs --skip-build-js-plugins --from rust-plugin-wasm两者的区别在于--example只构建指定这一个示例而--from会从指定示例开始一直构建到按字典序排序的示例列表末尾。示例列表的来源是 examples 目录下所有子目录的localeCompare排序见 scripts/build.mjs。参数映射命令行参数与环境变量原文档给出的参数映射如下仓库源码scripts/test-examples.mjs对其进行了完整实现参数含义说明--example name只构建一个示例支持--examplename写法也支持环境变量FARM_EXAMPLE--from name从给定示例构建到列表末尾别名--start-from支持--fromname/--start-fromname也支持环境变量FARM_EXAMPLE_START_FROM--skip-build-js-plugins跳过 JS 插件构建阶段别名--skip-build-js-plugin支持--skip-build-js-pluginstrue也支持环境变量FARM_SKIP_BUILD_JS_PLUGINS1/true从源码可以看出参数解析的细节--example与--examplename两种写法等价环境变量FARM_EXAMPLE兜底--from与--start-from互为别名parseStartFromArg会依次匹配--from name、--start-from name、--fromname、--start-fromname最后回退到FARM_EXAMPLE_START_FROM--skip-build-js-plugins的布尔解析要求值必须严格等于1或true不区分大小写环境变量同理。示例选择优先级原文档明确给出--example单示例模式优先其次是--from/--start-from区间模式默认行为构建全部示例。这一优先级在源码中同样成立buildExamples({ startFrom, example })先判断example命中则只取该示例否则再判断startFrom取区间最终回退到完整列表见 scripts/build.mjs。示例不存在时的校验脚本在真正开始构建前会对示例名做合法性检查读取./examples下所有目录若--from或--example指定的名称不在其中会直接抛出Example name was not found under ./examples该错误信息与文档中预期输出信号一节描述的完全一致且在buildExamples内部有第二层校验scripts/build.mjs。构建流水线与输出信号test-examples.mjs的构建顺序是固定的scripts/test-examples.mjsBuilding CLI...—— 构建packages/cliBuilding runtime...—— 构建packages/runtime及 runtime 插件runtime-plugin-hmr、runtime-plugin-import-metaBuilding core CJS...—— 构建packages/core的 CJS 产物若未跳过Building JS plugins...依据--from/--example打印提示Building examples from: name/Building only example: name逐个构建示例。单示例模式的预期输出信号Building only example: nameBuilding 1 examples...Building examples\name即Building examples/name脚本打印Building加示例路径以--example rust-plugin-wasm为例可以预期看到Building only example: rust-plugin-wasm、Building 1 examples...、Building examples/rust-plugin-wasm三行关键输出。值得说明的是buildExamples在构建每个示例前还会自动解析该示例的 Rust 插件依赖见 scripts/build.mjs凡是以rust-plugin-开头的示例名或示例package.json中声明了farmfe/plugin-*依赖脚本会先去 rust-plugins 下对应目录执行npm run build再用一个builtRustPlugins集合去重避免同一插件被重复构建在 CI 环境下若检测到已预构建的index.farm产物则会直接跳过插件构建以节省时间。故障排查定位是示例问题还是编排问题原文档给出了清晰的排查路径使用--example时却构建了另一个示例例如examples/arcgis请依次确认命令是否从仓库根目录执行命令使用的是--example而非只用了--from因为两者优先级不同若同时给出--from--example仍然优先但只传--from时不会进入单示例模式name是否与examples/下的目录名完全一致示例名是区分大小写且精确匹配的。命令以非零退出码结束时请检查第一个失败的示例构建日志如果失败发生在某个具体示例的npm run build阶段则多半是该示例自身的问题如依赖缺失、配置错误如果失败发生在Building CLI/Building runtime等前置阶段则是仓库编排层面的问题。E2E Preview 产物新鲜度writeToDisk 与预构建E2E 浏览器测试由 scripts/test-e2e.mjs 负责package.json中的test-e2e脚本还会先运行check-e2e-specs.mjs校验 spec 文件只做浏览器任务。原文档重点提醒了一个隐蔽的失败模式farm start服务的是当前源码而farm preview服务的是已存在的生产构建输出目录。如果该目录是由旧的源码/配置/缓存状态生成的preview 就会带着误导性的浏览器运行时错误失败——尽管 dev-server 模式完全通过。为此e2e/farm-runner.mjs中的startAndTest(examplePath, cb, preview)实现了按需预构建逻辑e2e/farm-runner.mjs它会遍历示例目录下的farm.config.ts、farm.config.mjs、farm.config.js等配置文件只有当配置中出现server.writeToDisk: true时才先执行npm run build再做 preview 测试其他示例跳过该预构建以保持 E2E 快速运行并避免重复示例构建流水线。仓库中开启writeToDisk: true的示例包括 examples/module-concatenation/farm.config.ts该示例同时使用concatenateModules: true、persistentCache: false、treeShaking: false和 examples/tailwind-next/farm.config.ts 等。这类示例在 dev server 运行期间会向磁盘写出类似生产构建的文件因此 preview 前必须重新构建避免服务到陈旧的 dev 产物。为什么预构建要保留并发原文档明确要求不要在 E2E 编排器中串行化这些预构建。原因在于预构建使用示例的常规持久缓存persistent-cache设置E2E 套件恰好要通过这些构建覆盖带缓存的并发生产构建这一场景而test-e2e.mjs正是通过多 worker 进程并行执行示例--concurrency/-j控制默认在 CI 下为 2、本地为 4见 scripts/test-e2e.mjs独立 worker 之间的并发构建本身就是缓存覆盖的一部分。陈旧 E2E 进程清理机制test-e2e.mjs在每次运行的前与后都会调用cleanupStaleE2EProcesses见 scripts/test-e2e.mjs 与 scripts/test-e2e.mjs实现在 e2e/process-cleanup.mjs判定规则属于上一次test-e2e进程树、且存活超过五分钟的进程会被终止覆盖范围包括孤立的 worker、dev-server、build 以及 Playwright Chromium 子进程平台差异Unix 平台按进程组清理先SIGTERM延时后SIGKILLWindows 平台按进程树清理taskkill /T /F孤儿 Chromium 处理当 Playwright Chromium 进程不再有所属父进程时也会被清理保护当前运行清理逻辑通过进程组 ID 与祖先进程链识别并跳过当前运行的进程确保不会误杀正在执行的测试可调阈值默认五分钟可通过环境变量FARM_E2E_STALE_PROCESS_SECONDS覆盖用于本地诊断。这套机制保证了每次运行相互独立不会因上次残留的 dev-server 占用端口或 Chromium 进程导致端口冲突与资源泄漏。缓存一致性调试marks 还原与 FARM_DISABLE_CACHE原文档给出了一个非常具体的调试建议在排查模块拼接module concatenation、tree shaking 或压缩minify问题之前先对比常规缓存构建与FARM_DISABLE_CACHE1构建。如果禁用持久缓存后e.replace is not a function之类的错误消失则应优先检查模块缓存的恢复路径module cache restore path而不是修改示例源码。这一现象在 Rust 侧的缓存恢复代码中有明确对应handle_cached_modules在恢复缓存模块时会重新创建 SWC 语法上下文crates/compiler/src/build/module_cache.rs// reset the mark to prevent the mark from being reused let (unresolved_mark, top_level_mark) resolve_module_mark( mut script.ast, cached_module.module.module_type.is_typescript(), context.meta.get_globals(cached_module.module.id).value(), ); script.top_level_mark top_level_mark.as_u32(); script.unresolved_mark unresolved_mark.as_u32();resolve_module_mark位于 crates/toolkit/src/script/swc_try_with.rs它先重置语法上下文ResetSyntaxContextVisitMut再调用 SWC resolver 生成全新的unresolved_mark与top_level_mark。关键要求缓存的 script 模块在恢复时必须把这两个 mark 还原到正确字段——top_level_mark来自 resolver 的top_level_markunresolved_mark来自 resolver 的unresolved_mark。如果两者被互换swap缓存构建就会生成运行时导出或 helper 不匹配看起来极像 minify 或模块拼接的 bug。ScriptModuleMetaData中这两个字段的定义见 crates/core/src/module/meta_data/script.rs。因此原文档强调在 E2E 中保留常规缓存、并发的 preview 构建正是为了让这一类缓存回归持续处于可观测状态而不是因为怀疑缓存就全局关闭它。与 E2E 测试体系的关系test-examples.mjs负责构建验证test-e2e.mjs负责浏览器验证两者相辅相成pnpm run test-e2e等价于node scripts/check-e2e-specs.mjs node scripts/test-e2e.mjs见 package.json其中check-e2e-specs.mjs会强制要求每个e2e.spec.mjs只通过startAndTest/watchAndTest或 Playwright 执行浏览器任务见 scripts/check-e2e-specs.mjsE2E 编排器将示例按轮询方式分发给多个 worker 进程每个 worker 启动一个常驻 headless Chromium见 scripts/test-e2e-worker.mjsspec 文件通过e2e/index.mjs导出的startAndTest、expect等 API 编写一个完整的示例可参考 examples/rust-plugin-wasm/e2e.spec.mjs——它同时覆盖start与preview两种模式并断言页面内容、控制台错误与失败请求均为零单示例运行方式pnpm run test-e2e -- --example name或--project name别名区间运行方式pnpm run test-e2e -- --from name与test-examples.mjs的参数风格保持一致e2e/README.md。小结Farm 的示例测试体系可以概括为一句话用test-examples.mjs精确控制构建范围、用test-e2e.mjs并行验证浏览器行为、用进程清理与缓存一致性检查兜底。当你面对一个preview 失败但 start 通过的诡异问题时优先按以下顺序排查确认示例是否开启writeToDisk决定 pre-preview 是否重新构建→ 对比FARM_DISABLE_CACHE1与常规缓存构建 → 检查module_cache.rs中top_level_mark/unresolved_mark的还原是否错位。这套方法论既适用于 Farm 源码贡献者也适用于依赖 Farm 生态做集成验证的开发者。赞分享前端构建构建工具开发工具【免费下载链接】farmExtremely fast Vite-compatible web build tool written in Rust项目地址https://gitcode.com/gh_mirrors/fa/farm点击查看免费下载相关推荐examples/test-extension/skills/e2e-test-skill/SKILL.mdexamples/test extension/skills/e2e test skill/SKILL.md name: E2E Extension Skill人工智能AI 应用大模型AI Agent交互助手前端MagiskBoot 完整指南如何快速解包与重打包 Android 启动镜像 boot.imgMagiskBoot 完整指南如何快速解包与重打包 Android 启动镜像 boot.img MagiskBoot 是 Magisk 的命令行工具专门用来移动开发系统底层Handsontable 视觉测试示例Visual Test Examples创建指南基于 Vite 的多功能演示脚手架实战Handsontable 视觉测试示例Visual Test Examples创建指南基于 Vite 的多功能演示脚手架实战 本篇指南面向需要在 Hand前端UI组件上一篇5分钟导出QQ空间全部历史说说GetQzonehistory 完整使用教程下一篇Bracket把一届完整赛事搬上线的自托管赛程管理系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考