Svelte/SvelteKit の地味に好きなところ
普段から Svelte / SvelteKit を使っているので、その地味に好きなところを紹介します。
また、微妙なところも最後に紹介します。
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 が便利なところ
Svelte では、通常の class='foo' に加えて、class:foo という書き方ができる[1]。
加えて、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 が不要になった[2]。
style も style:name={foo} のように書くことができる[3]。
<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が安定しないのでご了承ください。
日本語資料:
英語資料(このdemoが本当にわかりやすいので、字幕をつけて見てほしい):
自分は昨年発表されてからずっと rune を使っているが、かなり使いやすい。
正直 Svelte4 以前には戻れない。それくらい書き味が良い。
見た目は Vue の Ref であり、省略記法な React の useState であるが、コンパイラを経由することで書き心地とパフォーマンスを両立している。
他にも snippet 構文が最高だったり、$props() を用いた型安全な props の宣言が可能になったりと、 Svelt5 はとても良いものだが、いかんせんリリースが遅れに遅れているのが残念。
年度末の 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
SvelteKit では +page.server.ts と +page.svelte というファイルを用いて、サーバーの処理とクライアントの処理を分離することができる。
Remix でいうところの loader と component に相当するものである(厳密に言えば +page.server.ts には actions も書ける)。
すごいのは、この2つのファイルにまたがっているデータのやりとりが自動的に型安全になることである。
typeof load みたいなことをする必要がなく、+page.server.ts の load 関数の戻り値を変更すると即座に +page.svelte の data の型も変わる。

+page.server.ts の戻り値を変更すると、+page.svelte の data の型も自動的に変わる
また、path の params なども自動的に型安全にしてくれる[4]。
自分で、型を指定する必要はない。
// 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 標準技術を駆使している。
例えば、fetch関数、Request クラス、Stream APIs、Form Actions などなど。
ここ1年ほど React 界隈でやっと 'Form Actions' やら Progressive Enhancement が話題になってきたが、SvelteKit はそれに先駆けて Web 標準を謳っていた印象がある。
これについても過去に記事を書いたので、興味があれば読んでみてください。
Server / Client がファイルベースで分離されているところ
先ほども述べたが、SvelteKit では +page.server.ts と +page.svelte というファイルを用いて、サーバーの処理とクライアントの処理を分離することができる。
また、.server がついているファイルはクライアント側で読み込むことができない。
環境変数も、PUBLIC_ がついているものだけがクライアント側で読み込むことができる。
クライアント側に不要な情報が漏れることを防ぐ仕組みができていることは、開発する上で安心感を与えてくれる。
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 を型安全にすることができるが、これが標準であると嬉しい。
Server Endpoint の Response が型安全にならない (SvelteKit)
Server endpoint の結果も型安全になっていない(普通に fetch 関数で叩いてデータを取得しているだけなので)。
現状、Server Endpoint の型安全を保証したいなら、trpc や Hono RPC と組み合わせる必要がある。
上で述べた通り、SvelteKit は色々と型安全を頑張っているので、もう一踏ん張りしてほしい。
(そもそも Server Endpoint を使う必要はあるのか、全部 +page.server.ts の load 関数内に書いてしまえばいいのでは? という意見もある)
tsx じゃない
個人的には tsx があまり好きになれないのだが、これは好みの問題ではない。
ts/tsx でないことの最大のデメリットは、マクロ系のライブラリが使えないこと。
例えば unplugin という、ビルド時に便利な処理をしてくれるプラグインたちがいるのだが、彼らは大抵 ts/tsx の処理に特化している。
そのため、vue / svelte / astro などの非 ts/tsx なフレームワークの対応が遅れがちになる。
(個人的には unplugin-macros) が使えないのがたまに辛いこともある)
とはいえ、必要な処理を ts ファイルに切り出せばいいので、そこまで困ることはない。データの処理であれば +page.server.ts に逃すこともできるので。
まあ、本当に必要ならば自作するのですが...。
まとめ
ざっくり Svelte / SvelteKit の好きなとこを紹介した。
Discussion
記事を公開していただき、ありがとうございます!
質問なのですが、「直感的に書けるところ」というのはどのような点を指しているのでしょうか?
まず前提として私は「Reactはある程度書けるがSvelteには全く詳しくない、でも興味は持っている」という状態です。
私の印象だと、
など、他ではあまり見られない書き方が多くいです。
なかなか非直感的で辛そうだなーと勝手ながら思っていたのですが、意外と触ってみるとそんなことはないのでしょうか?
Svelteってユーザーからの評価はかなり高い印象があって、ずっと興味がありました。
個人的にReact(JSX)が好きなのもあり、Svelteの書き方が気持ち悪く見えるのがネックで後回しにしてたのですが、意外にそんなことないというのであれば試してみたいなと思った感じです...!
コメントありがとうございます!
「直感的に書けるところ」 という意味の真意は
といったところです。
3つめの部分に関して具体的なコードを書くと、Reactでは
と書くところを、Svelteでは
で書ける、ということです(Reactを悪く言う意図はありません)。
とはいえ、
exportを多用する、$:でリアクティブになるというのは、Svelte に初めて触れる方からはとっつきにくいと言われる意見ですね。自分はなれてしまいましたが。
ただ、Svlete4までのReactivityには一部の直感さを優先した結果起きてしまった非直感さも多くあります。
例えば、top-levelで宣言した変数しかリアクティブにならないこともその一つです。
加えて、
export letとかは受け手側は値を変更しないのにletを使わざるをえないのが違和感がありそうです(実際自分もそうでした)。それらはだいぶSvelte5で解消されると思います。
上に示したコードは、Svelte5で書くと
Repl
と書けるようになります。
また、
export letの代わりに$propsが導入されるので、React に似た感覚で props を受け取ることができるようになります。参考 Repl
なので、Svelte5 になると、React になれている方も、Svelte を始める心理的なハードルが下がると思います。
ただ、まだ正式リリースになっていないので、チュートリアルが古いままなので勉強しづらいですね....
Svelte5のリリースはおそらく数ヶ月先だと思いますが...
ここら辺の資料を眺めていただければなと思います!
返信ありがとうございます!
そうですよね。同じ理由で触るのを躊躇ってました。
なるほど!Svelte5のruneについて、ずいぶん前から知ってはいましたが、「なんとなく使いやすくなるんだなー」程度の浅い認識しかありませんでした...。
自分がSvelteを避けてた理由の大半が解決されているのであれば、触ってみたくなりますね。
改めて、わざわざ回答していただきありがとうございました!
触ってみます!