2026年10月1日,UTC时间下午3点49分,Qwik 2.0 RC发布到了npm。不到7个小时之内,SvelteKit 3和Remix 3.0.0也相继发布。三个主流框架在同一天撞车,像一场没有预谋的集体换血。
但Qwik 2.0 RC的发布说明里,最值得读的不是新功能。它讲的是一个框架为了守住"可恢复性(Resumability)"这条底线,愿意放弃什么 。答案之一是:HTML注释。
一、先说清楚:Qwik的"可恢复性"到底在反对什么
大多数框架的SSR流程是这样的:服务端生成HTML,浏览器收到后,把同一套组件代码再加载一遍、执行一遍 ,重新挂载事件监听器、重建组件树和状态。这个过程叫 hydration(水合) 。
问题在于:应用越大,启动时必须执行的JavaScript就越多。首屏可交互时间不是由"页面多大"决定的,而是由"你的组件代码总量"决定的。
Qwik不做这件事。它的官方文档把执行描述为:在服务器上"暂停",在浏览器中"恢复" 。监听器直接写进HTML属性,比如 on:click="./chunk.js#handler";组件边界、应用状态、状态与组件之间的订阅关系,全部序列化进HTML。浏览器里最先运行的只有一小段叫Qwikloader的脚本,它挂一个全局监听器,等用户真正点击某个元素时,才根据属性去加载对应的chunk。
首屏JavaScript的成本,被设计成与组件数量无关。 这是Qwik最核心、也最不容妥协的承诺。
二、v1的代价:那些"可爱的小注释",其实很重
"把状态和边界序列化进HTML"这件事,在Qwik v1里靠的是一个不太起眼的载体:HTML注释。
v1的HTML长这样(简化示例):
html
<main>
<!--qv q:id=7 q:key=counter-->
Count: <!--t=8-->123<!---->!
<button on:click="...">+1</button>
<!--/qv-->
</main>
<!--qv--> 标记组件边界,<!--t=8--> 标记某个文本节点由哪个signal驱动更新。
Qwik 2.0的RC公告把这些注释称为"cute little comments",但同一份公告非常直白地列出了它们的代价:
- 需要单次有序遍历才能写出;
- 给CPU和内存带来负担;
- 让响应式更新比平均水平的框架更慢;
- 让乱序流式传输变得不可能;
- 缓慢的获取会阻塞它下面的所有内容。
最后两条是致命的。2026年的Web平台正在全力推进"内容就绪就交付"的流式渲染,而Qwik v1的注释标记机制,在物理上要求HTML必须按顺序、一次性完整地写出来。这跟它自己想讲的故事------让浏览器"少做额外工作"------在深层逻辑上是矛盾的。
三、v2的答案:把"携带标记的载体"直接扔掉
Qwik 2.0的选择是:不再用HTML注释来携带这些信息。
v2的HTML变成了这样:
html
<main>
Count: 123!
<button on:click="...">+1</button>
</main>
<script type="qwik/state">[...]</script>
<script type="qwik/vnode">...</script>
body里的注释从60个降到了0 。所有边界、状态、文本更新位置的信息,被压缩进了HTML末尾的两个script块:qwik/state 和 qwik/vnode。
这不是简单的"挪了个位置"。它带来的是一连串结构性的解放:
- 乱序流式传输成为可能(实验性):页面不必等最慢的那块数据就绪才能开始输出。
- 更新不再需要重新解析HTML:vnode在内存中作为轻量对象存在,signal变化时直接更新对应的文本节点或属性,不再走"重新读HTML找标记"的路径。
- 长任务可以被切片:调度器每15毫秒把控制权交还给浏览器,点击和输入在长渲染期间不会被阻塞。
v2还沿用了2024年"Towards Qwik 2.0"设计文章中预告的一系列"抠细节"决策:vnode信息编码成约9个字符的字符串,元素引用用深度优先序号代替ID属性,vnode按需生成、用数组而非对象存储以帮助JIT优化。
所有这些决策指向同一个目标:不让浏览器做额外的工作。
四、牺牲了什么?社区并不全是掌声
Qwik 2.0 RC不是一次"纯升级"。它有一个社区已经注意到的代价:打包体积增加了。虽然"加载前运行的JS"从59KB降到了9KB,但整体的bundle size是上升的。
这是一个值得认真对待的权衡。Qwik v1的注释标记虽然"重",但它让框架在运行时需要的额外数据结构更少。v2把信息集中到末尾的script块,让流式传输和更新效率获得了结构性提升,代价是一次性传输的字节数变多了。
Qwik团队的选择隐含了一个判断:对于"可恢复性"这个目标来说,"首屏运行多少JS"比"总共下载多少字节"更重要。用户感知到的"卡",往往来自主线程被JavaScript执行阻塞,而不是来自多下载了几KB。v2把成本从"运行时"挪到了"传输时",同时换来了流式传输和可切片的长任务。
这个判断是否正确,取决于你的用户场景。对于网络极差、但设备性能尚可的环境,bundle增大可能是一个真实的代价。Qwik 2.0不是免费的午餐,它是一次有明确方向的取舍。
五、同一天发布,三种不同的"框架减法"
Qwik 2.0 RC的发布日,恰好撞上了SvelteKit 3和Remix 3.0.0。三个框架在同一天做出了三个方向不同的"减法":
Qwik 2.0做的是"移除运行时标记" 。它删掉HTML注释,把状态和vnode集中到末尾,目标是让"恢复"这件事在流式和调度层面都变得更干净。
Remix 3做的是"移除框架依赖" 。它不再绑定React,变成一个基于Web primitives(Request/Response)的单一包,把"全栈框架"和"UI库"解耦。
SvelteKit 3做的是"移除运行时本身" 。编译时框架的路线走到极致,运行时尽可能小,逻辑尽可能前移到编译阶段。
三个框架在同一天交出了三种不同的答案,但它们问的是同一个问题:在2026年,"框架"到底应该在运行时承担多少重量?
六、这对前端开发者意味着什么?
第一,框架的"设计哲学"正在变成可量化的工程取舍。 Qwik为了"可恢复性"删掉HTML注释,付出bundle增大的代价。这不是抽象的理念之争,而是"首屏运行JS"和"总传输字节"之间的具体权衡。当你评估一个框架时,看它愿意为什么付出代价,比看它宣传什么更重要。
第二,流式渲染正在从"框架特性"变成"平台预期"。 Chrome的声明式部分更新和Qwik 2.0的乱序流式实验指向同一个方向:HTML不应该因为交付顺序而被惩罚。当平台层开始解决这个问题时,框架在流式上的"独家能力"会逐渐被标准化。
第三,"不水合"的路线仍然小众,但它的压力正在倒逼整个生态思考启动成本。 Qwik不是主流选择。但它用两年零八个月打磨v2、为了一个目标删掉自己最显眼的机制,这件事本身在提醒所有人:首屏可交互时间不应该随着应用变大而无限增长。
写在最后
2026年10月1日,Qwik 2.0 RC发布。同一天,SvelteKit 3和Remix 3.0.0也来了。
Qwik 2.0最值得读的部分,不是它新增了什么,而是它愿意删除什么。HTML注释从60个降到0,bundle变大了,但乱序流式传输和15毫秒调度变成了可能。
一个框架为了守住"不水合"这条线,把自己最显眼的机制都扔掉了。这种级别的取舍,比任何 benchmark 数字都更能说明一个框架到底相信什么。
参考链接: