ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从预编译到源码重建:js-framework-benchmark 中 Dominator(Rust/WASM)基准实现的构建与源码剖析

从预编译到源码重建:js-framework-benchmark 中 Dominator(Rust/WASM)基准实现的构建与源码剖析 性能测试开发者工具【免费下载链接】js-framework-benchmarkA comparison of the performance of a few popular javascript frameworks项目地址https://gitcode.com/gh_mirrors/js/js-framework-benchmark点击查看免费下载本篇指南围绕 frameworks/keyed/dominator/README.md 展开讲解 js-framework-benchmark 中基于 Rust 编写的 Dominator 实现为何默认以预编译产物交付以及如何在本地从源码重新构建Rust nightly wasm-pack webpack 管线并深入剖析其响应式数据模型Mutable / MutableVec、六个基准操作的实现方式与 keyed 语义。读完本文你将掌握该实现零编译即用与强制重建两条使用路径并理解其从src/lib.rs到bundled-dist的完整编译链路。概述一个因依赖繁重而默认预编译的 Rust/WASM 实现原 README 开篇即点明核心事实由于 Rust 依赖数量庞大该示例默认以预编译形式提供使用前无需执行任何编译操作。这与仓库中大多数以 JavaScript/TypeScript 编写的实现如 vanillajs、react-hooks 等直接npm run build-prod即可形成了鲜明对比——Dominator 需要完整的 Rust 工具链、nightly 编译器和 wasm-pack 才能从源码产出 WASM因此官方将构建产物直接提交进仓库。在 package.json 中可以看到与此对应的设计build-prod被显式声明为一个no-op空操作脚本内容为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不会触发任何编译它只是提示使用者产物已随仓库提供若确需从源码重建请使用npm run build-prod-force。这正是本实现区别于其他框架实现的核心使用模式。目录结构速览该实现的核心文件全部位于frameworks/keyed/dominator/目录下构成一条完整的Rust 源码 → WASM → webpack 打包 → 浏览器加载链路路径作用src/lib.rs唯一的 Rust 源码状态模型、响应式渲染与全部基准操作Cargo.tomlRust 工程配置依赖版本、release 优化项、cdylib 输出js/index.jswebpack 入口动态加载 wasm-pack 生成的pkg模块index.html页面骨架挂载点#main与产物脚本引用webpack.config.js构建管线wasm-pack 插件 产物输出目录配置bundled-dist/预编译产物index.jswebpack bootstrap与.module.wasm分块package.jsonnpm 脚本与js-framework-benchmark元信息frameworkVersion 0.5.0、language: Rust直接使用预编译产物零编译即用仓库中已提交的 bundled-dist/index.js 是 webpack 的生产打包结果同目录下还包含1.js与accca9b65c226d0a493c.module.wasmWASM 二进制分块。从打包代码可以看到其运行机制index.js是 webpack 的 bootstrap 运行时负责异步加载分块并实例化 WASM内部通过WebAssembly.compileStreaming/instantiateStreaming流式编译若不支持则回退到arrayBuffer()后实例化入口模块执行t.e(1).then(t.bind(null,1)).catch(console.error)即加载编号为 1 的 chunk页面 index.html 仅需两处关键代码即可运行div idmain/div script srcbundled-dist/index.js/script这印证了 README 的第一句话拿到仓库后不需要 Rust、不需要 wasm-pack、不需要 nightly只要用仓库根目录的静态服务器把页面跑起来#main就会被 Dominator 渲染出的表格填满。对只想跑基准、不关心编译细节的使用者而言这一步已经完成。从源码重新构建前置环境README 明确给出了两条前置工具要求缺一不可Rust 工具链含rustup用于编译src/lib.rswasm-pack用于把编译产物封装为 npm 可消费的pkg/模块wasm-bindgen的 JS 胶水层。需要特别说明原 README 中指向 Rust 官网与 rustwasm 官方文档的链接本文以工具名形式呈现安装方式以各工具官方文档为准。此外该构建依赖nightly 工具链原因见下文为什么要 nightly小节这是与多数仅需 stable 的 Rust 项目不同的地方。四步构建命令详解原文档核心步骤完整继承在安装好上述工具后README 提供的完整构建流程为rustup toolchain install nightly rustup override set nightly npm install npm run build-prod-force逐条说明其作用与注意点第 1 步安装 nightly 工具链rustup toolchain install nightly下载安装 nightly 版本的 Rust 工具链。之所以必须用 nightly是因为该实现使用的wasm-bindgen/wasm-pack相关特性与依赖组合见 Cargo.toml 中的版本组合在工程编写时期依赖 nightly 的编译特性stable 无法保证一致产出。第 2 步为当前目录锁定 nightlyrustup override set nightly会在frameworks/keyed/dominator/目录下写入目录级覆盖rust-toolchain 机制使在该目录下执行任何cargo命令时自动使用 nightly而不影响系统其他项目的默认工具链。这是避免明明装了 nightly 却仍用 stable 编译的关键一步。第 3 步安装 npm 依赖npm install安装 package.json 中声明的开发依赖核心三件套为wasm-tool/wasm-pack-plugin^0.4.2webpack 插件自动调用 wasm-pack 编译 Rust cratewebpack^4.35.0与webpack-cli^3.3.5JS 打包与 CLI 入口rimraf^2.6.3跨平台删除目录用于清理旧产物。第 4 步强制重建npm run build-prod-force实际执行的是见 package.json 的 scripts 定义build-prod-force: rimraf bundled-dist pkg webpack即先删除旧的bundled-dist/与pkg/目录pkg/是 wasm-pack 生成的中间产物被 git 忽略或已清理js/index.js通过import(../pkg/index.js)动态引用它随后由 webpack 驱动完整的编译打包流程。命令名称中的 force 恰当地表达了绕过预编译、强制从源码重建的语义。构建管线底层拆解webpack 配置wasm-pack 插件的接入方式webpack.config.js 是整个构建管线的指挥中枢关键配置如下const dist path.resolve(__dirname, bundled-dist); module.exports { mode: production, entry: { index: ./js/index.js }, output: { path: dist, publicPath: bundled-dist/, filename: [name].js }, plugins: [ new WasmPackPlugin({ crateDirectory: __dirname, extraArgs: --out-name index }) ] };entry 指向js/index.js而该文件只有一行import(../pkg/index.js).catch(console.error)即 webpack 的入口实际是等待 wasm-pack 产物就位后再动态加载的异步导入WasmPackPlugin的crateDirectory: __dirname让插件把当前目录当作 Rust crate 根目录即读取 Cargo.toml自动执行wasm-pack buildextraArgs: --out-name index将 wasm-pack 输出命名为index与 js/index.js 中import(../pkg/index.js)的引用路径严格对应——改动这个参数会导致动态导入找不到模块output.publicPath: bundled-dist/决定了运行时异步分块与 WASM 的加载前缀与 index.html 中script srcbundled-dist/index.js的目录保持一致。Cargo.toml依赖与 release 优化src 的工程配置 体现了 WASM 基准实现的两个典型优化取向[profile.release] lto true # 链接期优化减小 WASM 体积 panic abort # panic 直接中止避免 unwinding 开销 [lib] crate-type [cdylib] # 产出可供 wasm-bindgen 消费的动态库依赖方面核心组合为dominator 0.5.0声明式 DOM 库提供html!宏与Dom类型futures-signals 0.3.6提供Mutable/MutableVec等响应式信号原语wasm-bindgen 0.2.46、js-sys 0.3.23、wasm-bindgen-futures 0.3.24启用futures_0_3特性与 JS 运行时互操作web-sys 0.3.23仅启用Window、Document、Element三个特性把 WASM 体积控制在最小必要范围。正是这些 Rust 生态依赖含传递依赖构成了 README 所述heavy amount of Rust dependencies也是官方选择提交预编译产物的直接原因。为什么要 nightly从工程事实推断虽然 Cargo.toml 中未显式声明rust-version但 README 明确要求先rustup toolchain install nightly并rustup override set nightly。从源码结构看该工程并未使用明显的 unstable 语法如 GAT、let else等可以推断 nightly 要求主要源于该版本dominator 0.5.0 / wasm-bindgen 0.2.46 / futures-signals 0.3.6当时依赖链对 nightly 编译特性的需要而非源码本身的语法诉求。实际工程中以 README 指定的 nightly 为准若遇到编译报错优先检查工具链版本是否与依赖锁定版本匹配。应用实现剖析src/lib.rssrc/lib.rs共 291 行是整个基准实现的核心其设计遵循响应式状态 声明式渲染的 Dominator 惯用风格。结构上分为三部分数据模型、状态操作、渲染与启动。数据模型行Row与状态StateRow结构体src/lib.rs保存单行数据struct Row { id: usize, label: MutableString, }id来自静态原子计数器ID_COUNTER: AtomicUsize初始值为 1每次fetch_add(1, Ordering::SeqCst)严格递增且永不重置除非页面刷新这是满足基准 keyed 语义的关键详见下文label用MutableString包裹意味着修改 label 只会触发与该字段绑定的 DOM 文本更新而非整行重渲染。State结构体src/lib.rs是全局应用状态struct State { rows: MutableVecRcRow, selected_row: MutableOptionusize, }rows: MutableVecRcRow响应式行集合Rc使行可以在多个闭包间共享而不复制selected_row: MutableOptionusize当前选中行的 id。注意这里只保存一个引用值而非每行一个选中标记符合仓库 README.md 中对实现风格的要求将选中行保存在状态中、避免逐行布尔标志否则会被标记为不符合规范的问题实现。六个基准操作与按钮映射js-framework-benchmark 的核心是一组固定的用户操作create / runlots / add / update / select / clear / swaprows / remove本实现将它们一一映射为State的方法与页面按钮 id按钮 id页面文案State 方法源码位置runCreate 1,000 rowscreate(1_000)src/lib.rsrunlotsCreate 10,000 rowscreate(10_000)同上addAppend 1,000 rowsappend(1_000)src/lib.rsupdateUpdate every 10th rowupdate()src/lib.rsclearClearclear()src/lib.rsswaprowsSwap Rowsswap()src/lib.rs行内点击选择行 / 删除行select_row(id)/remove_row(id)src/lib.rs各方法内部大量使用lock_mut()获得可变引用后批量操作例如append循环rows.push_cloned(Row::new())追加create一次性生成count个新行后replace_cloned整体替换保证整表替换为一次信号变更updateiter().step_by(10)遍历每第 10 行对label执行push_str( !!!)——只更新文本信号验证了部分更新基准的真实开销集中在 DOM 文本层swap当行数大于 998 时用move_from_to(1, 998)与move_from_to(998 - 1, 1)交换第 2 行与倒数第 2 行属于MutableVec的原地移动操作remove_rowretain按 id 过滤实现单行删除clear清空rows并将selected_row重置为None。响应式渲染信号驱动的 DOM 更新渲染层全部由html!宏与信号绑定构成展示了 Dominator 的典型写法src/lib.rs整表渲染render_table中tbody使用.children_signal_vec(state.rows.signal_vec_cloned().map(...))即把MutableVec变成响应式子节点流任何增删改都会精确映射为对应 DOM 节点的插入/移除/更新而非整表重绘选中态高亮tr使用.class_signal(danger, state.selected_row.signal_ref(...))当selected_row变化时仅切换目标行的dangerclass文本更新行的 label 链接使用.text_signal(row.label.signal_cloned())对应 update 基准中的每第 10 行文本刷新。按钮组件本身src/lib.rs是一个泛型辅助函数通过.event(move |_: events::Click| on_click())绑定点击事件并通过clone!(state ...)宏把RcState克隆进闭包规避 Rust 生命周期与所有权问题——这是Rc状态 事件闭包组合的惯用模式。启动入口与 DOM 挂载WASM 入口使用#[wasm_bindgen(start)]标记src/lib.rs#[wasm_bindgen(start)] pub fn main_js() { let state State::new(); let element window().unwrap_throw().document().unwrap_throw() .get_element_by_id(main).unwrap_throw(); dominator::append_dom(element, State::render(state)); }流程清晰创建State→ 通过web-sys拿到#main元素与 index.html 中的挂载点对应→ 调用dominator::append_dom把整棵响应式 DOM 树挂载进页面。整个渲染树由render_jumbotron操作按钮区render_table表格 隐藏的 glyphicon 预加载元素组成其中预加载 span 是仓库 README.md 对全部实现的一致要求用于避免字体图标首次出现时的性能抖动。keyed 语义与基准规范的一致性本目录名为keyed意味着数据项与 DOM 节点必须保持 1:1 对应、按 id 追踪。从源码可以确认两个关键事实id 唯一且单调递增Row::new()中的原子计数器从 1 开始永不重置与仓库 README.md 对新增实现的要求id 初始化为 1 并持续递增页面刷新才重置完全一致保证 keyed 测试能稳定定位到指定行选中状态采用单引用而非逐行标志State.selected_row只保存一个Optionusize行的高亮完全由该信号派生符合仓库对实现风格的要求不把选中标志挂在每行上这也是 src/lib.rs 中class_signal设计的原因。如何在本地查看与验证由于build-prod是 no-op直接使用预编译产物即可查看页面在仓库根目录安装顶层依赖并启动本地静态服务器按仓库 README.md 的做法npm ci npm run install-server随后npm start浏览器访问http://localhost:8080/frameworks/keyed/dominator/页面应出现带 Bootstrap 样式的操作按钮区与空白表格点击各按钮可即时看到 1,000/10,000 行创建、追加、部分更新、交换、清除与行选择/删除效果。若需要从源码重建则按上文四步构建命令详解依次执行成功后 bundled-dist/ 会被重新生成页面行为应与预编译产物一致。常见问题与注意事项不要手动执行 wasm-pack构建由 webpack 的WasmPackPlugin自动触发无需也不应手动wasm-pack build避免输出路径与--out-name index约定不一致导致 js/index.js 的动态导入失败nightly 是硬性要求跳过rustup override set nightly会导致工具链回落到 stable可能出现依赖编译错误pkg/目录是中间产物build-prod-force先rimraf bundled-dist pkg再重建若构建中途失败检查pkg/index.js是否已生成它是 JS 侧加载 WASM 的胶水层产物完整性预编译的bundled-dist/包含index.js、1.js与.module.wasm三部分部署或归档时三者必须同时存在缺一会导致运行时按需加载失败性能取向Cargo.toml 中的lto true与panic abort是为减小 WASM 体积、提升运行性能而设属于该实现可被复用的工程经验。总而言之Dominator 这个实现是 js-framework-benchmark 中少数Rust 编译进 WASM的代表它以预编译产物降低了仓库维护与基准运行的复杂度同时完整保留了从源码重建的能力。理解其 README 中的四步构建流程再结合 src/lib.rs 的信号式数据模型即可同时掌握它的使用方式与实现原理。赞分享性能测试开发者工具【免费下载链接】js-framework-benchmarkA comparison of the performance of a few popular javascript frameworks项目地址https://gitcode.com/gh_mirrors/js/js-framework-benchmark点击查看免费下载相关推荐如何快速部署现代化媒体管理系统MediaManager终极配置指南如何快速部署现代化媒体管理系统MediaManager终极配置指南 MediaManager是一款现代化的自托管媒体库管理系统专为替代传统的Arr套件而性能测试开发者工具开源生命周期评估软件openLCA 2.6.2从零开始的环境影响分析指南开源生命周期评估软件openLCA 2.6.2从零开始的环境影响分析指南 你是否想量化产品的环境影响却苦于没有合适的工具openLCA作为一款专业的开源生性能测试开发者工具原神抽卡数据分析实战指南3个关键步骤掌握概率统计原神抽卡数据分析实战指南3个关键步骤掌握概率统计 原神祈愿记录导出工具是一个基于Electron构建的桌面应用程序专门用于分析和导出《原神》游戏中的抽卡数据性能测试开发者工具上一篇Gas Town Hooks 管理指南基于 base/overrides 模型的集中式 Agent 生命周期钩子体系下一篇Argo CD argocd appset list 命令完全指南列出与筛选 ApplicationSet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表