☰
js-framework-benchmark 中的 Sauron 基准测试:预编译产物使用与 Rust 源码级重建指南
2026/9/28 6:16:24 网站建设 项目流程
  • 性能测试
  • 开发者工具

【免费下载链接】js-framework-benchmark

A comparison of the performance of a few popular javascript frameworks

项目地址:https://gitcode.com/gh_mirrors/js/js-framework-benchmark
点击查看免费下载

本文以 frameworks/keyed/sauron/README.md 为核心骨架,结合该实现目录下的 Rust 源码、Cargo 配置与构建脚本,完整讲解如何在 js-framework-benchmark 仓库中直接使用 Sauron 基准测试的预编译产物,以及当需要从 Rust 源码重新构建时所需的工具链、命令与底层原理。读完本文,你将能独立完成 Sauron 基准的"零构建运行"与"源码重建"两条路径,并理解其 WASM 加载、Elm 风格架构与 keyed 渲染的实现细节。

为什么 Sauron 基准默认提供预编译产物

Sauron 是使用 Rust 编写的 Web 前端框架,编译目标为 WebAssembly。在 js-framework-benchmark 的 keyed 实现(frameworks/keyed/sauron)中,构建链条涉及 Rust 工具链、wasm32-unknown-unknown编译目标、wasm-pack打包工具等一系列重型依赖,完整编译成本较高。

因此该示例默认直接提供已编译产物:bundled-dist/目录中已经包含生成好的 JavaScript 引导代码与 WASM 二进制,使用者无需安装 Rust、无需执行任何编译命令即可运行基准测试。README 中明确写道:

Because of the heavy amount of Rust dependencies, this example is pre-compiled, so you don't need to compile anything.

这意味着在常规基准测试流程中,只需要通过仓库的本地服务器启动页面即可,构建脚本build-prod本身就是一个 no-op。

仓库结构与预编译产物

在 frameworks/keyed/sauron 目录下,关键文件包括:

  • src/lib.rs:Sauron 应用的完整 Rust 源码(唯一的业务源码文件);
  • Cargo.toml:Rust 包配置与依赖声明;
  • index.html:基准页面入口,加载 WASM 模块;
  • bundled-dist/:预编译产物目录,包含index.html、js-framework-benchmark-sauron.js与js-framework-benchmark-sauron_bg.wasm;
  • package.json:npm 脚本与基准元信息声明;
  • package-lock.json:npm 依赖锁定文件。

当前仓库中预编译产物的大小约为:WASM 二进制js-framework-benchmark-sauron_bg.wasm约 260 KB,JS 引导文件约 23 KB,两者合计约 280 KB。这可以作为观察 Sauron 应用在浏览器中加载体积的直观参考(具体数值会随源码与优化参数变化,请以仓库实际文件为准)。

由于产物已就绪,运行基准的路径非常简单:通过仓库根目录的本地服务器(如 server 模块提供的服务)访问对应 URL,让 webdriver-ts 基准驱动对页面执行创建、更新、选择等操作即可,无需任何额外构建。

两条构建路径:build-prod与build-prod-force

frameworks/keyed/sauron/package.json 中声明了三个 npm 脚本,构成"默认跳过构建"与"强制从源码重建"的两级策略:

"scripts": { "build-prod": "echo This is a no-op. && echo Due to heavy dependencies, the generated javascript is already provided. && echo If you really want to rebuild from source use: && echo npm run build-prod-force", "build-prod-force": "rustup target add wasm32-unknown-unknown && cargo install wasm-pack && npx build-prod-without-tools-install", "build-prod-without-tools-install": "rimraf bundled-dist && wasm-pack build --release --target web --no-typescript --out-name js-framework-benchmark-sauron --out-dir bundled-dist && cpr index.html bundled-dist/index.html && (cd bundled-dist && rimraf .gitignore README.md package.json)" }

各脚本含义如下:

  • npm run build-prod:默认构建入口,仅打印提示信息,实际不执行任何编译。它明确提示:由于依赖较重,已提供生成好的 JavaScript,如需从源码重建请执行npm run build-prod-force。
  • npm run build-prod-force:强制重建。依次完成三件事:
    1. rustup target add wasm32-unknown-unknown——为 Rust 工具链添加 WASM 编译目标;
    2. cargo install wasm-pack——安装wasm-pack打包工具(首次安装需要联网下载并编译,耗时较长);
    3. npx build-prod-without-tools-install——调用第三个脚本执行实际打包。
  • npm run build-prod-without-tools-install:在已具备工具链的前提下执行真实打包:先rimraf bundled-dist清理旧产物,再通过wasm-pack build --release --target web --no-typescript生成面向 Web 环境的发布版 WASM 模块,输出名为js-framework-benchmark-sauron;随后用cpr把index.html复制进bundled-dist/,并清理打包工具生成的.gitignore、README.md、package.json等冗余文件。

