CodeZine(コードジン)

特集ページ一覧

作りながら学ぶ「Svelte」の構造とモダンなフロントエンド開発の考え方

高速・軽量なJavaScriptフレームワーク「Svelte」の世界 第2回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2022/02/28 11:00

 本連載では、「State of JS 2020」でも注目されているJavaScriptフレームワークのひとつ「Svelte」について、その概要や魅力、Svelteを使用したアプリケーションの開発方法について紹介します。今回は、Svelteでのコードの書き方を解説し、実際に簡単なSPAを構築する手順を説明します。

目次

はじめに

 本記事は、ユーザーインターフェイスを構築するためのJavaScriptフレームワークのひとつ「Svelte」を紹介する連載の第2回です。

 連載初回となる前回は、Svelteの生まれた背景や全体的なコンセプトを取り上げました。今回は、より具体的なSvelteでのコードの書き方を解説し、実際にSvelteで簡単な単一ページアプリケーション(以下SPAと書きます)を構築する手順を説明していきます。

 前半では、実際に手を動かしてSvelteのコードを書いてみる前に、Svelteのコードの全体的な構造を頭に入れておきましょう。前半は「初歩的なHTML/JavaScriptやjQueryでの開発の知識はあるが、モダンフロントエンドでの開発はほとんど(まったく)ない」方を想定して解説します。

 後半では、Svelteでの開発の流れや、コマンドラインでのプロジェクトの作成方法を具体的に説明していきますが、ややもすると何も考えずに書き写して終わりになってしまう場合があります。

 特に、Svelteを機会にフロントエンド開発をしっかり身につけたいと思われる方は、実行するコマンドや、書き写すコードの背後にあるモダンフロントエンド開発の考え方をぜひ頭に入れながら読み進めてください。それだけで身に付く深さがぐっと増すはずです。

 逆にReactやVueなどである程度フロントエンド開発の経験がある方は、後半までスキップしても問題ありません。

Svelteにおけるコンポーネントの概要

コンポーネントの構造

 ReactやVueなどの先行するフレームワーク・ライブラリと同様に、Svelteでは、アプリケーションを「コンポーネント(components)」という単位に分割して管理します。単純なコンポーネントの例を見てみましょう。

// Counter.svelte
<script lang="ts">
  import AnotherComponent from './Another.svelte';

  export let endOfSentence = 'してください。';
  let count = 0;

  const handleClick = () => count += 1;
</script>

<style>
  p {
    padding: 1em;
  }
</style>

<div>
  <p>クリックした回数: {count}</p>
  <button on:click={handleClick}>クリック{endOfSentence}</button>
</div>

<AnotherComponent />

 見ての通り、ほとんど通常のHTMLで慣れ親しんだ書き方しか登場しません。目新しいのは{}on:clickくらいです。

 一方で、HTMLとしては断片に過ぎないこれらのコードが、単一のファイルに格納されるのには違和感があるかもしれません。また、そのファイルの拡張子も.svelteという見慣れないものとなっています。

 Svelteでは、この.svelte拡張子を持つファイル1つが、1つのコンポーネントを表します。.svelteファイルは、SvelteコンパイラによりJavaScriptの「モジュール」にコンパイルされ、他のJavaScriptからインポートすることができます。

 UI開発では、どこかで開発したUI要素を他のページでも使い回したくなることが良くあります。例えば「表示内容をクリップボードにコピーするボタン」などは、毎回実装するのは大変ですよね。Svelteでは、こうしたUI要素を「コンポーネント」という単位に切り出しておき、必要に応じて各ページでインポートして再利用する、ということが簡単にできます。

 詳細は後述しますが、コンポーネントに切り出した部分は、コンポーネントの外側から変更できる範囲が限定されます。そのため「この変数を変更すると他の部分に影響する」とか「この行を削除するとなぜか他の部分が動かなくなる」といったような問題が起きづらくなります。また、1つのHTMLファイルやJavaScriptファイルが大きくなると、このような関係性を把握する認知的な負荷が大きくなりがちです。コードベースをコンポーネントに切り出すことで、こうした問題を予防する効果もあります。

 コンポーネントは、ほとんど通常のHTMLの感覚で書くことができますが、<script><style>タグだけは少し特殊な扱いとなります。

 <script>タグには、ほとんど通常と同じ感覚でJavaScriptを書くことができます。ここに書いたJavaScriptは、コンポーネントがインスタンス化されるときに実行されます。何点か、通常と異なる扱いになる文法があります。これらについてはこの後すぐに解説します。また、<script>タグは例外を除いて1つのコンポーネントに1つしか書くことができません。

 <style>タグには、通常のCSSを書くことができます。ただし、ここに書いたスタイルシートは原則として、そのコンポーネントにしか適用されません。そして<style>タグも、1つのコンポーネントに1つしか書くことができません。

 まとめると、Svelteコンポーネントは基本的に「動的処理(JS)」+「HTML断片」+「スタイルシート」から構成されることになります。

