Svelteを使って実際に画面を作ってみよう
前半では、Svelteコンポーネントの基本的な構造を説明しながら、モダンフロントエンド開発における「コンポーネント」が解決した問題意識について学びました。後半では、Svelteの開発ツールを使って実際にWebフロントエンドを開発してみましょう。
読者の皆さまは、ここ数年の激しい社会変化の中で、ビデオチャットツールを使う場面が増えた方が多いのではないでしょうか。こうしたフロントエンド開発のチュートリアルでは、TODOリストやブログサイトを題材にすることが多いのですが、たまには少し目新しい題材として、ビデオチャットツールを取り上げてみたいと思います。
もちろん実際にビデオ通話機能を開発するわけではなく、フロントエンド部分だけを簡単に、モックアップやプロトタイプのようなイメージで作ってみたいと思います。イメージとしては、こんな感じになります。
プロジェクトを作成
それでは、早速はじめましょう。ここでは、既に以下のJavaScriptの開発環境は構築してあることを前提とします。
- コマンドライン環境
- お好きなテキストエディタ(特にこだわりがなければ、Visual Studio Codeがオススメです。Svelte公式のチュートリアルでも推奨されています)
- Node.js(v16.6.2 で動作確認しました)
- npm
開発環境が準備できたら、コマンドラインで次のコマンドを実行して、プロジェクトを作成しましょう。npx degit
を使うことで、GitHub上で公開されているSvelteのプロジェクトテンプレートをコピーして、プロジェクトの初期状態として使うことができます(ちなみに、degit
もSvelteの開発者と同じ人が作ったツールです)。
$ npx degit sveltejs/template codezine-my-svelte-videochat $ cd codezine-my-svelte-videochat
プロジェクトの初期状態で配置されるファイルを見てみましょう。src
フォルダには、Svelteで書かれたコードであるApp.svelte
と、動作確認用のスクリプトmain.js
が配置されています。これから、これらを書き換えて自分たちのコードに置き換えていきます。
public
フォルダにあるファイルは、動作確認用のWebサーバからそのまま配信されます。
今回は触れませんが、rollup.config.js
も重要なファイルです。これは、Svelteで書かれたコードを通常のJavaScriptモジュールに変換する(トランスパイル/バンドリング)するための設定が書かれたファイルで、Svelteのプラグインをインストールしたり、Svelteコンパイラの設定を変更したりする場合に編集することになります。覚えておきましょう。
$ tree . ├── README.md ├── package.json ├── public │ ├── favicon.png │ ├── global.css │ └── index.html ├── rollup.config.js ├── scripts │ └── setupTypeScript.js └── src ├── App.svelte └── main.js
HTMLとテンプレート構文を使って画面の構成要素を作成
まずは、App.svelte
の内容を次のように書き換えて、ビデオ通話画面の全体像を作成してみます。この時点ではコンポーネント分割もせず、ボタンなどを押しても特に何も起きないハリボテのようなものにしておきましょう。
<div class="participant p1"> <span>参加者猫 (1) (自分)</span> <img src="https://placekitten.com/320/240?image=1"> </div> <div class="participant"> <span>参加者猫 (2)</span> <img src="https://placekitten.com/320/240?image=2"> </div> <div class="participant"> <span>参加者猫 (3)</span> <img src="https://placekitten.com/320/240?image=3"> </div> <div class="participant"> <span>参加者猫 (4)</span> <img src="https://placekitten.com/320/240?image=4"> </div> <div class="list-of-participants"> <ul> <li>参加者猫 (1) (自分)</li> <li>参加者猫 (2)</li> <li>参加者猫 (3)</li> <li>参加者猫 (4)</li> </ul> </div> <div class="control"> <button>退出</button> <button>音声 OFF</button> <button>ビデオ OFF</button> <button>画面共有</button> </div> <style> .participant { position: relative; float: left; width: 320px; height: 240px; border: 1px solid black; margin: 2px; background: black; } .participant span { background: black; color: white; padding: 0 0.5rem; position: absolute; top: 0; } .list-of-participants { clear: both; } </style>
class=participant
の要素は自分以外の参加者をそれぞれ表しています。class=list-of-participants
には、参加者のリストが表示されています。class=control
には、ビデオ通話によくある機能を表すボタンを配置しています。まず、ビデオ通話をた退出するためのボタン、それから、画面共有を開始するためのボタンです。
まずは、この状態での表示を確認してみます。初回のみ、$ npm install
で必要なnpmパッケージをインストールします。その後、$ npm run dev
すると、動作確認用のWebサーバが起動して、ブラウザでhttp://localhost:8080にアクセスできるようになります。
$ npm install $ npm run dev
以後は、このページをリロードすれば最新の状態の表示を確認することができます。
さて、このApp.svelte
もれっきとしたSvelteコンポーネントなのですが、Svelte特有の知識はほとんど使わずに書けました。まだフロントエンド開発に慣れていないエンジニアや、コードも触れるデザイナも混在するチームにとって、Web開発者の事実上の共通言語であるHTML/JavaScriptだけでここまで書けることは、Svelte導入の強い後押しにあると思います。
これ以降では、この画面要素を動くようにしながら、Svelteの主な機能を体感していきたいと思います。
ステートとイベントハンドラで、自分のカメラ画像をオン/オフするボタンを作成
ここまで作成した画面は、いつどんな状況で表示(「レンダリングする」といいます)しても、同じ画面が表示されました。つまり、先程書いたHTMLがそのままブラウザに渡されて、変化することはありません。
それではつまらないので、「ビデオON/OFF」のボタンを押すことで自分のカメラ画像の表示/非表示を切り替えられるようにしたとしたらどうでしょうか? ボタンを押すたびに、表示されるべきHTMLは変化しますよね。このようなことを「状態を持つ」と呼びます。
Svelteでは、このような状態を「ステート」を使って表現します。Svelteでステートを追加することはとても簡単です。App.svelte
に次のような<script>
タグを追加します。
<script lang="ts"> let visible = true; </script>
そして、自分のカメラ画像の部分を次のように書き換えます。自分の画像を、visible
がfalse
のときはカメラがOFFにされたことを擬似的に示すため、そう見える画像を代わりに表示しています。
<div class="participant p1"> <span>参加者猫 (1) (自分)</span> {#if visible} <img src="https://placekitten.com/320/240?image=1"> {:else} <img src="https://via.placeholder.com/320x240/000000/FFFFFF/?text=Video%20OFF"> {/if} </div>
{#if}{:else}{/if}
文は、普通のJavascriptのif-else
文と同様の役割を果たします。visible
がtrue
のときは1つ目のブロックのHTMLが、false
の場合は2つ目が表示されるわけですね。注目すべきは、visible
の値が変化するたびに自動的に表示が切り替わることです。visible
という内部状態(ステート)が変化するのに対応して、リアクティブにHTMLが更新されるわけですね。
といっても、この段階ではまだvisible
は初期値のtrue
から変化することがありません。従って表示内容もずっと同じままです。
これを、ボタンを押すことで変化するようにしてみましょう。
<button on:click={() => visible = !visible}>ビデオ ON/OFF</button>
これだけです。Svelteでは、HTML要素にon:click
のかたちでイベントハンドラを設定することができます。イベントが発生するたびに=
の横に置かれた式が評価されます。ここではvisible
にそれを反転した値を代入して、このボタンをクリックするたびに表示/非表示が切り替わるようにしています。
Svelteで動的な画面を作成する感覚を掴んでいただいたところで、少しチャレンジしてみましょう。「ビデオ ON/OFF」ボタンの隣には「音声 ON/OFF」ボタンがあります。当然これも押しても何も起きないボタンですが、これを使って音声のON/OFFを切り替えられるようにしてみてください。もちろん、実際には通話機能はないので、単に名前「参加者猫④(自分)」の横に、音声がONのときは「」、OFFのときは「」のemojiを表示することにしましょう(実装例はこちらでご覧いただけます)。