渐进式加载
Qwik 把懒加载变成框架的默认路径:组件、任务、事件与样式都可以按需到达。
大多数框架把懒加载边界交给开发者:用 import() 包一层,或者配置路由级拆分。问题是,页面已经在渲染树上的组件无法被懒加载,因为框架需要它们来重建状态。
Qwik 把这件事反过来。Optimizer 在构建时把组件拆成多个符号,运行时按需请求。即使组件已经出现在首屏,事件处理和任务代码也可以继续留在服务器上。
01Optimizer 在构建期做了什么#
你写普通的函数。任何以 $ 结尾的调用都会成为提取点:Optimizer 把函数体移到独立模块,留下一个 QRL(Qwik Resource Locator)引用。
export const Counter = component$(() => {
const count = useSignal(0);
useTask$(({ track }) => {
track(count);
console.log('count', count.value);
});
return <button onClick$={() => count.value++}>{count.value}</button>;
});上面的组件至少会拆成三个符号:渲染函数、响应任务、点击处理。三者可以在不同时间下载,也可以在不同时间执行。
02所有东西都可以是符号#
- 组件渲染:只有在需要重新渲染时才加载。
- 任务(tasks):只有被跟踪的状态发生变化时才运行。
- 事件监听器:用户真正交互时才下载。
- 样式:服务端已经内联的样式不会重复下载。
- 数据:route loader 的结果在服务端生成,只传结果,不传逻辑。
03预加载:不让第一次交互等待#
按需加载不等于第一次点击一定慢。页面完成加载后,Preloader 会根据构建期生成的 bundle graph,空闲预取最可能被用到的符号。用户点击时,如果代码已经缓存,执行几乎是即时的;如果没有,Qwik 会把请求插到队列前面。
bun run preview
# 打开 DevTools > Network,点击页面上的按钮
# 观察 modulepreload 与 chunk 请求继续读响应式,理解为什么 Qwik 可以只更新一小块 DOM,而不触发整棵组件树。