
Next.js 中 turbopack-benchTurbopack 基准测试套件的运行方法、六大场景与源码剖析【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js本文基于 Next.js 仓库内 turbopack/crates/turbopack-bench/README.md 展开完整介绍 Turbopack 官方基准测试套件的运行命令、环境变量与六大测试场景并结合 benches/mod.rs、src/lib.rs 等源码剖析其如何用真实无头浏览器测量启动、Hydration 与 HMR 性能以及如何与 Vite、Webpack、Rspack、Parcel 等其他打包器进行同场对比。读完后你将能够独立运行、筛选该基准套件并理解每个指标的确切测量口径。一、快速开始运行 Turbopack 基准套件最简单的方式是在仓库根目录执行cargo bench -p turbopack-bench该命令会针对 Next.js 开发服务器在多种场景下对 Turbopack 进行基准测试也是 Next.js 团队用来长期跟踪 Turbopack 性能表现的官方手段。基准套件的被测模块数量通过环境变量TURBOPACK_BENCH_COUNTS调整。默认值为 1,000 个模块见 src/lib.rs#L531-L533 中get_module_counts()的默认值vec![1_000]。若要测试一个包含 5,000 个模块的应用运行TURBOPACK_BENCH_COUNTS5000 cargo bench -p turbopack-bench该环境变量按“逗号分隔列表”解析见 src/util/env.rs 中read_env_list的实现因此也可以传入多个档位让同一轮基准在多个模块规模下各跑一组。二、六大基准场景每个指标到底在测什么README 定义了六个场景对应 benches/mod.rs#L32-L37 中注册到 criterion 的六个目标函数。测试会使用真实的无头浏览器执行常见的 Web 开发场景并等待结果真正反映到页面上而不是仅测量服务器侧事件基准场景测量内容备注bench_startup从冷启动无缓存到应用渲染进浏览器的耗时不要求可交互/完成 Hydrationbench_hydration从冷启动无缓存到应用在浏览器中可交互完成 Hydration的耗时CSR 场景不采集此指标因为首次渲染本身就是可交互的bench_hmr_to_eval从修改文件到新代码在浏览器中被求值evaluate的耗时代码被求值不代表用户已看到变化例如 React 组件还需重新渲染该指标主要度量打包器自身计算更新并下发到客户端的时间bench_hmr_to_commit从修改文件到变化真正反映到浏览器 DOM 的耗时通过 React 组件中的useEffect钩子测量更新组件提交commit到 DOM 的时间是用户端到端感知性能的良好代理bench_startup_cache从带文件系统缓存的启动到应用渲染进浏览器的耗时默认禁用可通过TURBOPACK_BENCH_CACHED1启用Turbopack 当时尚未内置文件系统缓存bench_hydration_cache从带文件系统缓存的启动到应用可交互的耗时默认禁用TURBOPACK_BENCH_CACHED1启用CSR 场景同样不采集关于缓存场景有一个 README 原文细节其列表最后一项写作 “bench_hydration”但从源码看src/lib.rs#L425-L439实际的 benchmark 组名为bench_startup_cached与bench_hydration_cached即原文档此处是笔误以源码为准。源码层面这六组场景的测量参数完全一致每组sample_size(10)至少 10 个样本、measurement_time(60 秒)见 src/lib.rs#L34-L48。这也解释了后文 README 的提示——基准跑得久是因为每个场景都要尽量采集至少 10 个样本。缓存场景默认直接跳过src/lib.rs#L441-L448 中bench_startup_cached_internal首先检查TURBOPACK_BENCH_CACHED未设置时立即返回。其测量流程是“完整构建一次 → 等待 4 秒让缓存落盘 → 停服 → 重复启动并计时”对应 src/lib.rs#L487-L523。三、用同一套件对比其他打包器README 说明Turbopack 官网公布的基准数字来自在受控环境中让 Turbopack 基准套件同时跑 Turbopack 与其他打包器目前对外公布的指标使用bench_startup与bench_hmr_to_eval两个基准。对比其他打包器的命令是加上-p turbopack-clicargo bench -p turbopack-bench -p turbopack-clicriterion 支持用正则过滤要运行的基准例如只跑 CSR 场景下 Turbopack 与 Vite 的 HMR 求值对比cargo bench -p turbopack-bench -p turbopack-cli -- hmr_to_eval/(Turbopack CSR|Vite)或锁定某个具体套件与打包器cargo bench -p turbopack-bench -- bench_hydration/Next\.js canary Turbo RSC这些基准名并非凭空而来每个基准项的 ID 由bundler.get_name()与模块数拼接而成见 src/lib.rs#L85-L87 的BenchmarkId::new(bundler.get_name(), format!({module_count} modules))。而打包器名称清单则来自 src/bundlers/mod.rs#L75-L217 的get_bundlers()当前套件覆盖Next.jsCanary / 14 / 13 / 12 四个版本分别以next dev --turboTurbopack或默认 webpack 编译器运行并分三个路由模式命名SSR/pageServerSidePrerenderedRSC/appServerSideRenderedWithEvents即 App Router React Server ComponentsRCC/client客户端组件Vite三种变体对应Vite::new(false, false)、Vite::new(true, false)、Vite::new(false, true)在基准名中体现为 Turbopack CSR|Vite 等过滤正则可匹配的形态Parcel、Webpack、Rspack各一个各打包器的配置文件随源码提供例如 next.config.js、vite.config.js、webpack.config.js、rspack.config.js。CSR 与 SSR 的口径差异README 原文强调基准套件混合了服务端渲染与纯客户端渲染的示例这体现在基准名中的 CSR 或 SSR 字样。Turbopack 两者都支持而部分其他打包器只支持客户端渲染示例。对比 CSR 结果与 SSR 结果时必须考虑这一差异。从源码看这一差异被显式编码在 src/bundlers/mod.rs#L19-L31 的RenderType枚举中ClientSideRendered/ServerSidePrerendered/ServerSideRenderedWithEvents/ServerSideRenderedWithoutInteractivity并在 src/lib.rs#L58-L80 中决定每个打包器是否需要等待 hydration 事件对 CSR 打包器startup 本身就等价于到 hydration 的时间因此bench_hydration直接跳过它——这正是 README 所说“CSR 不采集 hydration 指标”的实现。进度提示README 原文 Hint这些基准耗时很长因为要争取每个场景至少 10 个样本。可以设置TURBOPACK_BENCH_PROGRESS1在运行中实时显示数值。源码中该开关控制 setup/routine/teardown 各阶段的eprint!输出见 src/util/mod.rs#L164-L231HMR 场景还会按 2 的幂次迭代点打印当前样本均值与累计 dropped 更新数src/lib.rs#L303-L315。四、环境变量速查含源码中额外出现的开关README 明示了两个环境变量源码中还有几个未写入 README 的实用开关一并汇总环境变量作用出处TURBOPACK_BENCH_COUNTS被测应用模块数量逗号分隔列表默认1000README、src/lib.rs#L531-L533TURBOPACK_BENCH_PROGRESS1运行时显示实时测量值README、src/util/mod.rsTURBOPACK_BENCH_CACHED1启用默认的缓存版基准bench_startup_cached / bench_hydration_cachedREADME、src/lib.rs#L446-L448TURBOPACK_BENCH_HMR_WARMUPHMR 基准的预热改动次数默认 10src/lib.rs#L152TURBOPACK_BENCH_WITH_HEAD1以有头模式启动浏览器便于观察src/util/mod.rs#L89-L99TURBOPACK_BENCH_DEVTOOLS1浏览器自动打开 DevToolssrc/util/mod.rs#L91TURBOPACK_BENCH_IGNORE_ERRORS非--bench模式下捕获 panic、不中断后续基准src/util/mod.rs#L124-L135注意布尔型环境变量的解析规则比较宽松只要值不是0/no/false/空就视为真见 src/util/env.rs#L22-L28。五、源码剖析基准是怎么测的5.1 整体架构criterion 真实 ChromiumCargo.toml 显示该 crate 依赖criterionasync_tokio特性、chromiumoxidetokio-runtime特性、tokio、portpicker等。src/util/mod.rs#L89-L122 的create_browser()通过 CDP 协议启动真实无头浏览器默认no_sandbox失败时重试 3 次。每个基准项内部通过PreparedApp完成“复制测试工程 → 启动打包器 dev server → 打开页面 → 等待信号”的闭环见 src/util/prepared_app.rs#L84-L118。测试应用由turbopack-create-test-app生成src/util/mod.rs#L56-L87 的build_test()按指定模块数构建工程目录数为module_count / 20随后执行npm install并按打包器执行各自的prepare()安装对应框架版本。对 Next.js 而言prepare()会npm install指定版本的next并在 App Router 场景下写入 next.config.js见 src/bundlers/nextjs/mod.rs#L74-L88。5.2 启动与 Hydration 测量bench_startup/bench_hydration共用bench_startup_internalsrc/lib.rs#L50-L118每次迭代都把测试工程复制到临时目录保证缓存冷态→ 启动 dev server → 打开页面 → 按渲染类型决定是否wait_for_hydration()。hydration 判定依赖页面内 JS 调用__turbopackBenchBinding(Hydration done)由 src/util/page_guard.rs#L81-L91 以 120 秒超时等待该 CDP binding 事件。计时只覆盖start_server到信号到达的墙钟时间。Next.js dev server 的启动细节也值得注意src/bundlers/nextjs/mod.rs#L90-L136直接用node node_modules/next/dist/bin/next dev --port 0Turbopack 场景追加--turbo启动然后从 stdout 中正则解析本地地址其中 Next.js 12 因“port 0 被忽略回落到 3000”的历史 bug改用portpicker显式选端口。5.3 HMR 测量pragma 注入 CDP binding 回调bench_hmr_to_eval与bench_hmr_to_commit共用bench_hmr_internalsrc/lib.rs#L142-L337区别仅在CodeLocation是Evaluation还是Effect。核心测量循环make_changesrc/lib.rs#L388-L423准备阶段计时外insert_codesrc/lib.rs#L339-L384随机选中一个模块在/* turbopack-bench:eval-start */与/* turbopack-bench:eval-end */两个 pragma 之间替换代码。Evaluation位置对应 bench_hmr_to_eval注入globalThis.__turbopackBenchBinding(TURBOPACK_BENCH_CHANGE_N);即模块被求值时立刻回调Effect位置对应 bench_hmr_to_commit注入EFFECT_PROPS.message ...由测试应用中的useEffect在组件提交到 DOM后触发回调——这就是 README 所说“用useEffect钩子测量 commit 时间”的实现。对在服务端求值的打包器SSR 无客户端事件类Evaluation无法测量会直接跳过src/lib.rs#L154-L164对应 README 中“CSR 不采集 hydration 指标”的同类口径处理。计时开始把新内容fs::write落盘随后wait_for_binding等待页面通过 CDP 上报该消息src/util/page_guard.rs#L64-L79超时即记为失败并计入 dropped。防误报基准开始前在页面置globalThis.HMR_IS_HAPPENING truesrc/lib.rs#L200-L206teardown 时断言它仍为真src/lib.rs#L321-L331确保测的确实是 HMR 更新而不是整页刷新。预热与容错先用指数退避起点 100ms翻倍至打包器给定的初始超时发出第一次改动确认 HMR 连接已建立随后执行TURBOPACK_BENCH_HMR_WARMUP默认 10次预热改动正式迭代中若更新被丢弃Turbopack 与 Vite 在特定条件下会丢弃更新代码注释明确说明只累计 dropped 数并继续不中断基准。确定性选模块ModulePickersrc/util/module_picker.rs以固定种子 42 初始化随机数并按“深度均匀分布”随机挑选待修改模块使跨次运行具有一定可复现性。Linux 特殊处理make_change末尾在 Linux 上强制休眠max(duration, 100ms)注释说明“在 Linux 上触发 HMR 更新过快会有奇怪副作用”src/lib.rs#L418-L421。各打包器还有自己的 HMR 超时策略max_init_update_timeout默认 60 秒、max_update_timeout默认 5 秒src/bundlers/mod.rs#L60-L72Next.js 的 Turbo ServerSidePrerendered 组合把更新超时压到 500mswebpack 系则按5000ms module_count/2计算src/bundlers/nextjs/mod.rs#L138-L145体现“更新通常应很快不想在更新被丢弃时长时间等待”的设计意图。六、适用前提与注意事项该套件面向Next.js 仓库内的 Turbopack 开发场景运行需在 Rust 工作区内执行cargo benchHMR 基准还会自动npm install生成测试工程并启动真实 dev server 与 Chromiumchromiumoxide依赖因此环境需要 Node.js 与 npm 可用。缓存版基准TURBOPACK_BENCH_CACHED1默认关闭且 README 明确当时的前提Turbopack 尚未内置文件系统缓存结果解读需结合这一背景。对比不同打包器时务必注意基准名中的 CSR/SSR 标记与渲染类型的差异同一指标只在相同渲染口径下才有可比性。由于每组基准sample_size(10)且measurement_time为 60 秒全量运行尤其叠加多个TURBOPACK_BENCH_COUNTS档位耗时可观建议按第三节的方式用正则只跑关心的子集并配合TURBOPACK_BENCH_PROGRESS1观察进度。综上turbopack-bench是一个“criterion 统计框架 真实浏览器黑盒信号CDP binding”的组合对外以 README 描述的命令与环境变量驱动对内以 src/lib.rs 的统一计时循环把“启动、hydration、HMR 求值、HMR 提交”四类开发体验指标量化到可跨打包器对比的口径上是理解 Next.js 如何工程化地衡量并持续改进 Turbopack 性能的典型入口。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考