Svelteのライトな紹介

なぜ私がSvelteを進めるのか?

@nobkz

自己紹介

  •  tw: @nobkz
  • グラフィカル言語を日々つくっている
    • 一か月に一つはつくる
  • Lispとかが好き
  • GUIやらSPAやら。
  • 福岡の人
  • ボードゲーム部(日曜なんかやってます)
  • techparkでいろいろ教えてる
    • モデリング
    • Lisp
  • VSCodeの実装について登壇しました。

アジェンダ

  • はじめに
  • 仮想DOMのオーバーヘッド
  • GUIの設計的なところ
  • Svelteの考え方
  • その他

はじめに

ライトに話します

  • デザイナーの方どれくらいいるかな?
  • 普段はわりとプログラマー向けの話ばかり
  • できるだけ簡単な内容にします
  • できるだけゆっくり話します

仮想DOMのオーバーヘッド

仮想DOMはなぜ早いか?

  • 枝刈り戦略
  • 仮想DOMによる、ツリー差分比較
  • 実DOMへの更新を最小限に

でもちょっとまって?

  • 仮想DOMも結局、最終的に実DOMを更新している
  • 実DOMの更新が最小限になるように、最初から実装すれば?
  • 仮想DOMの差分更新の仕組み自体にオーバーヘッドが存在する

 仮想DOMができる以前

  • いろんなフレームワークが存在した
  • それらはだいたい仮想DOMより遅い実装をしてた
  • Vanillaの人達や古くからGUIを実装してた人々は上手に設計して、高速なSPAをつくっていた

 

※Vanilla フレームをワークを使わずに、実装する人たち。大抵フレームワークの設計が適切でないので、自分たちでGUIを設計して作っていく

仮想DOMのオーバーヘッド

  • 仮想DOMにはオーバーヘッドがある
  • 差分比較をしなくても、直接最小限の更新をすればよい

GUIの設計

GUIの基本的な設計

  • モデルとビュー
  • モデル(UIの内部パラメータ)
  • ビュー(UIの表示をつかさどる)

SPAでは

  • モデル = JSのオブジェクト
  • ビュー=モデルを参照してDOMを構築する

オブザーバー

  • モデルを更新したことをビューに通知していく
  • Signalやオブザーバブル、pub subなど

オブザーバーパターン

const model = { /* 内部パラメーター */ };
const views = [];

function modelChange{
	// なにか更新処理
    notify(model);
}

function view(model){
	 /* なにか DOMを更新 */
}

views.push(view);

function notify(model){
	views.forEach(view=>views(model));

}

仮想DOMの設計

  • ビューを更新するときに、仮想DOMを構築し、差分比較している
  • 実DOMの影響を最小限に
view : (model:Model)=> VirtualDOM

Vanillaな人たち

  • モデルの変更を詳細に伝える
  • 実DOMの影響を最小限に

最小限の更新をする実装

const model = { count : 0 };
const views = [];

function countUp{
	// なにか更新処理
    model.count += 1;
    notify(model);
}

function view(model){
	 if(viewObject.text != model.countup){
     	viewObject.text = model.countup;
     }
}

// ここで通知先もしっかり考える
views.push(view);
function notify(model){
	views.forEach(view=>views(model));
}

Svelteの考え方

Svelteの簡単な設計思想の紹介

  • 記述量を短く設計
  • no 仮想DOM
  • 有効グラフによるリアクティブパターン

Svelteの高速化の考え方

  • 短い記述をコンパイルする
  • コンパイルするから仮想DOMの差分は必要ない

Svelteの更新のコード

<script>
	let count = 0;

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

<button on:click={handleClick}>
	Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

代入に注目

  • Svelteでは代入をチェックする
  • 代入文は大抵、状態更新のため
  • 一方で破壊的関数は更新しない

Svelteのコンパイル結果

function handleClick() {
    /* モデル更新 */
	$$invalidate(0, count += 1);
}
    
    
 
 /* DOMの更新 */
 if (dirty &
 t3_value  !== 
 (t3_value = (/*count*/ ctx[0] === 1 ? "time" : "times") + "")) 
 set_data(t3, t3_value);
    

Vanillaの人たち

function handleClick() {
   /* モデル更新 */
    	count += 1; notify(count);

}
    
    
 
 /* DOMの更新 */
 if (dirty & /*count*/ 1 &&
 old_value !== 
 (new_value = (count === 1 ? "time" : "times") + "")) 
 set_data(new_value);

SvelteとVanilla

  • Vanillaは基本的にボイラープレートが多くなる
  • Svelte、Vanillaのボイラープレートを抽象化した言語をつくり、適切に更新する

コンパイル時に適切なコードを追加、修正するということ

  • Virtual DOMは差分更新による、実DOMの更新の最適化。(ランタイムでやってしまう)
  • Svelte コンパイルによってDOMの更新の最適化。(コンパイル時にやってくれる)
    • ランタイムが非常に小さく、高速

Lispのマクロ

  • LispでGUIをつくったことがある
  • Lispマクロ(=コンパイル時処理)
    • コンパイル時にコードを実行し、プログラムを変更する機能
    • 似たようなもの実装しました。

その他、まとめ

似たようなもの...

  • Mage
    • Haxeで、コンパイル時にコンポーネントを出す

リアクティブプログラミングについて

  • 値の関係を記述していく
  • 値が更新されたら、関係された値も一緒に更新していく
  • 値の有向グラフ

値の有効グラフ1

x: 10

y: 10

w: x + y

z: 10

a: z * y

20

200

値の有効グラフ2

x: 20

y: 10

w: x + y

z: 10

a: z * y

20

200

値の有効グラフ3

x: 20

y: 10

w: x + y

z: 10

a: z * y

30

200

値の有効グラフ3

x: 20

y: 10

w: x + y

z: 10

a: z * y

30

300

リアクティブなコード

x = Signal(10);
y = Signal(10);
z = Singal(10);

w <= x + y;
a <= w * a;

Svelteのリアクティブ

let x = 10;
let y = 10;
let z = 10;

$: w = x + y;
$: a = w * a;

まとめ

  • Svelteはよくある、GUIのボイラープレートを省いてくれる
  • Svelteはコンパイル時に最適なコードを出力してくれるため、ランタイムが非常に小さい

Svelteを軽く紹介します

By Nobukazu Hanada

Svelteを軽く紹介します

  • 561