morishitaです。
前回のエントリでフロントエンドフレームワーク Svelte を紹介しました。
今回は Svelte で Web Components を作ってみようと思います。
Svelte 入門に書いた Typescript, Pug, Sass を使えるようにした状態を前提とします。
Web Components のための設定
Svelte コンポーネントを Web Components としてビルドするにはrollup.config.js の svelte の設定に追加が必要です。
以下に rollup.config.js の抜粋を示しますが、'<== 追加' の行を追加します。
export default { // 〜 略 〜 plugins: [ svelte({ preprocess: sveltePreprocess({ sourceMap: !production }), compilerOptions: { customElement: true, // <== 追加 // enable run-time checks when not in production dev: !production, }, }), // 〜 略 〜 ], // 〜 略 〜 };
これで Web Components がビルドできるようになります。
App.svelte をWeb Components化してみる
以前、Vue.jsでWeb Componentを作ってみた というエントリが書きました。 そのときと同様にSvelteのデフォルトテンプレートにあるコンポーネント App.svelte を Web Component 化してみます。
そのためにちょっとだけ変更が必要です。
次のように App.svelte ファイルの先頭に <svelte:options>
タグを追加します。
<svelte:options tag="my-hello" immutable="{true}"/> <!-- この行を追加 --> <script lang="ts"> export let name: string; </script> <template lang='pug'> main h1 Hello {name}! p | Visit the a(href="https://svelte.dev/tutorial") Svelte tutorial | to learn how to build Svelte apps. </template> <style lang='sass'> main text-align: center padding: 1em max-width: 240px margin: 0 auto h1 color: #ff3e00 text-transform: uppercase font-size: 4em font-weight: 100 @media (min-width: 640px) main max-width: none </style>
<svelte:options>
はコンポーネントのコンパイルオプションを指定するためのもので tag
属性でカスタムタグ名を指定します。
Web Components のカスタムタグ名は -
(ハイフン) を含む必要があるのでここでは、my-hello としておきます。
で、このコンポーネントを次のコマンドでコンパイルします。
> yarn build
この結果、public/build/bundle.js ファイルが生成されます。
ちなみに yarn build
で出力されるファイルはミニファイされています。
このコンポーネントを表示するための HTML ファイルは次のようになります。これを demo.html として保存します。
<!DOCTYPE html> <html lang="en"> <head> <meta charset='utf-8'> <meta name='viewport' content='width=device-width,initial-scale=1'> <title>Svelte app</title> <link rel='stylesheet' href='./global.css'> <script defer src='./build/bundle.js'></script> <!-- ① --> </head> <body> <my-hello name="world"></my-hello> <!-- ② --> </body> </html>
重要なのは <!-- ① -->
と <!-- ② -->
とコメントしている2行です。
①でコンパイルした JavaScript のコードを読み込んでいます。
そして②でカスタムタグを使っています。
もう1つのポイントは Vue による実装だと、ランタイムライブラリも読み込む必要があったのに対して、Svelte ではその必要がないということです。
表示結果は次のとおりです。
表示結果は前回のエントリで紹介したものと同じですが、URL バーの URL を見てみてください。
Dev サーバ(http://localhost:5000
)で動いているのではなく先程の demo.html を表示しています。
実際にブラウザで見てみたい方はこちらで試せます => Svelte app
Popup を Svelte で実装して Web Component 化してみる
次に Vue.jsでWeb Componentを作ってみた で実装したのと同じ Popup タグを実装してみます。
Svelte コンポーネントのコードは次のとおりです。カスタムタグの名前は svelte-popup としています。
<svelte:options tag="svelte-popup" immutable="{true}"/> <template lang='pug'> div +if('isOpen') #popup(on:click="{close}") .dialog .title {title} .content {content} button(on:click="{open}") OPEN </template> <script lang="ts"> export let title: string; export let content: string; let isOpen: boolean = false; function open() { isOpen = true; } function close() { isOpen = false; } </script> <style lang="sass"> #popup position: fixed background-color: rgba(0,0,0,0.3) width: 100vw height: 100vh top: 0 left: 0 .dialog background-color: white width: 80vw margin: 100px auto 0 auto padding: 10px border-radius: 5px .title font-weight: bold </style>
これを表示した様子は次のとおりです。 こちらで試せます。 => Web Components - Svelte Popup
先に示したコードは Vue.jsでWeb Componentを作ってみた で示した Vue による実装になるべく合わせたのでほとんど同じコードになりました。
Pug 内での if
による表示の制御方法が違っているのと、 Svelte ではコンポーネントをクラスとして実装していない部分が主な違いです1。
仕様が簡単でシンプルなので差がつきにくいですが、Svelte による実装の方が少しだけコード量が少なくなりました。
ビルド後の JavaScript ファイルですが、 Svelte による実装ではミニファイした状態で 5KB でした。一方、 Vue による実装では 12KB になりました。Vue ではランタイムも必要になるのでビルド後のフットプリントまで比べると Svelte が有利ですね2。
まとめ
Svelte でも簡単に Web Components を実装できました。 やはりすべてが1ファイルに収まるこの形式はコンポーネントの実装には便利でわかりやすいと思います。もっともコード量が増えて来きたら分割したくなるだろうとは思いますが。
Vue よりも少ないコードで実装でき、ビルド後のフットプリントも小さくなりました。 Web Components だと JavaScript がコンポーネント内のスコープに封じ込められます。 そのため JQuery などで実装したレガシーなスクリプトと混在させてもお互いに干渉せず導入しやすいのではと思っています。
Svelte は活発に開発も続いているので、フロントエンドフレームワークの選定候補として検討してもいいかなと思いました。 しかもIntegrating Frameworks with Webpacker によると Webpacker は Svelte をサポートしているようです。まだ試してないですが、Rails への導入も難しくなさそうです。
最後に
アクトインディではエンジニアを募集しています。 actindi.net