traP Member's Blog

シンプルなJavaScriptフレームワーク「Svelte」を試してみる

ponya
このエントリーをはてなブックマークに追加

こんにちは。traP Advent Calendar 2016 12日目担当のponyaです。

今回は11月に出たばかりのJavaScriptフレームワークSvelteを触ってみたいと思います。

 

はじめに

知っている方は知っての通り、今JavaScript界隈では新しいツールやフレームワークが次々と出ては消えるというような感じで、これを学べば何年後でも古い言われないものが存在しないと言っても過言ではありません。(今のJavaScript界隈の状況がよくわかる記事→『2016年にJavaScriptを学ぶとこんな感じ』)

 

JavaScriptのフレームワークをよく知っている人であれば「また新しいフレームワークか・・・お前もどうせ消えるんだろ?」といった感じかもしれません。ただ、このSvelteは他のJavaScriptフレームワークとは少し毛色が違うところもあるのでそこも含めて触っていこうと思います。

 

Svelteのコンセプト

上で見たように、現在でも山ほどJavaScriptのフレームワークがあるんだからわざわざ新しいものを作っても、その二番煎じにしかならないような気がします。では、なぜこのSvelteは開発されたのでしょうか。作者は次のように書いています。(https://svelte.technology/blog/frameworks-without-the-framework/)

The common view is that frameworks make it easier to manage the complexity of your code: the framework abstracts away all the fussy implementation details with techniques like virtual DOM diffing. But that’s not really true. At best, frameworks move the complexity around, away from code that you had to write and into code you didn’t.

要するに(日本語訳丸投げ)フレームワークは本来難しい実装を簡単に使えるようにあるはずなのに、必要なコードを書く以外のところが複雑になってしまっているということです。

 

例えばReact+ES6でWebアプリを開発したい!と言っても、npm installしてコードを書き始めることができれば問題ないのですが、書いたコードがそのままブラウザでは動かないのでブラウザで動くようにビルドツールの設定をしなければなりません。この設定が色々と大変で、コードを書く以外のところで時間が余計に取られてしまいます。また、複雑な実装をフレームワークが肩代わりしている分、自分の書いたコードを実行するために必要な他のコードが肥大化し、書いたコードの処理に時間がかかります。Webアプリでは特にこの問題が大きく、Webページのパフォーマンス低下にもつながります。

 

対してSvelteでは単純にHTMLの部品化を実現するだけです。なので、JavaScriptとHTMLを学んだことがある人ならばすぐに習得することができ、既存のWebアプリからの移行も簡単です。また、実行時にコードの解釈を行うのではなく、予めブラウザで直接実行できるコードを簡単に作れるのでブラウザで外部JSの読み込みがなく、変換後のJavaScriptのファイルは書いたコード以外の部分が最小限にとどまっています。

 

このように、Svelteはとてもシンプルな作りになっています。前置きが長くなりましたが、早速使ってみましょう。

 

試してみる

nodejsのインストールができている前提でチュートリアルに必要なものをインストールします。

npm install -g svelte-cli

最初に構成要素となるHTMLの部品を用意します。

<!--App.html-->


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


これをjsファイルに変換しましょう。

svelte compile --format iife App.html > App.js

次にWebアプリ本体に作った部品を読み込むためのコードを書きます。

<!--index.html-->
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Hello App</title>
</head>
<body>
  <main></main>
  <script src="App.js"></script>
  <script>
    var app = new App({
        target: document.querySelector('main')
      });
  </script>
</body>
</html>

これでブラウザで開けばdataのnameに入っている変数で表示が変わるようにできるはずです。

Todoアプリを作る

Svelteを使ってTodoアプリを作ってみます。
まずは先ほどと同じようにブラウザで表示するメインのHTMLを作成します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="urf-8">
  <title>Todo App</title>
</head>
<body>
  <main></main>
  <script src="TodoApp.js"></script>
  <script>
    var app = new TodoApp({
        target: document.querySelector('main')
      });
  </script>
</body>
</html>

次にアプリの主要コンポーネントであるTodoApp.htmlを作成します。
最初は入力ボックスとボタンを設置して、入力された文字列を随時追加表示できるようにします。

<div>
  <div>
    <input bind:value="newTodo" />
    <button on:click="addTodo()">Add</button>
  </div>
  <div class="list">
    <ul>
    {{#each todoList as todo}}
      <li>{{todo.text}}</li>
    {{/each}}
    </ul>
  </div>
</div>

<style>
  button {
    margin-left: 10px;
  }

  .list ul {
    list-style: none;
  }
  .list li {
    margin-top: 10px;
  } 
  .list li button {
    margin-right: 10px;
  }
</style>

<script>
  export default {
    methods: {
      addTodo() {
        this.set({
            todoList: [
              ...this.get('todoList'), 
              {
                id: this.get('todoList').length + 1,
                text: this.get('newTodo'),
                checked: false
              }
            ],
            newTodo: ''
          });
      }
    },

    data() {
      return {
        todoList: [],
        newTodo: ''
      }
    }
  };
</script>

 

このコンポーネントにはdataとして配列であるtodoListと文字列であるnewTodoがあります。それぞれ、今Todoリストに追加されているデータ、テキストボックスに入力された値を保持します。
bind:valueでテキストボックスに入力された値をnewTodoに紐付けします。

<input bind:value="newTodo" />

 

下のコードでli要素を繰り返して、todoListをすべて表示させます。Svelteにはeachの他にifをつかってHTMLの要素を描画するかしないかを条件分岐させることもできます。

{{#each todoList as todo}}
<li>{{todo.text}}</li>
{{/each}}

 

on:clickでボタンをクリックするとaddTodo()を呼び出すようにします。

<button on:click="addTodo()">Add</button>

 

addTodo()の定義はexport default内のmethodsに書きます。他の関数をHTML内で利用するときもここに追記します。
addTodo()ではset()を用いてコンポーネントのtodoList配列にテキストボックスに入力される文字列を追加した新しいtodoListをコンポーネントに設定します。コンポーネントに保持されているdataはget()を用いて取得します。
また、set()で値を設定するとその値と関連する部分のHTMLが再描画されます。なので、いちいちHTMLの要素を追加する処理を書かなくてもtodoListにset()を用いて新しい値を設定すれば勝手に処理をやってくれます。

methods: {
      addTodo() {
        this.set({
            todoList: [
              ...this.get('todoList'), 
              {
                id: this.get('todoList').length + 1,
                text: this.get('newTodo'),
                checked: false
              }
            ],
            newTodo: ''
          });
      }
    }

 

先程と同じようにjsに変換してメインのHTMLを表示させれば、テキストボックスに値を入力してAddを押すと順次Todoが追加されるようになります。

次は完了したタスクを削除するボタンを追加します。
先程のコードを下のように書き換えます。

<!--
<ul>
    {{#each todoList as todo}}
      <li>{{todo.text}}</li>
    {{/each}}
</ul>
-->
<ul>
    {{#each todoList as todo}}
      <li><button on:click="removeTodo(todo.id)">Done</button>{{todo.text}}</li>
    {{/each}}
</ul>

methodsにタスクを削除するremoveTodo()を追加します。

methods: {
      addTodo() {
        const preTodoList = this.get('todoList')
        this.set({
            todoList: [
              ...preTodoList, 
              {
                id: preTodoList[preTodoList.length-1].id + 1,
                text: this.get('newTodo'),
                checked: false
              }
            ],
            newTodo: ''
          });
      },

      removeTodo(id) {
        const newList = []
        this.get('todoList').forEach(todo => {
          if(todo.id !== id) newList.push(todo);
        });
        this.set({todoList: newList});
      }
    }

これでSvelteで簡単なTodoアプリを作ることができました。

最後に

Svelteはまだリリースされたばかりのフレームワークで、まだ実装が物足りない部分があります。(ビルド失敗時のエラー表示など)詳しい使い方は公式サイトの説明がわかりやすい上、公式サイト上でコードを書いて試すこともできるので気軽に試してみてください。
https://svelte.technology/

このエントリーをはてなブックマークに追加

記事へのコメント

yamachan360
2017年2月25日 22:18

このサンプル、一番下のTodo以外を「Done」するとIDが被りませんか?

コメントを残す

メールアドレスが公開されることはありません。