渐进式
渐进式是指根据应用程序的需求下载代码,而不是急切地下载整个代码库。
这与 Qwik 的 核心原则 相连,该原则侧重于尽可能延迟 加载 和执行 JavaScript。Qwik 需要将应用程序分解成许多延迟加载的块才能实现这一点。
当前技术水平
- 延迟加载边界完全委托给开发者
- 框架只能延迟加载当前渲染树中不存在的组件。
问题在于框架需要将它们内部状态与 DOM 进行协调。这意味着应用程序至少需要进行一次 水合。框架需要能够进行完整渲染以重建框架的内部状态。在第一次渲染之后,框架可以更精确地进行更新,但损害已经造成,代码已经下载。因此,现在出现了两个问题
- 框架需要下载并执行组件以在启动时重建渲染树。(参见 水合是纯粹的开销)这迫使所有渲染树中的组件急切地下载和执行。
- 事件处理程序与组件一起提供,即使它们在渲染时不需要。包含事件处理程序会强制下载不必要的代码。
解决方案
Qwik 的架构充分利用了现代工具来自动解决入口点生成问题。开发者可以像往常一样编写组件,而 Qwik 优化器会将组件拆分成块,并在需要时下载它们。
此外,框架运行时不需要下载与交互性无关的代码,即使组件是渲染树的一部分。
优化器
优化器 是一种代码转换,它将函数提取到顶级可导入符号中,这使 Qwik 运行时能够根据需要延迟加载 JavaScript。
优化器和 Qwik 运行时协同工作以实现细粒度延迟加载的预期结果。
如果没有优化器,则
- 代码必须由开发者拆分成可导入的部分。这将是不自然的编写应用程序方式,导致糟糕的开发体验。
- 应用程序将不得不加载大量不必要的代码,因为没有延迟加载边界。
Qwik 运行时必须理解优化器的输出。这里需要理解的是,通过将组件拆分成延迟加载的块,延迟加载需求将异步代码引入框架。框架必须以不同的方式编写才能考虑异步性。现有框架假设所有代码都是同步可用的。这种假设阻止了将延迟加载轻松插入现有框架。(例如,当创建新组件时,框架假设其初始化代码可以以同步方式调用。如果这是第一次引用组件,则其代码需要延迟加载,因此框架必须考虑这一点)。
延迟加载
延迟加载是异步的。Qwik 是一个异步框架。Qwik 理解,在任何时候,它可能没有对回调的引用,因此它可能需要延迟加载它。(相比之下,大多数现有框架假设所有代码都是同步可用的,这使得延迟加载变得不 trivial)。
在 Qwik 中,所有内容都是延迟加载的
- 组件在渲染时 - 初始化块和渲染块
- 组件任务 - 副作用,仅在输入更改时下载
- 监听器 - 仅在交互时下载
- 样式 - 仅在服务器没有提供它们时下载
延迟加载是框架的核心属性,而不是事后才想到的。
$
优化器和 再次看看这个例子
// the `$` suffix for `component` indicates that the component should be
// lazy-loaded.
export const Counter = component$(() => {
const count = useSignal(0);
// the `$` suffix for `onClick` indicates that the implementation for
// the handler should be lazy-loaded.
return <button onClick$={() => count.value++}>{count.value}</button>;
});
注意代码中 $
的存在。$
是一个标记,它告诉优化器,它后面的函数应该延迟加载。$
是一个单字符,它提示优化器和开发者,让他们知道这里发生了异步延迟加载。