Svelte とは
Svelte は、コンパイラベースの Web アプリケーションフレームワークです。 特殊なテンプレート言語を使ってコンポーネントを実装することで、高度に最適化された HTML/JavaScript/CSS を出力することができます。 React.js アプリなどは、クライアントサイド JavaScript から共通のライブラリを呼び出す形で動作しますが、Svelte はコンパイル後の最適化された JavaScript のみで動作するようになっており、最終的な成果物が非常にコンパクトになります。 独自のテンプレート構文を学ぶ必要はありますが、ユーザー操作に反応するコンポーネントを、少ないコードで記述できるよう工夫されています。
Svelte よりも後発のコンパイラベースの Web アプリフレームワークに Astro があります。 Astro は、ビルド時にほとんどの JavaScript コードを実行して、その時点で静的な HTML ファイルを生成するというアプローチをとっています。 最終的にデプロイするのは、HTML (+CSS) だけになるので、初期表示が爆速になるという考え方です。 一方、Svelte はあくまで最適化された JavaScript コードはクライアントサイドで動かすという考え方です。
完全に静的なサイトであれば Astro を使い、インタラクティブなサイトであれば Svelte を使う、という使い分けがよさそうです。
- 参考: Astro 関連メモ
Svelte + SvelteKit プロジェクトの作成
Svelte のプロジェクトは次のように npm create svelte
コマンドで簡単に作成できます。
ウィザード形式の質問に答えていくだけで、TypeScript や ESLint、Prettier の導入まで一気にやってくれます。
Svelte プロジェクト(myapp
ディレクトリ)を作成したら、次のように依存モジュールをインストールし、開発サーバーを立ち上げることができます。
$ cd myapp
$ npm install # 依存モジュールをインストール
$ npm run dev -- --open # サーバーを起動してブラウザで開く
開発用サーバーは、デフォルトで 5173
番ポートで待ち受けます。
SvelteKit のルーティング
SvelteKit はファイルベースのルーティングの仕組みを採用しており、src/routes
以下に +page.svelte
という名前のファイルを配置することで、ユーザーがアクセス可能な URL が生成されます。
この特殊なファイル名は SvelteKit のルールなので受け入れるしかありません(逆に、Next.js や Astro のように、ページ用の pages
ディレクトリは存在しません)。
+page.svelte
ファイルを配置するディレクトリによって、次のように URL が対応づけられます。
基本的には、ページごとに専用のディレクトリを作るというスタンスで、これにより、そのページを構成するためのスクリプト(+page.server.ts
など)を同じディレクトリでまとめて管理できるようになっています。
作成する +page.svelte ファイル | 公開される URL |
---|---|
src/routes/+page.svelte | / |
src/routes/about/+page.svelte | /about |
src/routes/foo/bar/+page.svelte | /foo/bar |
src/routes/blog/[slug]/+page.svelte | /blog/[slug] ([slug] は任意のパス) |
例えば、雛形として生成される +page.svelte
ファイルの内容は次のようになっています。
.svelte
という拡張子からも分かるように、これが Svelte コンポーネントです。
現状は HTML の断片的なコードしか含まれていませんが、Svelte コンポーネント独自の構文を使ってコーディングすることができます。
上記の Svelte コンポーネントの内容がそのままレンダリングされるのではなく、実際の表示内容は、src/app.html
というテンプレートファイルに上記のコンテンツを組み込んだものになります。
テンプレート内の %...%
という部分は、SvelteKit によるビルド時に次のように置き換えられます。
%sveltekit.assets%
… アセット用のディレクトリパスに置換されます。%sveltekit.head%
… Web サイトをビルドした結果、必要な<link>
要素や<script>
要素が配置されます。また、Svelte コンポーネント内で<svelte:head>
要素として追加した内容もここに展開されます。%sveltekit.body%
… ページのメインコンテンツが配置されます。つまり、+page.svelte
に記述したマークアップコンテンツです。
ページを追加してみる
プロジェクトの初期状態ではトップページ (src/routes/+page.svelte
) しか存在しないので、試しに次のようなページコンポーネントを追加してみます。
すると、前述のルーティングルール通り、http://localhost:5173/hello
という URL でアクセスできるページが生成されます。
SvelteKit でサイト内の別ページへリンクするときは、上記のように通常の <a>
要素を使用します。
Svelte コンポーネントを作る
.svelte
拡張子の付いたファイルは Svelte コンポーネントとみなされ、このファイルをコンパイルすることによって、HTML/CSS/JS ファイルが生成されます。
Svelte コンポーネントは、別の Svelte コンポーネントからインポートして使用することができます。
Svelte コンポーネントは、次の 3 つのパートで構成されます(必要なものだけ記述できます)。
- スクリプト … TypeScript (JavaScript) コード
- マークアップ … 表示する HTML 要素
- スタイル … 上のマークアップ用の CSS 定義
例えば、下記は Counter
コンポーネントの実装例で、現在のカウント値を増加させるボタンを備えています。
Counter.svelte
ファイルは src
ディレクトリ以下のどこに配置してもよいのですが、src/lib
ディレクトリ以下に配置すると、別のファイルからインポートするときに $lib/Counter.svelte
というパスで参照できて便利です。
スクリプト内で定義した変数 (counter
) や関数は、マークアップ内で { count }
のような埋め込みスクリプトとして参照できます。
button
要素には、次のような Svelte 独自のプロパティ on:click
でイベントハンドラ(increment
関数)を呼び出すように設定しています。
<button on:click={increment}>増やす</button>
increment
関数の中では、次のように count
変数の値を更新しているのですが、Svelte ではこのように変数の値を =
演算子で再代入することで、その変数を参照している部分が再描画される仕組みになっています。
function increment() {
count += 1;
}
Web アプリの世界では、このようにデータと連動させてレンダリングを行う仕組みを「リアクティブ」と呼んでいますが、Svelte は React.js などと比べて簡単にリアクティブな実装を行えるようになっています(React.js では useState
フックを使用して同様の仕組みを実現しています)。
この Counter.svelte
コンポーネントを利用するには、別のコンポーネントから次のようにインポートします。
hello
ページに Counter
コンポーネントを埋め込むことができました。
当然ですが、Counter
コンポーネントは別のコンポーネントから何度でも使いまわすことができ、インスタンスごとに別々の count
変数を保持します(count
値は共有されません)。
Svelte コンポーネントの props 定義
最後に、Svelte コンポーネントにプロパティ (props) を渡せるようにしてみます。
次のように、Svelte コンポーネント内で変数を定義するときに export
を付けるだけで、このコンポーネントを利用する側から値をセットできるようになります。
count
変数の初期値を外からセットするには、次のようにコンポーネントの count
プロパティ (prop) として指定します。
ちなみに、count
変数にはデフォルト値 (0
) を指定してあるので、<Counter />
のようにプロパティを省略して使うことも可能です。
これで、Svelte と SvelteKit の基本的な使い方が分かりました。 いろんな決まりごとを覚えなきゃいけないフレームワークですが、使いこなせば React.js や Next.js よりも手軽に Web アプリを作れるかもしれません。
٩(๑❛ᴗ❛๑)۶ わーぃ