Ripple News SSR 基准:50 篇文章新闻页的服务器渲染与浏览器水合全链路测量

📅 发布时间:2026/9/16 14:21:34
Ripple News SSR 基准:50 篇文章新闻页的服务器渲染与浏览器水合全链路测量
Ripple News SSR 基准50 篇文章新闻页的服务器渲染与浏览器水合全链路测量【免费下载链接】ripplethe elegant TypeScript UI framework项目地址: https://gitcode.com/GitHub_Trending/ripple25/ripplenews套件是 Ripple 基准仓库中唯一同时覆盖服务器端渲染SSR与浏览器端水合hydration两个阶段的工作负载它为每个框架目标构建生产版本生成一份 50 篇 lorem-ipsum 文章的新闻页分别测量“服务器把应用渲染成 HTML 字符串”和“浏览器把服务器 DOM 接管为可交互界面”的耗时并通过一组正确性闸门保证测量结果不是虚假的。读完本文你将掌握该套件的完整运行方式、测量口径、数据集生成机制以及从 run.mjs 源码中能确认的实现细节。测量什么SSR 渲染与 hydration 两个操作news套件在 suites.json 中声明为kind: per-target操作只有两个ssr_render和hydrate迭代次数为 normal 20 次、quick 3 次。覆盖的目标矩阵包括octane-tsrx、octane-jsx、react、preact、ripple、solid、svelte、vue-vapor、inferno九个框架 fixture。两个操作的测量边界见 run.mjs 的实现SSR 渲染在 Node 中导入构建后的dist/server/entry-server.js对renderApp()做预热 采样计时度量的是服务器生成完整 HTML 字符串的成本不含网络传输水合每个采样使用一个全新的 headless Chromium 上下文与页面browser.newContext()页面#app中已经含有服务器渲染的 DOM计时器只包裹同步执行的window.__hydrate()排除网络加载时间但包含框架自身的提交commit工作。README 特别指出Vue Vapor fixture 的 SSR 使用 Vue 的标准编译服务器渲染器buffered这与浏览器端使用 Vapor 是两回事ssr-throughput套件还会用 500 篇文章卡片做持续 SSR 压测而news使用 50 张卡片的检查入库数据集。确定性数据集mulberry32 PRNG 保证字节级一致公平对比的前提是所有框架渲染完全相同的内容。gen.mjs 生成数据集使用 mulberry32 伪随机数生成器固定种子1234保证跨次运行结果稳定每篇文章包含id、sectionWorld/Business/Tech/Science/Sports/Culture/Opinion 之一、title、byline、lead以及两段正文外加一个 0–499 的points字段生成后把同一份data.js写入全部九个目标目录octane-tsrx/、solid/、react/、preact/、ripple/、svelte/、vue-vapor/、inferno/、octane-jsx/的src/data.js文件头标注 “AUTO-GENERATED by benchmarks/news/gen.mjs — do not edit by hand”。因此每个框架渲染的是字节一致的文章内容SSR 字节数与 DOM 节点数才有可比性。harness 也会把 HTML 字节数与 hydration 前后的 DOM census 记录进结果元数据。运行方式从仓库根目录执行准备环境Node 24初始录制使用 Node 24.18.0pnpm install --frozen-lockfile pnpm --filter ripple-benchmarks exec playwright install chromium然后是news套件本身的四种运行模式pnpm bench --quick news # 快速模式减少重复与预热只做正确性冒烟检查 pnpm bench news # 正常模式20 次迭代建立计时基线 pnpm bench --record news # 把成功结果保存到本地基线 pnpm bench --compare news # 与本地基线对比缺基线或回归会失败pnpm bench --list可以查看当前套件矩阵。README 建议用--targetsripple,octane-tsrx,solid,vue-vapor选择存在 fixture 覆盖的优先对比目标。此外每个目标还可以用套件内脚本单独跑news/package.json提供了bench:ripple、bench:solid等脚本底层即node run.mjs target支持--no-build复用已有dist/加速重跑。关键区别--quick只缩减重复次数预热从 5 次降到 1 次、迭代 20 → 3用于正确性冒烟不建立性能结论正常运行保留上游迭代次数。quick 与 normal 的结果、以及不同机器上的计时都不应互相比较。正确性闸门三个条件缺一不可harness 在计时之外单独跑一轮正确性检查run.mjs 第 148–180 行三个闸门对应 README 所说的“server-node adoption、article content、theme toggle”卡片数量root.querySelectorAll(article.card).length必须大于 0验证 50 篇文章全部渲染节点收养no-rebuild水合前后对#app的innerHTML剔除 hydration 记账注释与 suspense 种子脚本后做比较并单独固定第一个article.card的 DOM 节点引用——即使字节一致的重建也无法通过这证明服务器 DOM 真的被接管而非重建交互可用theme toggle点击#theme按钮后header.masthead的类名必须发生变化。由于 Solid/React 把 DOM 更新推迟到 microtaskharness 会等待setTimeout(0)后再读取类名。任一闸门失败时harness 仍会写出 BENCH_JSON 结果但附带顶层failed字段并以非零码退出统一 runner 把正确性失败视为致命错误。Ripple fixture 的实现细节Ripple 目标由四个文件构成值得逐一看entry-server.ts— SSR 入口。调用ripple/server的render(App)返回{ head, body, css }其中css是作用域样式表哈希集合用getCss()解析为 CSS 文本并包进style注入 head。该返回形状刻意与其他目标保持一致让同一套 harness 驱动全部框架。entry-client.ts— 客户端入口。水合被刻意推迟到window.__hydrate之后执行这样 Playwright 页面可以带着服务器 DOM 先加载完成再在隔离的同步计时器中执行hydrate(App, { target: container, props: {} })。源码注释说明 Ripple 的 hydrate 从服务器在 body 周围输出的HYDRATION_START标记开始遍历服务器 DOM 进行接管且同步提交因此同步计时器能捕获到完整的水合工作量。App.tsrx— 页面主体Header组件 for循环渲染全部ARTICLES卡片section 标签、标题、署名、导语、两段正文 页脚。Ripple 直接渲染{expr}占位无需as string转换。Header.tsrx— 用 Ripple 的track建立响应式状态let [dark] track(false)[dark]解构把 Tracked 绑定为可直接读写的响应式局部变量点击按钮切换darkheader的类名随状态变化。这个主题切换正是水合后交互性证明的载体。vite.config.js— 使用tsrx/ripple的compile做最小化的.tsrx转换而非ripple-ts/vite-plugin元框架。关键点是按 Vite 的 SSR 信号区分编译模式SSR 构建编译为mode: server产出 HTML 字符串客户端构建编译为mode: clientDOM 运行时 hydration。另因ripple包以原始源码发布SSR 打包时配置了ssr.noExternal: [/^ripple($|\/)/]让 Vite 参与转换。生产构建优先为什么只测 built artifactsharness 顶部注释明确了基准方法论只测生产构建不测开发模式——dev 模式携带未压缩代码和框架开发运行时React/Solid 的 dev 构建有警告与校验开销Octane 的 dev 转换未优化。因此每个目标先做两次vite build客户端以index.html为入口dist/clientesbuild 压缩SSR把src/entry-server.ts打成 Node 可加载的dist/server/entry-server.js。NODE_ENVproduction在任何解析框架运行时的导入之前设置因为react-dom/solidjs/web等外部依赖依据它选择生产构建。之后 harness 用一个内置静态服务器把 SSR body 拼入index.html模板的!--ssr-body--占位符客户端资源从dist/client直接读取每个框架目标占用固定端口Ripple 为 5194见 run.mjs 的TARGET_PORTS与 vite.config.js 的strictPort。端口被占用直接报错这也是 runner 要求“一次只跑一个基准进程、机器处于空闲状态”的原因。统计口径上采样经summarizeSamples汇总后输出score / median / min / p95主分数score取自上游选定的稳定样本窗口的均值。结果与回归对比结果写入benchmarks/results/news.json当前仓库已提交 baseline-1/2/3 三次正常运行的快照包含各目标的ssr_render与hydrate统计及htmlBytes、cards、hydration 前后 DOM census 等元数据。本地回归判定规则来自总 README计时分数需同时满足“相对基线增长超过 15%”和“绝对增长超过 10%”亚毫秒基线另有 0.1ms 阈值——这是回归容忍度不是性能优势证明。--ratios则会应用 baselines/ratios.json 中评审过的同次运行守卫Ripple 分数除以参照框架分数latency/bytes/counts 类指标小于 1 有利于 Ripple。该比率削弱同机影响但不能消除 CPU 架构、内存、浏览器行为差异竞品变快也可能推高 Ripple 的比率。历史上游分数不是本 checkout 的基线。溯源与限制该套件移植自 Octane导入自5ec6040修订2026-09-06MIT 许可见 LICENSE.octaneRipple fixture 的依赖解析到本工作区的ripple、tsrx/ripple、ripple-ts/vite-pluginOctane 固定为已发布的0.2.6。详见 UPSTREAM.md 与总 benchmarks/README.md 中关于统计、保存运行对比与结果路径的说明。需要注意的限制news测的是缓冲式 SSRbuffered与streaming-ssr的流式交付是不同工作负载上游历史分数仅具历史参考价值不可作为本 checkout 的性能基准直接引用。【免费下载链接】ripplethe elegant TypeScript UI framework项目地址: https://gitcode.com/GitHub_Trending/ripple25/ripple创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考