Lynx × Rspack 2.0:更快、更小、更贴近 Web
← 所有文章Lynx 基于 Rstack(Rsbuild 与 Rspack)构建了自己的工具链 Rspeedy,让每一个 Lynx 应用都能同步获得上游工具链的性能与能力。
随着 Rspack 2.0 与 Rsbuild 2.0 相继发布,Lynx 免费获得了上游的一系列优化:构建提速 18~39%、产物体积下降 3~9%,以及向 Web 通行约定对齐的配置,如 resolve.alias 和顶层 splitChunks。在此之上,我们针对 Lynx 做了一系列定制:更灵活的分包与动态加载、面向 PrimJS 的产物调优、默认 ES2017、Lynx Bundle 并行编码,以及精确错误反解。我们还引入了一个用于包体积优化的 Agent Skill,帮你系统化地优化应用体积。
这些能力从 Rspeedy 0.15 起可用。我们预计绝大多数项目无需改动配置即可获得这些收益,需要迁移的部分见下文升级指南。
Rspack 2.0
Rspack 是最底层的打包引擎。这次升级到 2.0,带来了最直接的性能与体积收益,绝大多数项目无需改动配置即可获得。Rspack 2.0 本身的完整变更,可参考 Rspack 2.0 发布博客了解。
构建提速 18~39%
在一组生产环境的 Lynx 应用上,我们测得构建耗时下降 18~39%,且不需要任何配置改动:
核心提速来自 Rspack 2.0 的引擎优化;多页应用还会进一步受益于 Lynx Bundle 的并行编码。
产物体积下降 3~9%
升级后产物体积也随之下降。在中间产物 main-thread.js、background.js 与最终的 Lynx Bundle 中,main-thread.js 与 Lynx Bundle 普遍下降 3~9%。
这部分收益来自 Rspack 2.0 更强的 tree-shaking,以及我们把后台产物默认目标提升至 ES2017。
Node.js 版本要求提升
最低要求提升至 Node.js 20.19+ 或 22.12+,不再支持 Node.js 18。
@lynx-js/*-webpack-plugin 不再支持 webpack
既然 Rspack 已经足够成熟,我们也将底层 @lynx-js/*-webpack-plugin 系列插件转为 Rspack-only:公开类型统一从 @rspack/core 导出。绝大多数项目通过 Rspeedy 间接使用,无需改动;如果你直接依赖这些插件,需要相应调整。
Rsbuild 2.0
Rsbuild 在 Rspack 之上提供开箱即用的构建配置。2.0 让这些配置进一步向 Web 生态的通行约定靠拢;这一层的变更主要集中在配置项的命名与位置调整上,语义保持不变。完整变更可参考 Rsbuild 2.0 发布博客。
source.alias → resolve.alias
将别名从 source.alias 迁移到 resolve.alias:
performance.chunkSplit → splitChunks
将 performance.chunkSplit.strategy 迁移到顶层 splitChunks.preset:
默认装饰器版本 2023-11
source.decorators.version 的默认值由 2022-03 变更为 2023-11,如需保持旧行为请显式配置。
面向 Lynx 的定制优化
在 Rspack 与 Rsbuild 之上,Rspeedy 做了一系列针对 Lynx 双线程运行时与产物格式的优化。
更灵活的分包与动态加载
Lynx 提供了由弱到强的三种拆分手段,它们在 Web 生态中都有对应的概念,并由 Rspeedy 适配到了 Lynx 的产物形态上:
构建期拆包的 splitChunks 较为常见(配置迁移见 performance.chunkSplit → splitChunks),这里不再展开;下面重点说说 Lazy Bundle 和 External Bundle。
Lazy Bundle
Lazy Bundle(懒加载分包)把单个应用的一部分延后加载,用 ReactLynx 的 lazy() 按需拉取,体验与 Web 中的动态 import() 一致:
在此基础上,我们正在为 Lazy Bundle 增加按 import 控制加载时机的能力:借助 Rspack 2.0 的 import attribute 支持,为每个 import 单独指定同步加载(用于首帧直出 IFR)或异步加载(后台驱动,默认)。届时的用法大致如下:
该能力正在开发中,将在后续版本提供。
External Bundle
External Bundle 是一个单独构建出来的 Lynx Bundle,可以被另一个应用在运行时拉取并渲染,从而实现跨应用复用。生产侧基于 Rslib 构建,用 defineExternalBundleRslibConfig 产出;消费侧则使用 Rsbuild 插件 pluginExternalBundle 接入。
面向 PrimJS:let / const 降级为 var
除了构建期更快,我们也让产物在 Lynx 的运行时里解析得更快。在 Android 上,Lynx 的后台线程运行在 PrimJS 引擎上,而我们发现 PrimJS 解析 var 的速度明显优于块级作用域的 let / const。因此 Rspeedy 0.15 默认在主线程与后台线程两层都开启了 SWC 的 transform-block-scoping,把 let / const 降级为 var,并将 output.environment.const 设为 false,让打包器自身生成的运行时代码也使用 var。
默认目标提升至 ES2017
我们把后台线程的产物目标从 ES2015 提升到了 ES2017(主线程保持 ES2019)。随着低端机型逐渐退场,更高的产物基线意味着更少的语法降级、更小更快的产物。如果你仍需要降级某些特定语法,可以把对应的 transform 加到 tools.swc 的 env.include:
Lynx Bundle 并行编码
对多页应用,构建提速不止来自 Rspack 2.0:Rspeedy 在一个并行的 worker 池中运行各 entry 的 tasm encode(@lynx-js/tasm),把原本串行的 Lynx Bundle 编码并行化,进一步缩短构建耗时。
精确的错误反解
Rspeedy 0.15 让线上错误能精确反解回源码:为每个 Lynx entry 生成统一的 debug-metadata.json,整合 JS、CSS、UI 三类 Source Map,主线程与后台线程的报错都能找到正确的反解信息、还原到原始代码。具体做法见线上错误反解。
One More Thing:包体积优化 Agent Skill
准确定位体积瓶颈,往往比优化本身更难,这需要理解 Lynx 的产物格式和 Rspeedy 的双线程构建机制。rspeedy-bundle-size 把这套知识封装成了一个 Agent Skill:它让 AI 理解 Lynx 双线程产物的体积构成,按「先测量、后优化」的方式工作:先量清楚一个应用的体积大在哪,再按回报高低排序,优先处理收益最大的部分(资源、后台 JS、主线程产物中的冗余代码)。

把它安装到你的 Agent(Claude Code、Codex 等)中:
之后用自然语言描述目标即可,例如「帮我拆解下这个应用的包体积,到底大在哪、怎么减」。Skill 会运行 Rsdoctor、按层给出体积拆解,并产出一张带优先级的优化清单,只有在你确认后才动手改代码。在真实业务中,这套工作流把页面体积减小了 10~13%,主要手段是把本应只在后台运行、却被打进了主线程的后台专属(background only)代码(如日志、网络请求、监控埋点等)正确标记并移出主线程,并通过 alias 去除重复打包的依赖。
升级指南
完整迁移步骤见 Rspeedy 升级指南。上文按层列出的破坏性变更,多数随 Rspack 2.0 / Rsbuild 2.0 升级引入。如需逐条核对,可参阅 Rspeedy CHANGELOG、Rsbuild v1 → v2 升级指南 以及 Rspack v1 → v2 迁移指南。
接下来
我们会继续和 Rstack 团队一起优化构建性能与产物性能,同时让更多 Web 上已经成熟的能力可以在 Lynx 上开箱即用,例如 Module Federation。
你可能也注意到了上文 Rspack → Rsbuild → Rspeedy 的三层结构有些绕,我们也有同感。接下来我们会探索如何消除 Rspeedy 这一层:把双线程模型等 Lynx 特性沉淀到上游 Rstack,减少 Lynx 专属的配置、概念与文档,让长远来看你可以直接用 Rsbuild 配置和构建 Lynx 项目。
在你现有的项目上升级试试看吧。如果遇到问题或有建议,欢迎在 GitHub 上提 Issue 或参与讨论。