9 ポイント 投稿者 GN⁺ 2025-02-19 | 7件のコメント | WhatsAppで共有
  • 最近 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 を使わなければならなくなる
    • これは結果として、「抽象化が開発の利便性を高める」という当初の意図とは逆に、開発者へより複雑な規則と手順を要求する状況を生んでしまう

コンポーネントは関数ではない

  • 2013 年ごろに仮想 DOM が人気を得た理由は、アプリケーションを関数の組み合わせとしてモデル化できたからだった
    • Svelte は仮想 DOM の代わりにコンパイラを使い、ライフサイクル関数を簡素化して性能を高める方式を維持してきた
    • しかし Svelte 5 では、ライフサイクルの概念が React Hooks に似た形で再び追加された
  • React における Hooks は、ライフサイクルメソッドの状態関連コードを減らすための抽象化である
    • コードはきれいになるが、setTimeout で状態を参照するときのように、開発者が注意すべき点も多い
    • Svelte 4 でも、コンポーネントのアンマウント時点で非同期コードが DOM 要素にアクセスすると問題が起こり得た
    • いまや Svelte 5 では、状態変更とエフェクトを調整するために、コンポーネントライフサイクルへ暗黙的な状態が追加されたように見える
  • $effect に関する公式ドキュメントでは、次のように説明している:
    > 「$effect はどこにでも配置できるが、コンポーネントの初期化中(または親エフェクトが有効なあいだ)に呼び出されなければならず、コンポーネント(または親エフェクト)がアンマウントされると消える」
  • これは、ライフサイクルにはマウント/アンマウントの 2 段階しか存在しないという説明とは異なり、状態変化を追跡しなければならない複雑なエフェクト構造があることを示唆している
  • 公式ライフサイクル文書 では「before update/after update はない」としながらも、$effect.pretick のような新しい概念が登場する
  • これは実質的に、マウント/アンマウント以外にも状態変化のタイミングへの理解が必要であることを意味する
  • 実際の利用で問題になったのは、Svelte と無関係な関数に渡した状態までもがコンポーネントライフサイクルに縛られる点だった
  • たとえば、モーダルウィンドウを store で管理しながらコールバックを子コンポーネントへ渡すパターンを使っていた
    const { value } = $props()  
    const callback = () => console.log(value)  
    const openModal = () => pushModal(MyModal, { callback })  
    
  • もしこのコードがモーダルを呼び出す側のコンポーネント内部にあるなら、そのコンポーネントが先にアンマウントされ、その時点で value は undefined に変わる
  • このリポジトリには最小再現例が掲載されている
  • つまり、コンポーネントのライフサイクルが終わった後も生きているコールバックで参照していた props が、突然 undefined になってしまう
  • これは素の JavaScript とは異なる動作であり、Svelte が独自にガベージコレクションのような処理をしているように見える
  • エンジニアリング上の理由はあるのだろうが、予想外の挙動で驚かされた

結論

  • 簡単であることは確かに魅力的だが、Rich Hickey が言うように 簡単さは単純さを意味しない
  • Joel Spolsky の言うとおり、予期しない動作が起こることは好ましくない
  • Svelte はこれまで多くの「魔法」を見せてきたが、今回のバージョンではその魔法を使うために覚えるべきことが増え、得るものより負担のほうが大きくなった
  • この記事の要点は Svelte チームを非難することではなく、むしろ Svelte 5(や React Hooks)を好む人が多いことも認識している
  • 重要なのは、ユーザーに利便性を提供することと、ユーザーが主導権を持てることのあいだのバランスである
  • 本当に良いソフトウェアは「賢さ」ではなく「理解」に基づいている
  • AI ツールが進化するにつれて、自分が何をしているのか分からなくさせるツールよりも、すでに蓄積した知恵を活かし、深い理解を助けるツールを選ぶことが重要になる
  • Rich Harris とチームには、これまでの楽しい開発体験に感謝したい。この記事が不正確ではないフィードバックになればと思う

