🧊

Svelteランタイムのコードを読む Part.2

前回の記事でランタイムにおける`svelte`のコアは読んだので、今回は拡張となる機能たちを見ていく。

  • `svelte/store`
  • `svelte/motion`
  • `svelte/transition`
  • `svelte/easing`
  • `svelte/animate`

これらのネームスペースで`import`できるやつ。

`svelte/store`

https://github.com/sveltejs/svelte/blob/master/src/runtime/store/index.ts

  • `readable()`
  • `writable()`
  • `derived()`
  • `get()`

`writable()`

`writable()`は、`{ set, update, subscribe }`というオブジェクトを返すだけ。
値ごとに`subscribers`という配列があって、`subscribe()`されるとその配列に入っていく。

テンプレートで`$store`と書いた場合は、`component_subscribe()`という内部的な関数に変換されて、自動で`subscribe()` + `onDestroy()`で捨ててくれる。

`readable()`は`{ subscribe }`だけを返すというだけで、ほかはまったく一緒。

`get()`

export function get_store_value(store) {
  let value;
  subscribe(store, (_) => (value = _))();
  return value;
}

特別な内部処理がある?って思ってたけど、まったくそんなことなかった。

`svelte/motion`

https://github.com/sveltejs/svelte/blob/master/src/runtime/motion/index.ts

  • `tweened()`
  • `spring()`

直線的ではなく曲線的に加算できるタイプの`store`です。
なので`{ set, update, subscribe }`というオブジェクトを返すところまでは一緒。

というか、内部的には`writable()`を値の保持に使ってて、値をアップデートするタイミングにモーション味があるだけ。

そのタイミングを実装する処理が行数のほとんどだった。

`svelte/transition`

https://github.com/sveltejs/svelte/blob/master/src/runtime/transition/index.ts

`{#if}`とかでDOMに現れるとき、消えるときにつけられるエフェクト。
このコンセプトを理解しないまま困ってます!っていうIssueを結構見かける。

テンプレートでこれを使うときは、だいたい`if/else`とかがセットになるので、それ用のブロックが生成される。
その中の`p`と`o`で、`create_bidirectional_transition()`という内部的な関数で処理される。

https://github.com/sveltejs/svelte/blob/master/src/runtime/internal/transitions.ts

あとはそれを`requestAnimationFrame`で段階的に呼び出す。
CSSアニメーションで表現できるものは、そのタイミングごとにCSSのルールをアップデートして表現してる。

`fade`なら`opacity`、`slide`なら`height/pardding/margin/border`みたいな。

ちなみに`transition`は、`in`だけ、`out`だけみたいな指定もできるし、別々の演出にすることもできる。

`svelte/easing`

https://github.com/sveltejs/svelte/blob/master/src/runtime/easing/index.ts

アニメーション用のイージング関数たち。
https://github.com/mattdesl/eases をそのまま使ってる模様。

ここに関しては特に読むことがない。

`svelte/animate`

https://github.com/sveltejs/svelte/blob/master/src/runtime/animate/index.ts

だいたいの仕組みは`svelte/transition`と同じ。

現状は`flip()`だけ用意されてる。
これも使いたかったら基本的に自作することになるはず。

これもコンセプトをあまり理解されてない感があるけど、`#each`の中で順序が入れ替わるときにだけ発現するもの。

`svelte/register`

https://github.com/sveltejs/svelte/blob/master/register.js

今回コード読んでてはじめて知った。

Nodeのコードからコンポーネントを直接`require()`できるようにするためのスタブ。
その都度`complie()`して返すだけのちょっとしたコードだった。

まとめ

ランタイムといっても完全にランタイムに独立して動く処理ばかりではなく、きっちりコンパイル時に布石が打ってあった。

改めて、SvelteはReactとかと比較するもんではないな〜と思った。

単にView部分を差分レンダリングする以上のことをやっていて、そういう意味でやっぱ今からWeb開発するような人たちにこそ触ってもらいたい。

コードをだいたい読んでみたはいいけど、コントリビュートできる気は全然していないのである・・・!