Qwik — это смелое переосмысление того, как работают реактивные пользовательские интерфейсы. Основная предпосылка заключается в том, что фреймворк создан с нуля для доставки HTML с минимальным использованием JavaScript — ровно столько JavaScript, чтобы постепенно внедрять интерактивность по мере необходимости.
Qwik использует детализированную модель для изоляции сегментов приложения, которые гидратируются по мере необходимости. Отталкиваясь от первых принципов, Qwik обеспечивает недостижимую иначе производительность и представляет собой альтернативный путь развития клиентского JavaScript.
Состояние Qwik
Qwik все еще находится на ранней стадии разработки, но с тех пор, как мы впервые его увидели, он прошел долгий путь. Теперь на StackBlitz есть полнофункциональный пример, игровая площадка REPL и инструмент командной строки. Qwik также был усовершенствован и теперь поддерживает более удобный для разработчиков синтаксис, подобный React. Под капотом по-прежнему находится продвинутый, единственный в своем роде реактивный движок, который определяет реактивные границы по состоянию, шаблонам и слушателям.
Возобновляемость
Qwik использует комбинацию умного рендеринга на стороне сервера и на стороне клиента, чтобы избежать двойного налогообложения, от которого страдают современные платформы, выполняющие работу по гидратации дважды: один раз на сервере и снова на клиенте.
Как пишет создатель Qwik Миско Хевери:
Основная идея Qwik заключается в том, что его можно возобновлять. Он может продолжиться с того места, на котором остановился сервер. На клиенте выполняется лишь минимальное количество кода.
Или, другими словами: позвольте серверу настроить HTML-страницу как можно более функциональной и позвольте клиенту выполнять минимально возможный объем работы для продолжения или возобновления процесса для пользователя.
Типичный процесс в реактивных платформах с SSR (отрисовкой на стороне сервера) заключается в том, чтобы сначала создать версию приложения на сервере, а затем отправить ее клиенту, который визуализирует созданное приложение. В этот момент клиентское приложение берет на себя управление, и ему, по сути, приходится снова загружать то же приложение, чтобы соединить работающий клиент.
Этот процесс известен как гидратация. Есть несколько умных способов сделать гидратацию более эффективной, но Qwik отказывается от них в пользу нового процесса, называемого возобновляемостью.
Возобновляемость означает, что клиент может продолжить с того места, на котором остановился сервер, без необходимости пересобирать приложение на клиенте.
Время интерактивного
Показатель, который Qwik стремится улучшить, — это время взаимодействия (TTI). Это относится к количеству времени, которое проходит между тем, когда пользователь отправляет запрос на веб-страницу, и тем, когда страница начинает реагировать на взаимодействие пользователя.
В то время как время загрузки (TTL) отслеживает, сколько времени потребуется клиенту для завершения получения всех необходимых данных (и, следовательно, этот показатель определяется в основном размерами файлов и скоростью сети), TTI учитывает важный факт современных JS-фреймворков: данные загружаются, затем клиент должен распаковать и выполнить код JavaScript, необходимый для того, чтобы сделать страницу интерактивной.
Реактивный двигатель требует много работы. Движок должен разгадать/проанализировать всю эту разметку (например, JSX), пронизанную переменными и выражениями, которые изменяют то, что отображается, в зависимости от изменения состояния, и то, как оно ведет себя в зависимости от кода.
На другом конце спектра находится обычная HTML-страница. Как только браузер завладеет им, страница готова к работе. Вот почему Google PageSpeed Insights дает такой странице, как Reddit.com, 32 балла из 100, а необработанный HTML — 100.
Замыкания и слушатели
Техническое препятствие для быстрого TTI описывается Хевери как «смерть из-за закрытия». Короче говоря, тот факт, что каждое замыкание должно поддерживать окружающую вселенную информации, означает, что приложение среды выполнения представляет собой слоеный пирог из активно загружаемого кода.
Решение, используемое Qwik, заключается в использовании глобального прослушивателя событий, который взаимодействует с сериализованными прослушивателями. Другими словами, универсальный прослушиватель событий используется для оркестрации прослушивателей, которые реализуются по требованию, вместо того, чтобы прослушиватели загружались и заключались в замыкания (независимо от того, будут ли они когда-либо фактически выполняться).
Qwik стремится обеспечить реактивность, встроенную в HTML, что делает его сериализуемым. Требуется лишь небольшой исполняемый файл, чтобы затем проявить реактивность во время выполнения на основе информации, инкапсулированной в разметке.
Разделение кода, точно настроенное
Другой способ взглянуть на это заключается в том, что Qwik выполняет точно настроенное разделение кода. Он загружает интерактивный код по мере необходимости, когда этого требует пользователь. Затем сборщики могут упаковать эти фрагменты в более крупные биты, если это имеет смысл.
Qwik изначально создан с тремя отдельными функциями для создания состояния, шаблона и прослушивателей. Это позволяет платформе загружать только то, что необходимо для поставленной задачи. Вы можете узнать больше об этом аспекте фрагментирования здесь.
Три границы состояния, шаблона и прослушивателя когда-то были напрямую запрограммированы разработчиками. Благодаря новому инструменту Optimizer, который незаметно преобразует React-подобный синтаксис в эти границы, вы получаете довольно знакомый DX. А оптимизатор выполняет работу по превращению фактического кода в набор крошечных заглушек, которые при необходимости могут возобновлять работу приложения небольшими порциями.
В оптимизаторе шаблоны и прослушиватели обозначаются знаком доллара, а состояние обрабатывается useStore
крюк. Вы увидите этот синтаксис через мгновение.
Конечный результат кода Qwik не похож на код других платформ, но использование Qwik с оптимизатором приводит его в соответствие с другими платформами. Qwik также представил QwikCity — набор функций более высокого порядка, таких как маршрутизация, которые упрощают создание полномасштабных приложений.
Практический опыт работы с Qwik
Теперь, когда вы имеете представление о концепциях Qwik, давайте попробуем программировать с его помощью. В листинге 1 показан простой компонент, написанный на Qwik. (Этот пример взят из FAQ Qwik.)
Листинг 1. Простой компонент Qwik
import { component$ } from '@builder.io/qwik';
export const App = component$(() => {
console.log('render');
return <p onClick$={() => console.log('hello')}>Hello Qwik</p>;
});
В листинге 1 показано, что компонент в Qwik определяется как анонимная функция, передаваемая в component$
функция из библиотеки Qwik. Каждый раз, когда вы видите знак доллара $
в Qwik он сообщает оптимизатору, что ему нужно выполнить некоторую работу. В частях приложения, подписанных долларом, Qwik будет использовать свои мелкозернистые границы отложенной загрузки.
onClick$
в листинге 1 приведен еще один пример специального синтаксиса Qwik. Qwik будет использовать некоторые хитрости, чтобы загружать только тот JavaScript, который необходим для поддержки функциональности, когда это действительно необходимо.
Код в листинге 1 будет разбит оптимизатором на несколько сегментов, как показано в листинге 2.
Листинг 2. Компонент Qwik после компиляции
// The app.js file itself
import { componentQrl, qrl } from "@builder.io/qwik";
const App = /*#__PURE__*/
componentQrl(qrl(()=>import('./app_component_akbu84a8zes.js'), "App_component_AkbU84a8zes"));
export { App };
// app_component_akbu84a8zes.js
import { jsx as _jsx } from "@builder.io/qwik/jsx-runtime";
import { qrl } from "@builder.io/qwik";
export const App_component_AkbU84a8zes = ()=>{
console.log('render');
return /*#__PURE__*/ _jsx("p", {
onClick$: qrl(()=>import("./app_component_p_onclick_01pegc10cpw"), "App_component_p_onClick_01pEgC10cpw"),
children: "Hello Qwik"
});
};
// app_component_p_onclick_01pegc10cpw.js
export const App_component_p_onClick_01pEgC10cpw = ()=>console.log('hello');
В листинге 2 вы можете видеть, что вместо включения фактической функциональности компонента Qwik включает ссылку, используя componentQrl()
функция из библиотеки. Эта функция занимает qrl()
функция, которая использует анонимную функцию для импорта сгенерированного файла компонента. Все эти ассоциации между компонентами скрытно управляются оптимизатором. Разработчику не нужно думать об этом напрямую.
QRL означает URL-адрес Qwik, то есть способ, которым Qwik ссылается на что-то, что будет загружаться отложенно. По сути, каждый раз, когда платформе необходимо отложить загрузку чего-либо, она вставляет QRL, обернутый специфичным для QRL потребителем (например, компонентом, состоянием или функцией шаблона).
Например, componentQRL
может в нужный момент загрузиться в коде, найденном в дочернем компоненте, в то время как родительский компонент может быстро отобразить его макет. Аналогично с onClick
обработчик: его можно оценить, когда происходит щелчок.
Интерфейс командной строки Qwik
Инструмент командной строки доступен в npm и имеет базовые функции, которые вы ожидаете, включая создание, режим разработки и производственную сборку. Интерфейс командной строки Qwik использует Vite в качестве инструмента сборки. Вы можете запустить новое приложение с помощью npm create qwik@latest
который запустит интерактивную подсказку.
Если вы создадите простое приложение и запустите производственную сборку, вы получите dist
каталог, в котором вы можете увидеть все отдельные загружаемые фрагменты приложения, которые мы описали ранее.
Настройка Qwik
Интересным местом, где можно получить представление о синтаксисе Qwik, является шпаргалка Qwik, которая предлагает параллельное сравнение кода Qwik и React. Вы увидите, что в целом переход не так уж и сложен. Некоторые области очень похожи, а некоторые требуют в основном изменения в мышлении. Более важный вывод заключается в том, что реактивная система в Qwik радикально отличается от React-подобных фреймворков, несмотря на сходство синтаксиса, достигнутое с Optimizer.
Инновационный подход Qwik к разделению кода и отложенной загрузке предлагает новый путь вперед для клиентского JavaScript. Будет интересно посмотреть, куда пойдут дела дальше.