カテゴリー: FrontEnd

Svelteのチュートリアルをやってみた

はじめに

フロントエンドの開発をする際のフレームワークは、Vue.jsを使うことがほとんどだったのですが、先日、知人よりSvelteなるものがあると教えてもらったので、チュートリアルをやってみました。

Svelteのv1.0.0は2016年12月30日にリリースされており、現在では、v3.31.0までリリースされています。

Svelteとは?

はじめに、Svelteについて、さっと紹介します。

Svelte is a tool for building fast web applications.と公式にあるように、高速なWebアプリケーションを構築するためのフレームワークです。乱暴な言い方をすると、ReactやVue.jsなどと似た方なものです。ただし、これらとはアプローチが異なるので、その辺りを次で説明します。

Svelteの特徴

公式曰く、Svelteの特徴は以下の3つです。

  • Write less code
  • No Virtual DOM
  • Truly reactive

Write less code

Svelteは、書かなければならないコード量を減らすことを目標としています。公式曰く、あるSvelteのコンポーネントと同等のReactのコンポーネントのコード量は、Svelteのコード量と比べて、だいたい4割ほど多いそうです。

実際に公式サイトに掲載されていたサンプルを見比べてみましょう。初めに、Svelteで書かれたコードです。

<script>
  let a = 1;
  let b = 2;
</script>

<input type="number" bind:value={a}>
<input type="number" bind:value={b}>

<p>{a} + {b} = {a + b}</p>

2つの入力欄とその合計を表示するだけのシンプルな画面です。

次にReactで書かれたコードです。

import React, { useState } from 'react';

export default () => {
  const [a, setA] = useState(1);
  const [b, setB] = useState(2);

  function handleChangeA(event) {
    setA(+event.target.value);
  }

  function handleChangeB(event) {
    setB(+event.target.value);
  }

  return (
    <div>
      <input type="number" value={a} onChange={handleChangeA}/>
      <input type="number" value={b} onChange={handleChangeB}/>

      <p>{a} + {b} = {a + b}</p>
    </div>
  );
};

見比べてみると、Svelteのコードの方がコード量が少ないことが見て取れます。

No Virtual DOM

ReactやVue.jsなどとは異なり、SvelteはVirtual DOMを使わない代わりに、ビルド時にフレームワークのないJavaScriptのコードに変換されます。これにより、DOMを更新するためにVirtual DOMの差分をチェックする必要がないため、高速に動作することができます。

Truly reactive

No Virtual DOMの説明と重複するのですが、Virtual DOMを使わず、ビルド時にDOMを直接変更するコードに変換されるため、高速に動作することができます。

また、Svelteでは状態を変化させるために状態管理ライブラリを使用する必要はありません。変数の値を変更するだけで画面に反映されます。

Svelteのシンタックス

Svelteのコードは.svelteファイルに記述します。記述の仕方はVue.jsに似ており、<script>タグの中に変数や関数などを定義し、<style>タグの中にCSSを記述します。なお、CSSはコンポーネントにスコープされているので、他のコンポーネントには影響しません。

<script>
  let name;
</script>

<h1>Hello1 {name}!</h1>

<style>
  h1 {
    color: #ff3e00;
    text-transform: uppercase;
    font-size: 4em;
    font-weight: 100;
  }
</style>

基本的なシンタックスをいくつか紹介します。

変数

変数は<script>タグの中にそのまま定義するだけです。

<script>
  let name;
</script>

画面に表示するには、{}で囲うだけです。

<h1>{name}</h1>

props

propsは変数定義と似ていますが、exportをつけて宣言します。

<script>
  export let firstname;
  export let lastname = 'Yamada';
</script>

値渡しはこのようにします。

<script>
  import MyComponent from './MyComponent.svelte';
</script>

<MyComponent firstname={'Taro'}/>

また、オブジェクトを展開して渡すこともできます。

<script>
  const name = {
    firstname: 'Taro',
    lastname: 'Yamada',
  };
  import MyComponent from './MyComponent.svelte';
</script>

<MyComponent {...name}/>

event

例えば、ボタンクリック時にカウントアップさせるには、このように記述します。

<script>
  let count = 0;

  function handleClick() {
    count += 1;
  }
