普段から Svelte / SvelteKit を使っているので、その地味に好きなところを紹介します。
また、微妙なところも最後に紹介します。
Note
本記事では Svelte5 を前提としています。
執筆時点では Svelte5 はまだ RC版です。
Who are you?
- ryoppippi
Frontendは Svelte メインで書いているReactも書くが、少なめAstroは書いているSolidでも簡単なものを作ったことがあるVue3はほぼ触ったことがない
Svelte の好きなところ👍
直感的に書けるところ
Svelte は直感的に書けるところが好き。
見た目も html に近い。
エディタの支援もしっかりしているので、書いていてストレスがない。
速い、軽い、うまい
結構適当に作っても、speedInsight でいい点数を取りやすい。
また、ビルド後のファイルサイズも小さいので、デプロイもしやすい(特に Cloudflare Pages との相性がいい)。
型安全がしっかりしているところ
tsx と比較して型安全が疎かであるように思われているが、Svelte は型安全がしっかりしている。
<script lang="ts">
const fruit: 'apple' | 'orange' | 'banana' | 'grape' = 'apple';
</script>
{#if fruit === 'apple'}
<p>🍎</p>
{:else if fruit === 'orange'}
<p>🍊</p>
{:else if fruit === 'banana'}
<p>🍌</p>
{:else if fruit === 'grae'}
<!-- grape が typo しているのでエラーになる -->
<p>🍇</p>
{:else}
<!-- fruit は never なので cast が必要 -->
<p style="color: red">Unknown fruit {fruit as unknown as string}</p>
{/if}
このように、ちゃんと型安全が効いている。 Svelte5 からは template 部分でも TypeScript の記法が使えるようになったため、より柔軟性の高い記述が可能になった。
もちろん要素の属性に渡す値や関数も型安全である。
また、後述する SvelteKit ではより面白い型安全機能が追加されている。
class:name/ style:name が便利なところ
Note
まず、class が className でない所。短く書けるので楽…。
Svelte では、通常の class='foo' に加えて、class:foo という書き方ができる^https://svelte.jp/docs/element-directives#class-name。
加えて、class:foo={true} という書き方で条件を指定することで、クラスの付与を制御できる。
<p class="foo" class:bar class:baz="{true}" class:qux="{false}" />
これは tailwindcss や UnoCSS などの utility-first CSS フレームワークとの相性がいい。
<p
class="text-white"
class:text-red="{isDanger}"
class:text-blue="{isInfo}"
class:text-green="{isSuccess}"
class:text-yellow="{isWarning}"
/>
tsx で似たようなことをやろうとすると、clsx 等の追加のライブラリが必要になり、そのぶん runtime cost が増える。
標準機能でこれができるのは、とても便利。
おまけに可読性が高い。
ちなみに、最近 Astro にも class:list が追加されて、clsx が不要になった^https://docs.astro.build/en/reference/directives-reference/#classlist。
style も style:name={foo} のように書くことができる^https://svelte.jp/docs/element-directives#style-property。
<p
style='color: red'
style:margin-top='{foo}rem'
style:background-color={darkMode ? 'black' : 'white'}
/>
この書き方は、特に css variables を使うときに便利である。
<script>
const color = '#ff3e00';
</script>
<p style:--color="{color}" />
<style>
p {
color: var(--color);
}
</style>
こんな感じで、外部変数を既存の css に適用することができる。
style タグが使いやすいところ
Svelte では、style タグ内で書いたスタイルは、そのコンポーネント内でのみ有効である。
いわゆる scoped スタイルである。
<style>
p {
color: red;
}
</style>
もちろん、global なスタイルも書ける。
<style global>
:global {
body {
background-color: black;
}
}
</style>
また、未使用のスタイルがあれば警告を出してくれるし、ビルド時に未使用のスタイルは自動的に削除される。 とても便利。
each blocks に :else が使えること
本当に地味なポイントだが、each blocks に :else が使えて嬉しい。
{#each items as item (item.id)}
<p>{item}</p>
{:else}
<p>No items</p>
{/each}
for-else 構文ってどんな言語にあるんだろう。
Python とか Zig とか?
Rune が使いやすいところ
Svelte5 で導入される rune が使いやすい。 rune についてここで語ると長くなるので、詳しくは色々記事をご覧ください。
ただ、正式リリースまではAPIが安定しないのでご了承ください。
日本語資料: https://baseballyama.github.io/techfeed-20240424-svelte5/1 https://docs.google.com/presentation/d/14wc-XSfmXxfHu-2YMM8gJHANzZbAdkS8YSwS-rvf48U/edit https://zenn.dev/tomoam/scraps/375fb71c09fe0f
英語資料(このdemoが本当にわかりやすいので、字幕をつけて見てほしい): https://www.youtube.com/watch?v=_SpO5T96AYY https://svelte-5-preview.vercel.app/docs/runes
自分は昨年発表されてからずっと rune を使っているが、かなり使いやすい。
正直 Svelte4 以前には戻れない。それくらい書き味が良い。
見た目は Vue の Ref であり、省略記法な React の useState であるが、コンパイラを経由することで書き心地とパフォーマンスを両立している。
他にも snippet 構文が最高だったり、$props() を用いた型安全な props の宣言が可能になったりと、 Svelte5 はとても良いものだが、いかんせんリリースが遅れに遅れているのが残念。
年度末の Advent Calender では思う存分 rune についての記事を書きたい。
<script lang="ts">
import type { ComponentProps } from 'svelte';
type Props = { count: number } & ComponentProps<typeof HTMLDIVElement>;
const { cont, ...rest }: Props = $props();
</script>
{#snippet countDiv(count: number)}
<div {...rest}>Count: {count}</div>
{/snippet} {@render countDiv(count)}
SvelteKit の好きなところ👍
Zero-effort type safety
https://svelte.jp/blog/zero-config-type-safety
SvelteKit では +page.server.ts と +page.svelte というファイルを用いて、サーバーの処理とクライアントの処理を分離することができる。 Remix でいうところの loader と component に相当するものである(厳密に言えば +page.server.ts には actions も書ける)。
Note
+page.server.ts では load 関数をエクスポートすることで、サーバーサイドでのデータ取得を行う。 +page.svelte では data という変数をエクスポートすることで、クライアントサイドでのデータ取得を行う。
クライアントサイドでの処理は +page.svelte 内の script タグ内で行う(Vue3 の script setup に相当)。
すごいのは、この2つのファイルにまたがっているデータのやりとりが自動的に型安全になることである。 typeof load みたいなことをする必要がなく、+page.server.ts の load 関数の戻り値を変更すると即座に +page.svelte の data の型も変わる。
+page.server.ts の戻り値を変更すると、+page.svelte の data の型も自動的に変わる
また、path の params なども自動的に型安全にしてくれる^https://kit.svelte.jp/docs/routing#page-page-server-js。 自分で、型を指定する必要はない。
// src/routes/blog/[slug]/+page.server.ts
export async function load({ params }) {
// slug は string であることが型安全に保証される ↓
const post = await getData(params.slug);
if (post) { return post; }
return error(404, 'Not found');
};
コードを書けば自動で型がついてくれる体験は病みつきになる。
Web 標準技術を駆使しているところ
SvelteKit は、Svlte の文法こそ独自であるものの、ベースとなる技術は Web 標準技術を駆使している。
https://kit.svelte.jp/docs/web-standards
例えば、fetch関数、Request クラス、Stream APIs、Form Actions などなど。
ここ1年ほど React 界隈でやっと ‘Form Actions’ やら Progressive Enhancement が話題になってきたが、SvelteKit はそれに先駆けて Web 標準を謳っていた印象がある。
これについても過去に記事を書いたので、興味があれば読んでみてください。
/blog/2023-04-28-zenn-aea8dcbc21c39e-ja
Server / Client がファイルベースで分離されているところ
先ほども述べたが、SvelteKit では +page.server.ts と +page.svelte というファイルを用いて、サーバーの処理とクライアントの処理を分離することができる。
また、.server がついているファイルはクライアント側で読み込むことができない。
環境変数も、PUBLIC_ がついているものだけがクライアント側で読み込むことができる。
クライアント側に不要な情報が漏れることを防ぐ仕組みができていることは、開発する上で安心感を与えてくれる。
/blog/2023-04-26-zenn-8addfe62eb4d3e-ja
Svelte / SvelteKit の微妙なところ🤔
色々あるが…
対応しているライブラリが(比較的)少ない
React に比べると、対応しているライブラリが少ない。
特に UI 周り。 shadcn-svelte や melt-ui など使い勝手のいいものはそこそこあるが、まだまだ少ない。 React Aria の Svelte 版があればいいのに…。
また、vueUse に匹敵するような便利関数詰め合わせライブラリもまだまだ発展中。
そもそも Svelte5 でこれまでの store から rune への移行の過渡期であるため、安定してこないところもある。
とはいえ、ある程度素の JavaScript ライブラリが使えるので、そこまで困ることはない。
route が型安全にならない (SvelteKit)
fetch 関数を使う時や、a タグでリンクを貼るときの文字列が型安全にならない。
一応、存在しないpathを指定すると、ビルド時にエラーが出るので 気づくことはできるが、開発中に型安全であると嬉しいなと思う(Next.jsのtypedRoutesみたいなもの希望)。
現状ではvite-plugin-kit-routes というプラグインで route を型安全にすることができるが、これが標準であると嬉しい。 https://www.kitql.dev/docs/tools/06_vite-plugin-kit-routes
Server Endpoint の Response が型安全にならない (SvelteKit)
Server endpoint の結果も型安全になっていない(普通に fetch 関数で叩いてデータを取得しているだけなので)。
現状、Server Endpoint の型安全を保証したいなら、trpc や Hono RPC と組み合わせる必要がある。
上で述べた通り、SvelteKit は色々と型安全を頑張っているので、もう一踏ん張りしてほしい。
(そもそも Server Endpoint を使う必要はあるのか、全部 +page.server.ts の load 関数内に書いてしまえばいいのでは? という意見もある)
Note
ちなみに Form の型安全については、superfoms というライブラリがある。
tsx じゃない
個人的には tsx があまり好きになれないのだが、これは好みの問題ではない。 ts/tsx でないことの最大のデメリットは、マクロ系のライブラリが使えないこと。
例えば unplugin という、ビルド時に便利な処理をしてくれるプラグインたちがいるのだが、彼らは大抵 ts/tsx の処理に特化している。
そのため、vue / svelte / astro などの非 ts/tsx なフレームワークの対応が遅れがちになる。
(個人的には unplugin-macros) が使えないのがたまに辛いこともある)
とはいえ、必要な処理を ts ファイルに切り出せばいいので、そこまで困ることはない。データの処理であれば +page.server.ts に逃すこともできるので。
まあ、本当に必要ならば自作するのですが…。
まとめ
ざっくり Svelte / SvelteKit の好きなとこを紹介した。