Svelteコンポーネントの構成
Svelteコンポーネントの構成

テンプレート構文と内部状態(ステート)

 SvelteコンポーネントがHTML文書の中に配置されると、その部分がSvelteコンポーネントの「HTML断片」と置き換えられます。

 このとき、{}で括られた部分は、その中身の評価値で置き換えられます。例に登場する{count}であれば、<script>タグ内のJavaScript(以下、単にJSと書きます)でletで宣言されているcount変数の値で置き換えられます。最初の段階では、初期値である0となります。

 JS内でcount変数が変更されると、HTML文書内の{count}も同じように更新されます。もしhandleClick関数が呼ばれればcount += 1が実行されてcountの値は1になりますね。このときに、自動的に{count}と書かれた箇所も1に更新されます。

 この例のように、コンポーネントの内部状態の変化に応じて、表示内容が自動的に更新されることを指して「リアクティブである」「リアクティビティ(reactivity)がある」などと呼びます。コンポーネントの内部状態は「ステート(states)」などと呼ぶこともあります。

 Svelteでは、letで宣言された変数がステートを表すことになります。

プロパティ

 ステートはコンポーネントの内部状態なので、コンポーネントの外側からは変更したり読み取ったりすることができません。

 もしかすると、この制限は不便に聞こえるかもしれません。確かに、素朴なHTML/JavaScriptやjQueryでの開発で頻繁にやっていたように、必要な変数にいつでもアクセスして状態を変更できたほうが便利な面もあります。

 一方で、この自由さのメリットは、アプリの規模が大きくなるにつれて徐々にデメリットに変化していきます。ある段階で、「この変数の値を変更できて便利だ」と思う場面より、「この変数に基づいて処理を進めたいが、もしかしたらどこかで変更しているのを忘れているかもしれない」と心配になる場面が多くなってきます。この段階は、1人で趣味的なプログラムを書いている場合でさえ、意外なほど早く訪れます。複数人で開発する本格的なプロジェクトであれば尚更です。

 モダンフロントエンドの開発では、この自由を制限し、その代わり「コンポーネントのコードを書くときには、そのコンポーネントの内部状態だけを把握すれば十分」となるようにしています。

 といっても、内部状態に一切アクセスできなければ、実用的なソフトウェアを開発することは難しくなります。そこで、コンポーネントの状態に外部からアクセスする窓口として「プロパティ(properties/props)」という仕組みを備えることが一般的です。

 Svelteでは、export letで宣言した変数がプロパティとなります。今回の例ではexport let endOfSentence = 'してください。';の行がこれにあたります。使い方は詳しくは後半で説明しますが、Counterコンポーネントを次のように書いて呼び出すことで、呼び出し側からendOfSentence変数の値を変更することができます。

<Counter endOfSentence='してね。' />

 こうすると、ボタンに表示される文字列は「クリックしてください。」から「クリックしてね。」に変化します。endOfSentenceプロパティを通じて、コンポーネントの内部状態をコンポーネントの外から書き換えたことになります。

 これに対して、以下のようにしてもcountの値は変化しません。countexport letではなくletで宣言された純粋な内部状態であり、プロパティとは違って外部からアクセスできないことに注目しましょう。

<Counter count={127} />

 また、このexportの使い方はJavaScript本来のexport構文とはあまり関係がないことに注意してください。Svelteはこのように、JavaScriptの文法の持つ意味(セマンティクス)を変更しています。これは、Svelteがコンパイラだからできることです。

 この書き方は、JavaScriptにとても詳しい方には初見では違和感があるかもしれません。コンポーネント開発の文脈においては十分自然に感じるように工夫して変更されているので、慣れてしまえば気になりません……が、JavaScriptにまだ慣れていない方は、Svelteの外でJavaScriptを書くときに混乱にしないように意識しておくと良いでしょう。

 さて、以上でSvelteコンポーネントの基本的な構成要素と構造を把握していただけたと思います。他にもいくつかアプリケーションを開発するために重要な要素があるのですが、ここからは実際にSvelteのコードを書きながら、どんな場面で使いたくなる機能なのか、どんな挙動の機能なのかを体感しながら身につけて頂きたいと思います。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:高速・軽量なJavaScriptフレームワーク「Svelte」の世界

著者プロフィール

  • 濱口 恭平(ハマグチ キョウヘイ)

     1990年・三重県生まれ。ドイツに拠点を置く Web3 / Privacy Tech スタートアップ でCTO/VPoEを務める傍ら、サイドプロジェクトとして「誰でも使えるビデオ通話SDK 」"kommu" を開発している。  多くの人に快適な開発者体験を提供できるフロントエンド技術を探求する中...

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5