7件のコメント

 
firea32 2025-02-24

proxy を作る人は楽なんだけど、デバッグする人は腹が立ちますよね(笑)

 
bichi 2025-02-21

サイドプロジェクトは solidjs DX ナンバーワン >w< / しあわせ

 
pcj9024 2025-02-20

Svelteのような代替案があったからこそ、React/Next.jsも大きな刺激を受けられたのだと思います。
根本的にSvelteはlanguageなので、UIを記述する言語が進むべき方向も、うまく示してくれたらと思います。

私はReactを使います

 
iolothebard 2025-02-20

過ぎたるは及ばざるがごとし
心魔に取り憑かれる
屋上屋を架す

 
colus001 2025-02-20

React と、特に Next の影響を少なからず受けて、妙な方向に変わってしまったと思います。+page は Svelte を知らない状態で見ると理解しづらいですし、$state$derived のような rune は React を追っているように見える一方で、むしろ変数の前に $: を付けていた時代のほうがまだ良かったように思えます。{#each a in array} {/each} のような古めかしい文法も我慢できなくはないですが、やはり面倒です。選択的 reactivity による性能改善というのであれば、SolidJS のほうがはるかに良い方向性だと思います。JSX をそのまま使うぶん、React から移行しやすいのもありますしね。SolidJS が相対的にあまり注目されていないのが不思議なくらいです。

 
xiniha 2025-02-19

Signals は Gartner hype cycle の Trough of disillusionment に向かっているように思えますね 🤔 ユースケースが徐々に定まっていくにつれて、評価も改善していくのではないかと思います

 
GN⁺ 2025-02-19
Hacker Newsの意見
  • 最初はrunesにあまり興味がなかった。しかし、.svelte テンプレートにリアクティブな外部コンポーネントを取り込み、内部でリアクティビティをカプセル化できるようになったときに考えが変わった。これは、vitestのテストを書ける一方でリアクティビティの利点も得られることを意味する。本当に強力で、AFAIK、フロントエンドの世界では独特だ

    • フロントエンド開発者の大半は、まったくテストをしない。TypeScriptは正しさを担保するために人々が使う道具であり、それにはもっともな理由がある。しかし、svelteユーザーは常にtypescriptに対して狭い見方をしてきたし、それにも理由がある
    • 個人的にはテスト可能なフロントエンドコードを書くのが好みで、Svelte 5はその点で革新的だ。ブラウザでリアクティブでありながら、単体テストも十分に書ける
    • こうしたことをすべて踏まえても、ブログ記事は真実を語っている。プロキシを追加するのはとても不快に感じる。ReactとVueは抽象化の上に抽象化を積み始めたときに自分には合わなくなったが、プロキシはその出発点だった
    • Svelte 5がJavaScriptではないことこそが、<i>Svelte 5を好きな理由</i>だ
    • フロントエンド/Webを理にかなって実現する主な方法は2つあると思う
        1. 静的HTML、またはサーバーサイドレンダリングされたテンプレート。おそらくHTMX
        1. JavaScriptにコンパイルされる言語/プラットフォーム。少なくともTypeScriptだが、HTMLとCSSは実際かなり良いものだと思っているので、JSX、React、Tailwindなどは<i>除外</i>される。一方で、Svelte 5やいくつかの他のフレームワークは、素のTypeScriptより実際に改善されている
    • Svelte 5はカテゴリ2では明確な勝者だ
    • 優れたHTMLテンプレート、簡単で筋の通った状態伝播、モジュール式コードを簡単に書ける機能を備えている。CSSとうまく連携し、簡単な使い捨てアプリやツールなら1〜2ファイルで作れることも多いし、より大きく本格的なアプリケーションも可能だ。Svelte 4より魔法っぽさや意外性が少なく、正直使っていて楽しい。ありがたいことにIndexedDBのことを気にしなくていい
    • 今日ではJavaScriptを1行でも書く理由がまったく思いつかないが、まあ人それぞれだ
  • 商用展開されたSvelteKitアプリケーションを積極的に開発しており、その経験について考えを共有したい

    • SvelteKitに最初に惹かれた理由は、そのシンプルさだった。プロジェクトをセットアップした後は、モダンなフレームワークの利点を複雑さなしで享受しながら、一度に1つのHTML/JS/CSSファイルに取り組めた。これは、ApacheサーバーにHTMLファイルを置くだけで何もかも動いていた初期のWeb開発時代を思い出させた
    • しかし、Svelteがそのシンプルなパラダイムから離れていくのを見るのは残念だ。Rich Harrisは当初から、Svelteの使いやすさとシンプルさを主要な売り文句にしていた。今のSvelteKitのバージョンが悪いわけではないが、以前のバージョンの方が好みだった。当時は +page のようなルーティング構造を扱う必要がなかった。Svelteファイルを好きな場所に置けて、モダンなフレームワークの利点を享受しつつもシームレスにレンダリングされていた
    • こうした変化は、以前は不要だった複雑さを追加しており、そもそものSvelteの魅力から離れていく恐れがある。自分はすでに知っているものを基準に選んでいた
  • EmberJSが消えてしまったのは惜しい。APIはこの10年かなり安定していた。皮肉なことに、この10年EmberJSアプリを書いてきた人の方が、React、Svelte、Vueなどで同じことをしてきた人より、移行に苦労しないだろう

    • 残念ながらEmberチームは初期にいくつか奇妙な判断をしており、素のJavaScriptと比べて容易に理解できるものではなかった(その大半は今では修正されている)
    • JavaScriptかどうかは、APIの安定性に比べればあまり重要ではない
    • 個人的には、JavaScriptの問題は変化が多すぎることだ
  • 著者が記事冒頭に挙げている2つのGithubリンクは同じ問題を指しており、その問題には解決策がある(use $state.raw

    • Svelte 2か3の頃からSvelteのファンだった。フレームワークの利点を享受しつつ、素のHTML/CSS/JSを書くのに最も近かったからだ(そしてSassとTypeScriptも使える)。素晴らしい
    • Svelte 5はrunesが奇妙で不安に感じられた。プロジェクトをアップグレードし、別のプロジェクトでも作業したあとでは、そこまで悪くない。Svelte 5は状態処理の古い方式と新しい方式を混在させることを許さず、エラーメッセージも大半は有益だ
    • このコメント欄ではhtmxや素のJSの方が客観的に優れていると言う人たちがいるが……いや? あなたがやっていることにはそうかもしれないが。個人的にはSvelteの方がReactよりずっと理解しやすい。ベンチマークを気にする人向けに言えば、SvelteはSolidJSと同じくらい速い(ReactユーザーはSolidに簡単に移行できそうだ。文法が似ているように感じる)
  • 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のパッケージの大半はいまだにストアを使っているので、2つのバージョンの世界と格闘しなければならず、コードを書くのがときどき本当に混乱する。また、Svelte HMRはまだ初期段階のようで、Svelteモジュールが再読み込みされると状態を壊すことがある
    • Svelteを本当に好きになりたい。レンダリング速度はかなり速いし、その背後にあるアイデアも気に入っている。しかし、Reactの生産性は無敵だ
  • コールバックにクロージャを渡したときの予期しない挙動を理由に、SvelteはJavaScriptではないと言うのは奇妙に感じる。より良いタイトルは「Svelte 5が予想外で嫌いだ」だろう

  • 純粋なJavaScriptを使えるコンポーネントやアプリを構築できるライブラリを探しているなら、Litをチェックしてみてほしい: Lit

    • 深いリアクティビティのためのsignals用追加パッケージがあり、今後のSignals TC39提案との統合を目指している: Signals
    • LitはPhotoshop、Reddit、Home Assistant、The Internet Archiveのような主要アプリで使われている
  • 理にかなったフロントエンド体験がほしい? 素のJavaScript、Web Components、htmx、Blazorを使おう

    • JSフレームワークは、どんな理由であれ狂気だ