从源码重建的完整步骤

如果 README 中要求的依赖(Rust 工具链)已安装,重建流程即 README 中列出的两条命令:

npm install npm run build-prod-force

前提说明:build-prod-force内部会调用rustup与cargo,因此机器上必须先有可用的 Rust 工具链(安装方式参考 Rust 官方安装指南);首次运行还会执行cargo install wasm-pack,这一步需要较长时间,且在无网络或受限环境下会失败。此外wasm-pack还依赖一个可用的 WASM 目标编译环境,若rustup target add因网络问题失败,可预先手动添加。

构建命令参数详解

build-prod-without-tools-install中wasm-pack build的核心参数:

参数作用
--release使用 Cargo 的 release profile 编译,启用优化(对应Cargo.toml中[profile.release]的设置)
--target web生成面向浏览器原生 ES 模块的绑定,输出init默认导出函数,供<script type="module">直接import
--no-typescript不生成.d.ts类型声明文件,减小产物体积
--out-name js-framework-benchmark-sauron指定输出文件基名,最终得到js-framework-benchmark-sauron.js与js-framework-benchmark-sauron_bg.wasm
--out-dir bundled-dist输出目录

底层源码剖析:Elm 风格架构与 keyed 渲染

预编译产物的源头是 frameworks/keyed/sauron/src/lib.rs,它演示了 Sauron 的核心编程模型,属于典型的Elm 风格(Model–View–Update)架构:

  1. 状态(Model):App结构体持有rows: Vec<RowData>(行数据)、next_id(自增 ID 计数器)、selected_id(当前选中行)、rng: SmallRng(随机数生成器,用于生成标签文本)。
  2. 消息(Msg):enum Msg定义了Run(usize)、Add(usize)、Update(usize)、Clear、Swap、Remove(usize)、Select(usize)七类动作,与基准测试的按钮一一对应。
  3. 更新(update):impl Application for App中重写update(&mut self, msg) -> Cmd<Msg>,根据消息原地修改状态。例如Msg::Run(amount)会先覆盖已有行的前min(amount, rows.len())行,再追加剩余数量的新行(src/lib.rs)。
  4. 视图(view):重写view(&self) -> Node<Msg>,通过node!宏书写 JSX 风格的虚拟 DOM 描述,并调用view_jumbotron()渲染控制按钮区域(src/lib.rs)。

keyed 语义的关键:key属性

这是 keyed 分类实现的核心差异点:在行渲染函数RowData::view中,每个<tr>都显式携带key=id属性(src/lib.rs):

node! { <tr class={if selected { "danger" } else { "" }} key=id > <td class="col-md-1">{ text(id) }</td> <td class="col-md-4" on_click={move |_| Msg::Select(id)}> <a class="lbl">{ text(&self.label) }</a> </td> <td class="col-md-1"> <a class="remove" on_click={move |_| Msg::Remove(id) }> <span class="glyphicon glyphicon-remove remove" aria-hidden="true"></span> </a> </td> <td class="col-md-6"></td> </tr> }

key让 Sauron 的 diff 算法能够按稳定标识复用 DOM 节点,这正是"Swap Rows"等操作在 keyed 模式下被正确高效执行的前提。事件绑定同样在模板中声明:点击标签行触发Msg::Select(id),点击删除图标触发Msg::Remove(id)。

随机数据的生成

RowData::new从三组静态词表(ADJECTIVES、COLOURS、NOUNS)中各随机取一个词,拼接成形如"pretty red table"的标签(src/lib.rs)。随机数使用randcrate 的SmallRng,在Cargo.toml中通过features = ["small_rng"]启用。

应用挂载入口

#[wasm_bindgen(start)]标注的start()函数是 WASM 模块的启动入口:它通过sauron::document().query_selector("#main")找到挂载点,再调用Program::append_to_mount(App::new(), &mount_el)启动应用(src/lib.rs)。这个#main容器正是 frameworks/keyed/sauron/index.html 中定义的<div id='main'></div>。

Cargo.toml:面向 WASM 的发布优化配置

