- 最近 Svelte 5 に Web アプリケーションをアップグレードした後に経験した問題を整理
- deep reactivity 機能と変更されたライフサイクルにより、予期しない動作が発生した
- Svelte 3/4 は長く愛用してきたが、今後 新しいプロジェクトで Svelte を選ぶことはなさそう
高速さの必要性
- Svelte チームは deep reactivity によって性能最適化を試み、より良いパフォーマンスを引き出した
- 従来もコンパイル工程を通じて高速な性能を提供しており、これは他のフレームワークとの差別化要因となる強みだった
- その一方でフレームワークは不透明になり、デバッグが難しくなったが、性能と生産性の面では受け入れ可能なトレードオフだと感じていた
高速さの必要性
- Svelte チームが Svelte 5 で主軸としている大きな変化は「deep reactivity」で、より細かな反応性によって性能を高めようとしている
- 以前の Svelte バージョンでは主に Svelte コンパイラを活用してこの目標を達成していた
- 開発者が新しい概念を直接学ばなくても内部ロジックを組み替えやすかった点が、Svelte の独自性を際立たせていた
- 同時に、このコンパイル工程がフレームワークを不透明にし、複雑な問題のデバッグを難しくしていた
- コンパイラ自体のバグによって原因を特定しにくいエラーが発生し、ときには問題のあるコンポーネントを全面的にリファクタリングしてようやく解決できることもあった
- それでも速度と生産性の面では合理的な妥協だと感じており、プロジェクトを定期的に初期化しなければならない不便さも受け入れてきた
SvelteはJavascriptではない
- Svelte 5 はこの トレードオフを 2 倍にした
- 最大の違いは、抽象化と性能の折衷点がコンパイル段階を越えてランタイム部分にまで入り込んだことにある
- deep reactivity を支えるための Proxy の使用
- 暗黙的なコンポーネントライフサイクル状態
- この 2 つの変更は性能を改善し、開発者 API をより洗練されたものに見せている
- 何が問題なのか。残念ながらこの 2 機能は leaky abstraction の典型例と言える
- 結局のところ、開発者が扱うにはより複雑な環境をもたらす
Proxyはオブジェクトではない
- Proxy の利用により、Svelte チームは開発者に追加作業を求めることなくフレームワークの性能を少し引き上げることができた
- React のようなフレームワークでは、複数のコンポーネントをまたいで状態を渡すと不要な再レンダリングを起こしやすいが、Svelte はそれを減らす目的で Proxy を導入した
- Svelte コンパイラは従来から仮想 DOM の差分比較で生じる一部の問題を回避していたが、Proxy によってさらに性能を高められると判断したようだ
- Svelte チームは Proxy が開発者体験の向上にも寄与すると述べ、「効率性と使いやすさの両方を最大化できる」と主張していた
- 問題は、Svelte 5 が見た目にはより単純に見えても、実際にはより多くの抽象化を追加している点にある
- たとえば配列メソッドの検知に Proxy を使えば、Svelte 4 で必要だった
value = value のようなコードを書かずに済む利点がある
- Svelte 4 ではリアクティビティをトリガーするために、開発者がコンパイラの動作原理をある程度理解している必要があった。一方 Svelte 5 では「コンパイラを忘れてよい」という印象を与えるが、実際にはそうではない
- 新しい抽象化によって得られる利便性のぶんだけ、コンパイラが望むとおりに動作させるために開発者が知っておくべき規則も増えた
- 長いあいだ Svelte を使う中で、個人的には徐々に Svelte store を多用し、リアクティブ宣言はあまり使わなくなっていた
- Svelte store は基本的に JavaScript の概念に近く、
update メソッドを呼ぶ方式も単純で、$ 構文は付加的な利点にとどまっていた
- Proxy はリアクティブ宣言と同様に、「見た目は同じでも、実際には境界で異なる動作をする」という問題を引き起こす
- Svelte 5 を初めて使ったときはすべてがうまく動いたが、Proxy 状態を IndexedDB に保存しようとすると
DataCloneError が発生した
- しかも、どの値が Proxy なのかを確実に把握するには、構造化複製を
try/catch で試す必要があり、これは性能コストが大きい
- 結局、何が Proxy なのかを覚えておき、外部で Proxy を認識できない文脈では毎回
$state.snapshot を使わなければならなくなる
- これは結果として、「抽象化が開発の利便性を高める」という当初の意図とは逆に、開発者へより複雑な規則と手順を要求する状況を生んでしまう
コンポーネントは関数ではない
結論
- 簡単であることは確かに魅力的だが、Rich Hickey が言うように 簡単さは単純さを意味しない
- Joel Spolsky の言うとおり、予期しない動作が起こることは好ましくない
- Svelte はこれまで多くの「魔法」を見せてきたが、今回のバージョンではその魔法を使うために覚えるべきことが増え、得るものより負担のほうが大きくなった
- この記事の要点は Svelte チームを非難することではなく、むしろ Svelte 5(や React Hooks)を好む人が多いことも認識している
- 重要なのは、ユーザーに利便性を提供することと、ユーザーが主導権を持てることのあいだのバランスである
- 本当に良いソフトウェアは「賢さ」ではなく「理解」に基づいている
- AI ツールが進化するにつれて、自分が何をしているのか分からなくさせるツールよりも、すでに蓄積した知恵を活かし、深い理解を助けるツールを選ぶことが重要になる
- Rich Harris とチームには、これまでの楽しい開発体験に感謝したい。この記事が不正確ではないフィードバックになればと思う
7件のコメント
proxy を作る人は楽なんだけど、デバッグする人は腹が立ちますよね(笑)
サイドプロジェクトは solidjs DX ナンバーワン >w< / しあわせ
Svelteのような代替案があったからこそ、React/Next.jsも大きな刺激を受けられたのだと思います。
根本的にSvelteはlanguageなので、UIを記述する言語が進むべき方向も、うまく示してくれたらと思います。
私はReactを使います
過ぎたるは及ばざるがごとし
心魔に取り憑かれる
屋上屋を架す
React と、特に Next の影響を少なからず受けて、妙な方向に変わってしまったと思います。
+pageは Svelte を知らない状態で見ると理解しづらいですし、$stateや$derivedのような rune は React を追っているように見える一方で、むしろ変数の前に$:を付けていた時代のほうがまだ良かったように思えます。{#each a in array} {/each}のような古めかしい文法も我慢できなくはないですが、やはり面倒です。選択的 reactivity による性能改善というのであれば、SolidJS のほうがはるかに良い方向性だと思います。JSX をそのまま使うぶん、React から移行しやすいのもありますしね。SolidJS が相対的にあまり注目されていないのが不思議なくらいです。Signals は Gartner hype cycle の Trough of disillusionment に向かっているように思えますね 🤔 ユースケースが徐々に定まっていくにつれて、評価も改善していくのではないかと思います
Hacker Newsの意見
最初はrunesにあまり興味がなかった。しかし、
.svelteテンプレートにリアクティブな外部コンポーネントを取り込み、内部でリアクティビティをカプセル化できるようになったときに考えが変わった。これは、vitestのテストを書ける一方でリアクティビティの利点も得られることを意味する。本当に強力で、AFAIK、フロントエンドの世界では独特だ商用展開されたSvelteKitアプリケーションを積極的に開発しており、その経験について考えを共有したい
+pageのようなルーティング構造を扱う必要がなかった。Svelteファイルを好きな場所に置けて、モダンなフレームワークの利点を享受しつつもシームレスにレンダリングされていたEmberJSが消えてしまったのは惜しい。APIはこの10年かなり安定していた。皮肉なことに、この10年EmberJSアプリを書いてきた人の方が、React、Svelte、Vueなどで同じことをしてきた人より、移行に苦労しないだろう
著者が記事冒頭に挙げている2つのGithubリンクは同じ問題を指しており、その問題には解決策がある(
use $state.raw)Svelte 5はJavaScriptではないという意味では<i>最悪の</i>やり方だ。jsの問題を解決せず、いくつかのフロントエンド問題に対する漏れのある抽象化を提供している。Solidの方がSvelteより良い方向性だと思う。Solidは新しい言語に依存していないからだ。しかし、jsが理想的ではないので、jsではないものを作ろうとする本能は理解できる。Elmはsvelteの先駆けだ。だが、もっと良いものを作れると思う……[0]
Svelte 4のストアが本当に嫌いだったので、Svelte 5を使い始めた。新しいプロジェクトでSveltekitとSvelte 5を使っていて、言わざるを得ない……SveltekitとSvelteの技術の方が技術的には優れているのに、Reactの生産性は依然として無敵だ
+page.server.tsや+page.svelteやその派生形の名前が付いているので、コード検索がしづらい。Svelteのツール群はtscやESLintとは別に存在していて、CIに統合したり開発で使ったりするのがより難しいコールバックにクロージャを渡したときの予期しない挙動を理由に、SvelteはJavaScriptではないと言うのは奇妙に感じる。より良いタイトルは「Svelte 5が予想外で嫌いだ」だろう
純粋なJavaScriptを使えるコンポーネントやアプリを構築できるライブラリを探しているなら、Litをチェックしてみてほしい: Lit
理にかなったフロントエンド体験がほしい? 素のJavaScript、Web Components、htmx、Blazorを使おう