テックタッチアドベントカレンダーの 20 日目を担当させていただく matchy です。
最近は趣味でアプリケーションの UI デザインを Figma で作るのが楽しくてつい時間を忘れてしまいます。
近ごろ Astro や今回紹介する Qwik など、MPA フレームワークの話をよく SNS などで見かけるので、気になり調べてみました。
Qwikとは?
- builder.io が開発している Web フレームワーク
- Web サイトやアプリケーションの構築に使用できる
- SSR ベース
公式
特徴をまとめてみる
- 約 1 KB の JS で起動できる
- 最小限のアプリケーションをダウンロードして実行する
- JavaScript の実行とダウンロードを可能な限り遅らせる
- アプリケーションとフレームワークの実行状態をサーバーでシリアライズし、クライアントで Resume させる
- Hydration を使用しない
- jsx、tsx で書ける
ん? Hydration を使用しない?
SSR では、まずサーバー上でページのレンダリングを行い、生成された HTML をクライアントに返却します。
その後、そのままだとインタラクティブなコンテンツの操作が行えないため、 Hydration という処理が走り、レンダリング済みの DOM と比較しながらイベントハンドラをアタッチしていきます。
SSR ベースのフレームワークにも関わらず、その Hydration を使用しないということで???となる方もいるのではないでしょうか。
Hydration の課題
- ページの表示までは行われるが、TTI(Time to Interactive = コンテンツがインタラクティブになるまでの時間)がユーザーの環境に依存してしまう
- コンポーネントの量が増えていくとそれだけ初期ロード時の JS サイズが大きくなってしまう
- インタラクティブな部分が少ないページや静的なページも関係なく、コンポーネントの JS をすべてダウンロードし DOM の計算を行うコストがかかってしまう
Resumable という概念
Hydration の問題の解消として React 18 の Selective Hydration や、冒頭で少し触れた Astro では Islands Architecture という Hydration を行う箇所をインタラクティブな部分限定にし、パフォーマンスを向上させるといったアプローチを取っています。
それに対して Qwik では Resumable というアプローチを採用しました。
そもそも Hydration の処理を行わず、ダウンロードする JS ファイルを最小限にすることで、ページのレンダリングコストを下げることが可能になっています。
また、DOM にイベントハンドラを仕込んでおき、ユーザーの操作に応じて必要な JS のみダウンロードを行うので、結果 TTI も短縮できるといったアイデアです。
TTI を短縮できることによって、UXの向上や page speed Insights の指標の改善が狙えます。
import { component$, useStore } from '@builder.io/qwik'; export const Counter = component$(() => { const store = useStore({ count: 0 }); return ( <div> <p>Count: {store.count}</p> <p> <button onClick$={() => store.count++}>Increment</button> </p> </div> ); });
(Qwik でインタラクティブなボタンを実装した例)
<button on:click="/src/counter_component_div_p_button_onclick_ziketbnzetm.js#Counter_component_div_p_button_onClick_ZIkEtbnzEtM[0]" q:id="3">Increment</button>
(レンダリングされた HTML では button 要素に on:click の属性が付与されて出力される。値には遅延読み込みする JS ファイルが指定されており、イベントが発火したら JS ダウンロードが行われる)
プロジェクト作成をしてみる
Qwik の Getting Started に沿ってプロジェクトを 1 つ作成してみたいと思います。
npm create qwik@latest
次にプロジェクトを作成する場所とプロジェクト名を決めます。
? Where would you like to create your new project? › ./qwik-app
? Select a starter › (use ↓↑ arrows, hit enter) ❯ Basic App (QwikCity) └─App with Routing built-in (recommended) Documentation site (QwikCity) Component library
ここで starter を選択します。(今回は Basic App)
? Would you like to install npm dependencies? › (Y/n)
npm の依存パッケージをインストールするか聞かれるので enter(Yes)を押します。
🦄 Success! Project created in qwik-app directory 🐰 Next steps: cd learning/SUBSCLiZE/subsclize_app npm start 🔌 Integrations? Add Netlify, CloudFlare, Tailwind... npm run qwik add 📚 Relevant docs: https://qwik.builder.io/docs/getting-started/ 💬 Questions? Start the conversation at: https://qwik.builder.io/chat https://twitter.com/QwikDev 📺 Presentations, Podcasts and Videos: https://qwik.builder.io/media/
無事インストールされました!
ディレクトリを移動してnpm run dev
で起動してみます。
cd /Users/username/qwik-app
❯ npm run dev > dev > vite --mode ssr Port 5173 is in use, trying another one... VITE v4.0.1 ready in 641 ms ➜ Local: http://127.0.0.1:5174/ ➜ Network: use --host to expose ➜ press h to show help
起動できました!
ちなみに、Qwik では Vite がビルドツールとしてデフォルトで入っているのもあり開発環境の起動もビルドも爆速でした。
Qwik City とは
Learning Qwik and Qwik City are not two different things, Qwik City is built on top of Qwik, bringing opinionated routing and goodies to make your life easier.
We call it a meta-framework for Qwik. Qwik City is to Qwik, what Next.js is to React, what Nuxt is to Vue, or SvelteKit to Svelte.
Qwik のメタフレームワークで、React に対しての Next.js、 Vue に対しての Nuxt.js ようなもの。
独自のファイルベースのルーティングで、高速でアプリケーションを構築できるとのことです。
(ざっくり調べた感じ、ルーティングディレクトリの制約が Next.js などとは異なるみたいです)
最後に
色々な角度からパフォーマンス向上させるためのアプローチをしかけているライブラリやフレームワークが続々と出てきていて、面白いなと思いました。
また、SSR における Hydration の問題を学ぶ良い機会にもなりました。
今回は内容が膨大化してしまうため Getting Started までの紹介となってしまいましたが、これを機に Qwik を利用したアプリケーションを作ってみようと思います。