Svelte ・SvelteKit入門
今回のモチベーション
Svelte聞いたことあったけど、触ったことない。なんか学習コスト低くて簡単にreactiveにできるらしいけど、実際にどうなのか。
去年ぐらいにSveltekit出たみたいだけど、使いやすいのか。チュートリアルとか記事とかあさってみよう
2022のフロントエンドフレームワーク利用率は20%: 4位(React,Angular,Vueの次)、6月にversion4が出ましたよ。
マイナーの中ではいいけど、メジャーと比べるとまだまだ普及してない。
特徴
- 仮想DOMを利用しない、事前コンパイル
Svelteは、実行時にアプリケーションのコードを解釈するのではなく、ビルドに際しアプリをクリーンなJavaScriptコードに変換するということです。その結果、フレームワークの抽象化によるパフォーマンス低下が発生することなく、アプリの初回読み込み時のもたつきを心配する必要もありません。
-
事前知識を必要としない学習コストの低さ
素のHTML、CSS、JavaScript/TypeScriptを書いていくだけ。
マークアップとJSをがかけたら調べながら構築できる。チュートリアルが親切。 -
「1個のことを実現する方法は常に1個である」という考え方のもと記法がシンプル
$:
ラベルのみでリアクティビリティを実現する。加えてSvelteコンパイラには、このような無限ループを検知する機能があり、コンパイル時にこれに気づくことができるみたい。 -
国内の利用企業を探したがパッと見つけられず。。ざっと確認したけどアプリケーションの一部だけ利用して、様子見しているところはありあそう。
メジャーなエコシステムの一覧
Svelteの記法
状態管理
<script>
let count = 0;
function increment() {
count += 1;
}
</script>
<button on:click={increment}>
Clicked {count}
{count === 1 ? 'time' : 'times'}
</button>
reactivity
以下のようにラベル付き文で宣言するとリアクティブ宣言(reactive declarations)となり
参照される値が変わるたびにこのコードを再実行する
リアクティブな 値 を宣言するだけでなく、任意の ステートメント をリアクティブに実行することもできます。
<script>
let count = 0;
$: double = count + 2;
$: if (count >= 10) {
alert('count is dangerously high!');
count = 0;
}
function increment() {
count += 1;
}
</script>
<button on:click={increment}>
Clicked {count}
{count === 1 ? 'time' : 'times'}
</button>
<p>{count} double id {double}</p>
変数への代入と状態変化の検知
cart.push(id)
を呼び出していますが、'Add a number' ボタンをクリックしても今のところ何も起こりません。冗長な気もしなくはないですが、代入して追加することで、reactiveになります。
<script>
let count = [];
変数への代入文を書くとreactiveになる
function addToCart(id) {
cart = [...cart, id]
}
要素追加をするがreactiveにならない
function addToCart(id) {
cart.push(id)
}
</script>
props
子コンポーネントでexport
することで、親から渡されたpropsを受け取れる
# App.svelte
<script>
import PackageInfo from './PackageInfo.svelte';
const pkg = {
name: 'svelte',
speed: 'blazing',
version: 4,
website: 'https://svelte.dev'
};
</script>
<PackageInfo {...pkg} />
# PackageInfo/svelte
<script>
export let name;
export let version;
export let speed;
export let website;
$: href = `https://www.npmjs.com/package/${name}`;
</script>
<p>
The <code>{name}</code> package is {speed} fast. Download version {version} from
<a {href}>npm</a> and <a href={website}>learn more here</a>
</p>
logic
#
の文字は常に ブロックの開始 タグと/
の終了 タグをつけて、{}
if,else等々が利用できます。
## if ##
<script>
let count = 0;
function increment() {
count += 1;
}
</script>
<button on:click={increment}>
Clicked {count}
{count === 1 ? 'time' : 'times'}
</button>
{#if count > 10}
<p>{count} is greater than 10</p>
{:else}
<p>{count} is between 0 and 10</p>
{/if}
## each ##
<div>
{#each colors as color, i}
<button style="background: {color}"> {i + 1}</button>
{/each}
</div>
## await ##
<script>
import { getRandomNumber } from './utils.js';
let promise = getRandomNumber();
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>
generate random number
</button>
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
Binding
<script>
let name = 'world';
</script>
<input bind:value={name} />
<h1>Hello {name}!</h1>
Lifecycle
-
onMount
コンポーネントが最初に DOM にレンダリングされた後に実行されます -
beforeUpdate
関数は DOM が更新される直前に作業をスケジュール -
tick
は非同期関数で、次のDOM更新サイクルが完了を待機したいときなどに使用されます。
SvelteKit
去年の12月にversion1がリリース
Announcing SvelteKit 1.0
上記の内容を以下に要約すると、
How is it different?
サーバーでレンダリングされた最初のページがロードされた後、クライアントサイド・ナビゲーションがデフォルトになります。 (nextと同じ)
HTMLの生成もできて、一つのアプリケーションでサーバーサイドの処理もできるので、従来のNodeサーバーとしてアプしょ
What can I use with SvelteKit?
viteでビルドして、TypeScript, ESLint, Prettierとか使えるし、Vitest(ユニットテスト用)を追加するかどうか尋ねられます。TailwindやSupabaseなど、多くの人気プロジェクトにはすでに統合ガイドが存在する。コンポーネントストーリーにはStorybookとHistoireを使うことができるし、npmが提供しているものにももろん全てアクセスできます。
NuxtやNextと特に大きな差分ななさそう。SvelteKitでも同じようなことが簡単な記法で高速でできます的なことが言いたいのかも
Routingとディレクトリ構成
Nextと一緒で、slugで動的なページも対応できるし、ディレクトリベースのルーティングを使用しているので、特に違うところはなさそう。
.server.js
ファイルを置き、そこで load
関数を宣言するとサーバーでのみ実行モジュールとして定義される
API Routeについて
ページ以外にも+server.js
ファイルを追加し、そこでHTTP メソッド GET
、PUT
、POST
、PATCH
、DELETE
に対応する関数をエクスポートすることで、 API ルート(API routes) を作成することもできます。
# +server.js
import { json } from '@sveltejs/kit';
export function GET() {
const number = Math.floor(Math.random() * 6) + 1;
return json(number);
}
# +page.svelte
<script>
/** @type {number} */
let number;
async function roll() {
const response = await fetch('/roll');
number = await response.json();
}
</script>
<button on:click={roll}>Roll the dice</button>
{#if number !== undefined}
<p>You rolled a {number}</p>
{/if}
チュートリアルで作ってコード眺めてみたが、読み慣れてないのもあるが、かなりコードが追いづらいので、色々できるjquery感がある。
npm create svelte@latest my-app
cd my-app
npm install
npm run dev -- --open
感想
確かに書きやすいし、数時間チュートリアルを確認しただけで、なんとなく書けそうなイメージは持てるが生のHTMLを書きたい!というモチベーションもないので、業務で利用するのはなかなか辛い気がする。
簡単に書けすぎて、中規模以上になるとコードが荒れて、負債化しないかなーという気もする。実際にやってみないとわからない。TSとかTailwindも使えるので、コンポーネントをきれいに分ければ、いい感じになるのかも知れれないが、あえてReactを選択しない理由としては弱い気がする。
パッと思いついた用途としては、Svelteはコンパイル時にVanilla JSでDOMへの変更処理なども記述されるから、GitHub Actions経由でbuildして、Svelte(SPA) on S3 + CloudFrontとかで運用するとかなら読み込み速度が早い動的なwebサイト簡単に作れそうなので、一度作ったらあまり保守しなくて良さげなサービスとかなら、サクッと作れて、早いみたいなメリットを受けれる気がする。
Discussion