ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Angular 仓库 Benchmarks 基准测试脚本:`pnpm benchmarks` 运行与结果对比实战指南

2026/9/9 22:08:32 拓冰建站 浏览量
Angular 仓库 Benchmarks 基准测试脚本:`pnpm benchmarks` 运行与结果对比实战指南 Angular 仓库 Benchmarks 基准测试脚本pnpm benchmarks运行与结果对比实战指南【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angularAngular 主仓库把一套可运行、可对比、可自动化触发的前端性能基准测试工具集中收拢在scripts/benchmarks目录并通过根目录package.json中的pnpm benchmarks一条命令对外暴露。本文面向需要在 Angular 框架本体上验证「改动是否带来性能回退」的贡献者与研究者完整讲解单次基准运行、本地双 SHA 对比、以及在 PR 里用/benchmark-compare评论触发 GitHub Actions 自动对比的完整链路同时结合仓库源码scripts/benchmarks/index.mts、targets.mts、results.mts剖析其底层实现原理。这套脚本解决什么问题官方文档对它的定位很明确这是一个「用于运行基准测试并进行对比的便捷脚本」。它本身不负责采集性能样本——真正的样本采集由 packages/benchpressAngular 的性能采样运行器完成测试代码则位于 modules/benchmarks/src。scripts/benchmarks扮演的是「总指挥」角色包装 Bazel 命令、解析命令行参数、发现可选基准目标、聚合并格式化输出结果、以及在对比模式下搭建隔离工作区。三个层级的职责划分见 contributing-docs/running-benchmarks.md目录/包职责modules/benchmarks/src存放各场景的基准测试代码如 tree、expanding_rows 等与 Bazel 目标scripts/benchmarks便捷脚本代码命令解析、目标发现、结果收集、对比编排packages/benchpressBenchpress 采样运行器负责真实测量与统计分析在根目录 package.json 中注册为benchmarks: node scripts/benchmarks/index.mts即pnpm benchmarks等价于直接执行 scripts/benchmarks/index.mts 这个 TypeScript 入口。由于仓库通过packageManager: pnpm11.24.0锁定包管理器见 package.json运行前需确保已按仓库约定使用对应版本 pnpm 安装依赖并完成 Bazel 环境配置。支持的子命令一览scripts/benchmarks/index.mts 基于yargs定义了三个子命令并启用了.demandCommand().strict()必须指定一个子命令、参数严格校验子命令功能命令行帮助中是否可见run [bazel-target]在本地运行单个基准测试可见run-compare compare-ref [bazel-target]在「当前工作区」与「指定 Git 引用如 main 或某个 SHA」之间做基准对比可见prepare-for-github-action comment-body供 GitHub Actions 工作流调用解析 PR 评论并解析/拉取对比 SHA隐藏false不出现在帮助里查看全部命令帮助pnpm benchmarks --help pnpm benchmarks run-compare --help运行单个基准测试pnpm benchmarks run最基本的用法是直接运行pnpm benchmarks run若未显式传入[bazel-target]脚本会调用promptForBenchmarkTarget()index.mts先用 Bazel 查询出仓库里所有可用的基准目标再借助inquirer/prompts的select弹出一个交互式列表供你挑选。对应实现是 scripts/benchmarks/targets.mts 中的kind(^js_test|^web_test, //modules/...) intersect attr(name, ^perf$, //modules/...)也就是说可发现目标被限定为位于//modules下、kind 属于js_test或web_test、且规则名以perf开头的目标。由此可以推断只有那些用perf命名的 Bazel 测试目标才是本脚本的调度对象。也可以一步到位直接指定目标跳过交互pnpm benchmarks run //modules/benchmarks/src/expanding_rows:perfrun的实际执行流程index.mts解析目标若传入的是短名/模式先用bazel query --outputlabel展开为完整标签见 targets.mts定位测试日志目录执行pnpm bazel test target并附带一组固定的测试标志从 Bazel testlog 收集并解析 JSON 结果最后在终端打印汇总。Bazel 目标发现与 testlog 定位的实现细节理解目标的「发现—解析—取日志」三段式逻辑能帮你排查执行过程中遇到的目标相关报错源码均在 scripts/benchmarks/targets.mts发现findBenchmarkTargets执行上面的bazel query按行拆分结果过滤空行后得到标签列表解析resolveTarget执行pnpm bazel query --outputlabel -- target把用户输入可能是未完全展开的标签规范化为唯一完整标签返回值带有ResolvedTarget品牌类型标记取日志路径getTestlogPath优先使用dist/testlogs/包路径/目标名的符号链接约定如dist/testlogs/modules/benchmarks/src/expanding_rows/perf若该目录不存在则回退到调用bazel info bazel-testlogs --lockfile_modeupdate查询真实输出根若查询失败再回退到dist/testlogs下的约定路径。结果文件位于 testlog 目录内的test.outputs/outputs.zipZIP 中散落各场景的 JSON 报告。基准测试完成前这些输出可能尚未生成这也是脚本必须先在本地bazel test跑通目标、再收集结果的原因。与本地改动做对比pnpm benchmarks run-compare官方文档给出两种对比命令pnpm benchmarks run-compare main pnpm benchmarks run-compare compare-sha [bazel-target]compare-ref位置参数既可以是main这样的分支名也可以是任意提交 SHA。同样地若省略[bazel-target]会弹出交互式选择框。run-compare的编排逻辑是 index.mts 中最复杂的部分其核心思想是让两份代码在完全一致的基准采集条件下各自跑一遍再并列输出结果。完整流程可拆为跑当前工作区记录当前分支/修订号对当前代码执行bazel test并收集结果确保对比提交可用先cat-file -e检查对比 SHA 是否已在本地若不存在则从上游仓库git fetch拉取创建隔离工作区在dist/benchmark-compare-temp下用git worktree add --detach检出对比 SHAdist/被 git 忽略不会污染仓库状态复制脚本与采样运行器把当前 PR/工作区的scripts/benchmarks和packages/benchpress覆盖到隔离工作区显式排除node_modules避免复制出损坏的相对符号链接。这一步让对比采用与当前工作区一致的基准框架代码从而把差异收敛到被测的框架实现本身同步本地配置复制.bazelrc.user不存在则创建空文件安装依赖在隔离工作区执行pnpm install --no-frozen-lockfile --prefer-offline。由于这是一个「混合工作区」main 代码 PR 脚本/lockfile会产生 lockfile 不匹配这也是基准测试统一附加--lockfile_modeupdate标志的原因跑对比版本并收集结果在隔离工作区再次bazel test同一目标收集其 testlog清理finally块中移除 worktree失败时用fs.rmSync兜底清理并worktree prune输出对比结论终端分别打印「Comparison reference」与「Working stage」两套结果。若在 GitHub Actions 环境检测process.env.GITHUB_ACTION中运行还会额外通过setOutput导出comparisonResultsText、workingStageResultsText两个 Markdown 格式的输出供工作流消费。# 与 main 分支对比交互选择目标 pnpm benchmarks run-compare main # 与某个 SHA 对比并指定 Bazel 目标 pnpm benchmarks run-compare a1b2c3d //modules/benchmarks/src/expanding_rows:perf在 PR 里用评论触发自动对比scripts/benchmarks/README.md明确指出该脚本与仓库里的 benchmark compare GitHub Actions 工作流配合使用允许 Angular 组织成员通过 PR 评论发起基准对比。评论格式在任意 PR 中添加如下格式的评论即可触发见 contributing-docs/running-benchmarks.md/benchmark-compare main //modules/benchmarks/src/expanding_rows:perf_chromium/benchmark-compare other-sha //modules/benchmarks/src/expanding_rows:perf_chromium注意必须显式提供基准目标无法省略。如果你不知道有哪些目标可用可以先在本地执行一次不带参数的pnpm benchmarks run通过交互提示列出所有可用目标作为参考。工作流实现对应配置为 .github/workflows/benchmark-compare.yml触发条件与保护措施包括触发器为issue_comment的created事件且job级别守卫要求评论来自 PRgithub.event.issue.pull_request且以/benchmark-compare开头通过团队会员校验动作确认评论者属于angular组织team团队未通过则直接退出给触发评论添加一个「rocket」反应表示命令已被接收检出评论对应的 PR 分支支持 fork检出源为head_owner/head_repohead_sha依次执行pnpm benchmarks prepare-for-github-action $COMMENT_BODY和pnpm benchmarks run-compare $COMPARE_SHA $BENCHMARK_TARGET最后把结果以评论形式回贴到 PR分「PR当前工作区 SHA」与「Compare Ref对比 SHA」两个区块展示。prepare-for-github-action做什么该隐藏命令负责把自然语言评论解析成机器可用的参数index.mtsconst matches /\/[^ ] ([^ ]) ([^ ])/.exec(commentBody);即把/命令 引用 目标中的引用与目标拆出然后输出三个值benchmarkTarget评论中声明的 Bazel 目标prHeadSha当前 HEAD即 PR 头提交的 SHA通过git rev-parse HEAD获取compareSha先尝试git rev-parse -- 引用在本地解析若失败则git fetch --depth1到上游仓库后取FETCH_HEAD解析。这样既支持 PR 内的提交也支持上游仓库中的任意提交。基准测试代码与 Bazel 目标是如何组织的所有可发现基准位于//modules下的js_test/web_test目标中典型入口是各目录下名为perf的规则。以 modules/benchmarks/src/expanding_rows/BUILD.bazel 为例一个完整基准场景由四类规则构成应用打包optimize_angular_app产出压缩后的 bundle再由genrule复制出约定命名的app_bundle.jsperf 库把*.perf-spec.ts基于 protractor 的测量规格编译成测试包静态服务http_serverprodserver在测试时承载被测页面基准测试通过benchmark_test(name perf, server :prodserver, deps [:perf_lib])组装。benchmark_test宏定义在 modules/benchmarks/benchmark_test.bzl其要点是用spec_bundle打包 perf-spec 源码并排除在常规 CI 之外manualtag底层展开为protractor_test且设置enable_perf_logging True这是 Benchpress 能拿到浏览器性能日志的关键目标统一追加benchmark-test、manual、no-remote-exectags——manual保证它默认不进普通bazel test //...no-remote-exec强制在本地机器执行以降低抖动。相关浏览器内手动预览与 e2emodules/benchmarks/README.md 补充了不依赖本脚本的开发方式# 浏览器内运行某个基准场景如 ng2 tree 基准 pnpm bazel run modules/benchmarks/src/tree/ng2:devserver # 跑某目录全部 e2e 测试 pnpm bazel test modules/benchmarks/src/tree/ng2/... # 跑所有 e2e 测试 pnpm bazel test modules/benchmarks/...仓库还保留*_aot.ts入口文件它们用于 Google 内部运行基准的入口并仍随对应的ng_module规则一起构建。通过环境变量控制测量行为每个基准目标默认执行完整的 Benchpress 采样流程。需要调整采样行为时可通过 Bazel 的--test_env注入以下变量见 modules/benchmarks/README.md环境变量作用默认值PERF_SAMPLE_SIZEBenchpress 通过简单线性回归在scriptTime不再下降前持续采样此变量指定回归所用的样本量20PERF_FORCE_GC设为true时在测量前后强制执行垃圾回收并额外测量与报告 GC 耗时未启用PERF_DRYRUN设为true时不打印结果、不落 JSON 文件且只做单次测量不做回归采样常用于快速验证链路可用性未启用官方示例dry-run 方式跑baseline树基准pnpm bazel test modules/benchmarks/src/tree/baseline:perf --test_envPERF_DRYRUNtrue这些变量最终由angular/benchpress读取并影响其采样策略——即 packages/benchpress 中样本采集器的工作方式。结果收集与两种输出格式无论run还是run-compare结果收集都复用 scripts/benchmarks/results.mts 中的collectBenchmarkResults优先读取 testlog 下的test.outputs/outputs.zip遍历其中的.json文件逐个JSON.parse并用「对象上是否存在completeSample字段」来判别是否为合法 Benchpress 报告isJsonReport无法解析或不合法的文件静默跳过若两个候选位置都找不到任何有效报告则抛出错误No valid benchpress benchmark reports found in testlogDir。一个 Bazel 基准目标内部可能包含多个场景scenario。每个场景报告取自description.id作为场景标识并同时生成两种摘要summaryConsoleText由metricsText、有效样本文本、statsText拼接而成用于本地/CI 终端展示summaryMarkdownText额外把完整样本用details折叠块包起来再置于正文前用于 GitHub Actions 评论这类 Markdown 消费方。最终在run-compare中若处于 GitHub Actions两个版本的 Markdown 结果会分别写入comparisonResultsText与workingStageResultsText由 .github/workflows/benchmark-compare.yml 回贴为 PR 评论。保证对比公平性的执行细节对比结果是否可信取决于两轮运行的条件是否一致。从源码注释与标志位可以看出设计者对可复现性的刻意安排index.mts。每次基准执行都会附加--cache_test_resultsno // 禁用测试缓存确保每次都真正执行 --coloryes // 输出带颜色 --cursesno // 关闭 curses 交互界面适配非 TTY --test_outputstreamed // 流式输出依赖可用 RBE 远程构建但测试在本地执行以降低波动 --lockfile_modeupdate // 混合工作区存在 lockfile 不一致允许 Bazel 在内存中更新 lockfile其中--test_outputstreamed的取舍尤其关键依赖构建可以走远程RBE加速但采样测试必须在本机串行执行避免多机 CPU 差异导致样本波动流式输出同时便于调试。适用前提与限制本文所有命令均基于当前仓库状态基准目标是走 Bazelpnpm bazel test执行的因此前提是先完成仓库的 Bazel/pnpm 环境搭建目标发现范围限于//modules下的perf命名目标仓库另设的 modules/ssr-benchmarksSSR 场景不在pnpm benchmarks的目标查询范围内如需覆盖请走其自身机制交互式目标选择依赖 TTY因此把pnpm benchmarks run-compare用于 CI 时必须像 GitHub 工作流那样显式传入目标否则无法弹出选择框。延伸阅读仓库内脚本说明与定位scripts/benchmarks/README.md官方基准使用指南contributing-docs/running-benchmarks.mdCLI 入口与三个子命令的实现scripts/benchmarks/index.mts目标发现/解析/testlog 路径scripts/benchmarks/targets.mts结果聚合与摘要格式scripts/benchmarks/results.mts进程执行封装含 shell 注入防护设计scripts/benchmarks/utils.mts基准场景组织方式与测量参数modules/benchmarks/README.md、modules/benchmarks/benchmark_test.bzl、modules/benchmarks/src/expanding_rows/BUILD.bazel基准对比的 GitHub Actions 工作流.github/workflows/benchmark-compare.yml基准采样运行器 Benchpresspackages/benchpress【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考