</script>

<button on:click={handleClick}>
  Count up
</button>

<p>
  {count}
</p>

また、|で繋ぐことで、イベントの振る舞いを修飾することができます。

<button on:click|once|capture={handleClick}> Count up </button>

bindings

svelteのデータフローはトップダウン型のため、親のコンポーネントは子のコンポーネントにpropsを渡すことができますが、その逆はできません。しかし、bind:valueを使うことで、これを実現することができます。

<script>
  let name = 'taro';
</script>

<input bind:value={name}/>

<h1>{name}</h1>

if

条件に応じて表示を切り替えたい場合は{#if}を使用します。

<script>
  let number = 1;
</script>

{#if number % 2 == 0}
<p>
  even
</p>
{:else if number % 2 != 0}
<p>
  odd
</p>
{:else}
<p>
  error
</p>
{/if}

each

繰り返しで処理したい場合は{#each}を使用します。

<script>
  let persons = [
    { id: 1, name: 'Taro',}
    { id: 2, name: 'Hanako',},
    { id: 3, name: 'Ichiro',}
  ];
</script>

<ul>
  {#each persons as person}
    <li>{name}</li>
  {/each}
</ul>

また、(person.id)のように識別する値を指定することもできます。

<ul>
  {#each persons as person (person.id)}
    <li>{name}</li>
  {/each}
</ul>

await

非同期で処理した値を表示したい場合は{#await}を使います。

<script>
  async function someAsyncFunc() {
    // 何らかの処理
    return 1;
  }

  let promise = someAsyncFunc();
</script>

{#await promise}
  <p>...waiting</p>
{:then val}
  <p>{val}</p>
{:catch error}
  <p>{error.message}</p>
{/await}

lifecycle

コンポーネントのlifecycleにはonMountonDestroybeforeUpdateafterUpdateTickがあります。

onMountはコンポーネントがレンダリングされた直後に実行されます。

<script>
  import { onMount } from 'svelte';

  onMount(async () => {
    await someAsyncFunc();
  });
</script>

onDestroyはコンポーネントが破棄される時に実行されます。

<script>
  import { onDestroy } from 'svelte';

  onDestroy(() => someFunc());
</script>

onDestroyに限らず、lifecycle関数はコンポーネントの初期化時に呼び出す必要がありますが、ReactやVue.jsなどとは異なり、どこでも呼び出すことができます。以下のように関数内に書けるため、clearInterval()に渡すidを保持しておく必要がありません。

<script>
  import { onDestroy } from 'svelte';

  function someFunc(callback, ms) {
    const interval = setInterval(callback, ms);

    onDestroy(() => {
      clearInterval(interval);
    });
  } 
</script>

beforeUpdateはDOMが更新される直前に実行されます。また、afterUpdateはDOMが更新された直後に実行されます。

<script>
  import { beforeUpdate, afterUpdate } from 'svelte';

  beforeUpdate(() => someBeforeFunc());

  afterUpdate(() => someAfterFunc());
</script>

Tickはほかのlifecycleとは異なり、いつでも呼び出すことができます。Svelteでは、コンポーネントを更新してもすぐにDOMには反映されず、次のマイクロタスクが実行されるタイミングでまとめて更新されます。

await tick()とすることで、次のマイクロタスクが実行されるタイミングで任意の処理を実行することができます。

<script>
  async function someAsyncFunc() {
    await tick();
    // 任意の処理
  }
</script>

環境構築

Svelteの環境構築は非常に簡単です。任意のバージョンのNode.jsをインストールした後にnpx degit sveltejs/template project-nameを実行し、npm installを実行するだけです。

サーバーを起動するにはnpm run devを実行します。その後、http://localhost:5000/にアクセスすると、表示の確認ができます。

本番環境などで使用する場合は、npm run buildでビルドし、npm run startでサーバを立ち上げます。

TypeScriptで書く場合

TypeScriptで書きたい場合は、node scripts/setupTypeScript.jsを実行します。

さいごに

Svelteについて、ざっと紹介しました。チュートリアルでは実際にブラウザで実際にコードを書きながら学習できるので、始めやすいと思います。

おすすめ書籍

 

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: JavaScript

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前