本セッションの登壇者
セッション動画
Yuichiro Yamashitaと申します。Svelteのメンテナをしています。Twitterもやっているのでフォローしていただけるとうれしいです。

今日はSomething with Svelteというテーマで発表したいと思います。
Svelteの特徴 - 他のライブラリとの併用
まずSvelteをご存じない方のために、30秒だけSvelteのことを紹介したいと思います。Rich Harrisという方が作ったライブラリです。公式サイトにあるように、ReactやVueに比べて少ない記述量で実装できること、仮想DOMがないこと、直感的なリアクティビティの3点が特徴です。また、既存スタックに埋め込めるということも個人的には良いポイントだと思っていて、本日はこれについて紹介したいと思います。

おそらく多くの方は「Svelteが最近海外で流行りだしているというのは知っているし、使ってみたいけれど、業務で使うとしたら事例が多いReact / Vue / Angularのどれかだよなぁ」と思われていることでしょう。
かくいう私も業務ではVue.jsを使用していて、Vue2からVue3への移行をがんばっています。しかし同時にSvelteも使用しています。
今日は「業務で使うならReact / Vue / Angularのどれか」ではなく、「これからの時代はReact / Vue / AngularのどれかとSvelte」ということをご紹介したいと思います。
Svelteのユースケース
では、SvelteをReact / Vue / Angularといっしょに使うユースケースを紹介します。1つ目は遅延なく60fpsが要求されるような、性能が求められる場合です。
これはReactアプリケーションのデモで、文字を打っていくとグラフが更新されますが、60fpsには追いついていません。それに対してSvelteのデモでは、ある程度文字を打ち続けてもずっと60fpsが維持されており、Svelteのほうが性能がいいことがわかります。Reactのデモはとくに非同期モードやConcurrentモードなどは使っていませんが、Svelteも同様にそういったものを使わずに60fpsを維持できています。

2つ目のユースケースとして小さなバンドルサイズが要求される場合があります。
たとえばこれは弊社のflyleというプロダクトマネジメントを支援するサービスですが、右下にチャットのモーダルが出ています。こういったモーダルは、ランタイムのサイズが小さい方が良かったりすると思います。

たとえばVueとの比較でいうと、Svelteではなにもしないとランタイムサイズが1.58KBしかないのに対して、Vueは20.21KBあり、比較的小規模のアプリを作るうえではSvelteのほうが小さなランタイムになります。

Svelteと他のライブラリの併用方法
では、このような60fpsを維持したい・小さなバンドルサイズでランタイムを動かしたいといったケースがあったときに、どうやってReact / Vue / Angularと併用するのか。今日は、
- Web Componentsを使う
- 単にJavaScriptを埋め込む
- 他のライブラリと共存する
の3つを紹介したいと思います。
1つ目のWeb Componentsについては、SvelteでもCustom Elementを作ることができます。公式サイトのドキュメントにあるように、<svelte:options tag="my-element" />
でタグの名前をつけるだけでWeb Componentの実装が完了します。あとは作成したCustom Elementを使うだけでよく、非常に簡単に実現できます。詳細な説明は省きますが、これらの参考資料を見ていただければ実装できるかと思います。

2つ目のJavaScriptを埋め込む方法はシンプルで、
- Svelteのファイルをインポートする
new
でコンポーネントを生成するtarget
にDOMのどこにレンダリングするかを指定する- 必要な
props
がある場合はそれを渡す
ということをするだけで、JavaScriptで簡単に埋め込むことができます。今のところ、弊社でSvelteを使っている箇所ではこの方法(JavaScriptで埋め込む)を採用しています。

3つ目は他のライブラリと共存する方法で、デモをお見せしたいと思います。このアプリケーションの外側はVueでできていて、グレーの四角い枠の中はSvelteの世界になっています。たとえばVue側でボタンをクリックしてcount
をインクリメントすると、四角い枠の中のSvelte側のcountもインクリメントされます。同様に、Svelteの中でcount
をインクリメントすると、Vue側のcount
もインクリメントされます。これはVueとSvelteを共存させていますが、ReactとSvelteでも同様の共存ができます。

今回はVueとSvelteを共存させるコードを簡単に紹介します。基本的には先ほどのJavaScriptで埋め込む方法と同じで、ref="svelteWrapper"
の要素をtarget
として、SvelteComponent
をnew
して、svelteWrapper
の中にSvelteComponent
をレンダリングします。

プロパティを渡すときは、Vueのコンポーネントで受け取ったprops
をそのまま、もしくは必要なものだけをprops
に渡せばSvelte側に反映されます。また、VueのwatchEffect
や watch
といった Reactivity APIを使うことで、Vueコンポーネントのprops
が更新されるたびにSvelte側にも反映し、 まずVueからSvelteへのプロパティの共有ができるようになります。

そして、Svelte側でprops
を更新したときに双方向バインディングを実現したい場合は、SvelteでEventDispatcher
を定義して、Vue側ではイベントが発火したら処理をするというようなPub-subパターン的な方法があります。

また、単にprops
が変わったらこういう処理を実行する、ということをSvelteにprops
として渡してあげるという方法もあります。これらの方法で双方向バインディングが実現できます。

あとはVueからSvelteコンポーネントの関数を実行することもできて、Svelteでexport 関数
とすると、その関数はVueのコンポーネントからも呼べます。

ReactとSvelteでも同様のことができて、サンプルが私のGithubにあるのと、ReactとSvelteの共存方法を他のSvelteメンテナが動画にしているので、それも見ていただけるとうれしいです。
- Vue3とSvelteの共存サンプル
- ReactとSvelteの共存サンプル (React初心者なので変なコードがあればPRお願いします...)
- ReactとSvelteの共存方法解説動画
まとめ
遅延なく60fpsを実現したい場合や、小さなバンドルサイズが要求される場面ではSvelteとなにか別のライブラリを併用するという選択肢があります。実装方法として今日ご紹介したのは、
- Web Components
- JavaScriptで埋め込み
- 他のライブラリとの共存
の3つです。
以上で発表は終わりです。ありがとうございました。