QRL 与懒加载边界
理解可序列化的代码引用,以及 $ 到底改变了什么。
QRL 是 Qwik URL 的缩写。它不是网络请求,而是一个可序列化的代码引用:指向某个 chunk 里的某个符号,必要时还携带闭包捕获的值。
./chunks/counter.js#Counter_onClick[0,1]
# 之前:chunk 路径
# 之后:符号名
# 方括号:捕获变量在 q:obj 中的索引01从 JSX 到 HTML#
export const Counter = component$(() => {
const count = useSignal(0);
return (
<button onClick$={() => count.value++}>
{count.value}
</button>
);
});Optimizer 会把组件、事件处理函数与任务拆成独立模块。每个 $ 都是切分点。服务端渲染后,HTML 中留下的是指针,而不是已经执行过的闭包。
<button q-e:click="./chunks/counter.js#Counter_onClick[0,1]">
0
</button>
<script type="qwik/json">{ ... }</script>页面加载时只执行约 1 KB 的 qwikloader。用户点击按钮,qwikloader 冒泡找到 q-e:click,解析相对路径,加载对应 chunk,调用符号,再用 useLexicalScope() 恢复捕获的 signal。
02为什么不用 import()#
| 问题 | QRL 的解法 |
|---|---|
| 动态 import 无法序列化到 HTML | QRL 本身就是可写进 HTML 的字符串 |
| import 只到 chunk,不能指定符号 | URL 后带 #SymbolName |
| 相对路径离开模块后失去基准 | 用 q:base 在 DOM 中解析 |
| 闭包变量无法跨进程恢复 | 索引引用 qwik/json 中的对象 |
| 开发者手动切分边界 | Optimizer 根据 $ 自动切分 |
03写 $ 函数时的规则#
- 捕获的局部变量必须是 const,并且可序列化。
- 模块级变量必须被导入或导出,Optimizer 才能在新模块里重新引用它。
- 不要捕获类实例、DOM 节点或函数;需要跨边界时改用可序列化数据或 noSerialize()。
- 组件、任务、事件处理器分别成为独立符号,浏览器只下载真正执行的那部分。