Прогрессивный

Прогрессивный подход - это загрузка кода в соответствии с потребностями приложения, без предварительной загрузки всей кодовой базы.

Это связывает нас с основным принципом Qwik, который фокусируется на задержке загрузки и выполнения JavaScript-кода. Для этого Qwik должен разбить приложение на множество лениво загружаемых фрагментов.

Текущее техническое состояние

Существующие фреймворки страдают от двух проблем:

  • Границы ленивой загрузки полностью делегированы разработчику;
  • Фреймворки могут лениво загружать только те компоненты, которых нет в текущем дереве рендеринга.

Проблема заключается в том, что фреймворкам необходимо согласовывать свое внутреннее состояние с DOM. А это значит, что хотя бы один раз в приложении происходит гидратация. Фреймворки должны иметь возможность выполнить полный рендер для восстановления внутреннего состояния фреймворка. После первого рендера фреймворки могут быть более оперативными в отношении своих обновлений, но ущерб уже нанесен, код загружен. Итак, теперь у нас есть две проблемы:

  • Фреймворки должны загружать и выполнять компоненты для перестройки дерева рендеринга при запуске (см. гидратация — это дорого). Это вызывает жадную загрузку и выполнение всех компонентов в дереве рендеринга.
  • Обработчики событий поставляются с компонентами, даже если они не нужны во время рендера. Включение обработчиков событий вызывает загрузку ненужного кода.

Решение

Архитектура Qwik в полной мере использует современные инструменты для автоматизации задачи создания точки входа. Разработчики могут писать компоненты как обычно, в то время как оптимизатор Qwik разделит компоненты на фрагменты и загрузит их по необходимости.

Кроме того, среде выполнения фреймворка не нужно загружать код, который не требуется для интерактивности, даже если компонент является частью дерева рендеринга.

Оптимизатор

Оптимизатор) — это преобразование кода, которое извлекает функции в импортируемые символы верхнего уровня, что позволяет среде выполнения Qwik лениво загружать JavaScript по мере необходимости.

Оптимизатор и среда выполнения Qwik работают вместе для достижения желаемого результата фрагментарной ленивой загрузки.

Без оптимизатора либо:

  • Код должен быть разбит разработчиком на импортируемые части. Было бы неестественно писать приложение, делающее плохой DX.
  • Приложению пришлось бы загружать много ненужного кода, так как не было бы границ ленивой загрузки.

Среда выполнения Qwik должна понимать вывод оптимизатора. Здесь нужно понимать, что разбивая компонент на лениво загружаемые фрагменты, требование ленивой загрузки вводит во фреймворк асинхронный код. Фреймворк должен быть написан по-другому, чтобы учесть асинхронность. Существующие платформы предполагают, что весь код доступен синхронно. Это предположение предотвращает простое внедрение отложенной загрузки в существующие фреймворки (например, когда создаётся новый компонент, фреймворк предполагает, что его код инициализации может быть вызван в синхронной манере и если это первая ссылка на компонент, то его код должен быть загружен лениво, и поэтому фреймворк должен учитывать это).

Ленивая загрузка

Ленивая загрузка является асинхронной. Qwik - это асинхронный фреймворк. Qwik понимает, что у него не всегда может быть ссылка на функцию обратного вызова, и поэтому для неё может потребоваться ленивая загрузка (в отличие от этого, большинство существующих фреймворков предполагают, что весь код доступен синхронно, что делает ленивую загрузку нетривиальной).

В Qwik всё загружается лениво:

  • Компонент при рендере - блок инициализации и блок рендера;
  • Задачи компонента - побочные эффекты, загружается только при изменении входных данных;
  • Слушатели - загружаются только при взаимодействии;
  • Стили - загружаются только в том случае, если сервер ещё их не отдавал.

Ленивая загрузка - это основное свойство фреймворка, а не второстепенное.

Оптимизатор и $

Давайте снова посмотрим на наш пример:

// Суффикс `$` для `component` указывает, что компонент должен быть
// лениво загружен.
export const Counter = component$(() => {
  const count = useSignal(0);
 
  // Суффикс `$` для `onClick` указывает на то, что реализация для
  // обработчика должна быть загружена лениво.
  return <button onClick$={() => count.value++}>{count.value}</button>;
});

Обратите внимание на наличие $ в коде. $ — это маркер, сообщающий оптимизатору, что функция после него должна быть загружена лениво. $ — это единственный символ, который напоминает оптимизатору и разработчику, что здесь происходит асинхронная отложенная загрузка.

Участники

Спасибо всем участникам, которые помогли сделать эту документацию лучше!

  • adamdbradley
  • RATIU5
  • manucorporat
  • fleish80
  • msssk
  • mhevery
  • mrhoodz
  • thejackshelton
  • moinulmoin