この記事は社内勉強会用に作成したものです。
Svelte
目次
Svelte とは?
- JavaScript フレームワーク
- フレームワークだがコンパイラーであるという特異性も備えている
- 実行前にコードを最適化したJavaScriptにコンパイルする = 軽い、速い
- ReactやVueは実行時にコードを解釈する = 重い、遅い
- 開発者へのアンケート結果
特徴
- Write less code
- No virtual DOM
- Truly reactive
Write less code
少ないコード量で書ける
全てのコードにはバグが存在する可能性があります(All code is buggy)。したがって、書かなければいけないコードが多ければ多いほど、アプリケーションがバグだらけになるのは理にかなっています。
重要なのは読みやすさ(Readability is important)
巧妙なトリックを使って読みやすさを犠牲にしてでもできるだけコードをコンパクトにするべきだ、と主張しているわけではありません。
for (let i = 0; i <= 100; i += 1) {
if (i % 2 === 0) {
console.log(`${i} is even`)
}
}
↓ 読みやすさを犠牲にコード量を減らす
for (let i = 0; i <= 100; i += 1) if (i % 2 === 0) console.log(`${i} is even`)
他のフレームワークとの比較
入力された 2 つの数字の足し算
- React: 442 文字
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>
)
}
- Vue: 263 文字
<template>
<div>
<input type="number" v-model.number="a" />
<input type="number" v-model.number="b" />
<p>{{ a }} + {{ b }} = {{ a + b }}</p>
</div>
</template>
<script>
export default {
data: function () {
return {
a: 1,
b: 2,
}
},
}
</script>
- Svelte: 156 文字
<script>
let a = 1;
let b = 2;
</script>
<div>
<input type="number" bind:value={a}>
<input type="number" bind:value={b}>
<p>{a} + {b} = {a + b}</p>
</div>
No virtual DOM
仮想 DOM を使わない
'仮想 DOM は速い'という神話を完全に終わりにしよう
-
DOM
- HTML や XML 文書の構造を表現するためのインタフェース
- 開発者ツールで見られる
-
仮想 DOM
- ブラウザ上の実際の DOM と同じような構造を持つ JavaScript オブジェクトのツリー
- 仮想的な DOM の変更内容をもとに実際の DOM を変更する(最小限の更新が可能)
- React や Vue などで使用されている
Svelte の 差分更新
- コンパイル時に変更される可能性がある箇所を最適化された JavaScript コードに変換する
- 変更時には仮想 DOM を使わずに DOM の必要箇所のみを変更できる
→ 差分検出のコストが必要ない
→ 軽くて速い
Truly reactive
真のリアクティブ(特別なコードを書くことなく UI が更新される)
-
React
const [count, setCount] = useState(0); function increment() { setCount(count + 1); }
-
Vue
let count = ref(0); function increment() { count.value += 1; }
-
Svelte
let count = 0; function increment() { count += 1; }
Svelteの始め方
ローカル
npm create svelte@latest myapp
cd myapp
npm install
npm run dev
オンラインコードエディタ
記述方法
チュートリアルが充実している。
Hello world
<script>
let name = 'world';
</script>
<h1>Hello {name}!</h1>
省略記法
<img src={src} alt="A man dances.">
↓
<img {src} alt="A man dances.">
リアクティビティ
- 値を変更するだけで画面に反映される
function incrementCount() {
count += 1;
}
リアクティブ宣言
-
変数と変数を同期させる
// countが変更されるとdoubledも変更される let count = 0; $: doubled = count * 2;
-
ステートメントを同期させる
$: console.log('the count is ' + count);
-
ブロック
$: { console.log('the count is ' + count); alert('I SAID THE COUNT IS ' + count); }
-
if 文
$: if (count >= 10) { alert('count is dangerously high!'); count = 9; }
配列やオブジェクトの場合
大まかなまとめ: 更新される変数は代入の左側に直接置かなければならない。
-
自身を代入する
function addNumber() { numbers.push(numbers.length + 1); numbers = numbers; }
-
スプレッド構文を使う
function addNumber() { numbers = [...numbers, numbers.length + 1]; }
HTML内のロジック
分岐や繰り返しなどのロジックは{}
を用いる
# の文字は常に ブロックの開始 タグを示します。
/ の文字は常に ブロックの終了 タグを示します。
: の文字は {:else} のように ブロックの継続 タグを示します。
if 文
{#if x > 10}
<p>{x} is greater than 10</p>
{:else if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
each 文
第二引数として index を取得できる
<ul>
{#each cats as cat, i}
<li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}" rel="noreferrer">
{i + 1}: {cat.name}
</a></li>
{/each}
</ul>
await
非同期処理によって処理の終了を待つ
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}