frameworks/keyed/sauron/Cargo.toml 中除了声明依赖(sauron = "0.61.4"、rand = { version = "0.8.5", features = ["small_rng"] }、getrandom = { version = "0.2.7", features = ["js"] })与crate-type = ["cdylib"](编译为 C 动态库形式,供 wasm-bindgen 链接)之外,还包含三组面向体积与性能的关键配置:

[profile.release] lto = true codegen-units = 1 panic = "abort" [package.metadata.wasm-pack.profile.release] wasm-opt = ['-O4']
  • lto = true与codegen-units = 1:开启全程序链接时优化、关闭并行代码生成单元,以获得更强的跨 crate 内联与死代码消除,代价是编译时间明显增加——这也是"重依赖、耗时编译"的一部分来源;
  • panic = "abort":将 panic 行为改为直接中止,省去 unwinding 相关运行时开销与体积;
  • wasm-opt = ['-O4']:让wasm-pack在构建完成后调用 Binaryen 的wasm-opt以最高优化等级(-O4)对 WASM 二进制做进一步体积与性能优化,这也是预编译产物体积得以控制的重要一环。

页面入口与 WASM 加载机制

frameworks/keyed/sauron/index.html 展示了 Sauron 基准页面如何加载 WASM:

<base href="bundled-dist/"></base> ... <div id='main'></div> <script type="module"> import init from './js-framework-benchmark-sauron.js'; await init().catch(console.error); </script>

要点如下:

  • <base href="bundled-dist/">使页面内的相对资源(包括模块脚本)都从bundled-dist/子目录解析,与预编译产物的存放位置一致;
  • 使用 ES Module 的顶层await调用wasm-pack --target web生成的默认导出init()完成 WASM 实例化;
  • 实例化时引导脚本通过fetch拉取js-framework-benchmark-sauron_bg.wasm(见 bundled-dist/js-framework-benchmark-sauron.js 中new URL('js-framework-benchmark-sauron_bg.wasm', import.meta.url)的默认路径解析),并利用WebAssembly.instantiateStreaming流式编译。

运行环境注意点

从预编译产物的引导代码可以看出两类运行时约束,实际部署或本地测试时需要留意:

  1. MIME 类型:WASM 文件必须以application/wasm的 Content-Type 提供服务,否则引导代码会回退到较慢的WebAssembly.instantiate路径(引导代码中对此有明确告警逻辑);js-framework-benchmark 的 server 模块提供了静态资源服务,可直接复用;
  2. 环境 API:引导代码会访问TextDecoder/TextEncoder(用于 Rust 与 JS 之间字符串传递)、crypto.getRandomValues(供getrandom在浏览器环境取随机种子)等浏览器 API,因此基准页面必须在现代浏览器或相应测试环境中运行,不能直接在纯 Node 环境执行。

与仓库基准体系的配合

Sauron 位于frameworks/keyed/分类下,其package.json中的js-framework-benchmark元信息声明了框架版本(frameworkVersion: 0.61.4)、语言(Rust)与仓库地址,供基准驱动读取。实际跑分由 webdriver-ts 模块通过浏览器自动化执行标准操作集(如 Create 1,000 rows、Update every 10th row、Swap Rows 等),这些操作的触发按钮 ID(run、runlots、add、update、clear、swaprows)都已在 src/lib.rs 的view_jumbotron()中按基准约定声明,与测试驱动一一对应。

总结

  • 日常使用基准:直接使用bundled-dist/预编译产物,无需安装 Rust 或执行任何编译命令;
  • 从源码重建:安装 Rust 工具链后依次执行npm install与npm run build-prod-force,后者会完成rustup target add wasm32-unknown-unknown、cargo install wasm-pack与wasm-pack build全流程;
  • 理解实现:src/lib.rs 展示了 Sauron 的 Model–View–Update 架构、node!模板宏与key属性驱动的 keyed 渲染;Cargo.toml 则揭示了面向 WASM 的发布级优化(LTO、panic = "abort"、wasm-opt -O4)。

如果你只是复现或对比基准结果,请记住第一条路径:开箱即用,零构建;只有当你想修改 Rust 源码、验证新版本 Sauron 或复现完整构建流程时,才需要走上第二条路径。

  • 性能测试
  • 开发者工具

【免费下载链接】js-framework-benchmark

A comparison of the performance of a few popular javascript frameworks

项目地址:https://gitcode.com/gh_mirrors/js/js-framework-benchmark
点击查看免费下载

相关推荐

上一篇:Raft共识算法Rust实现教程
下一篇:autoDocstring 使用教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询