前回の記事でランタイムにおける`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`
今回コード読んでてはじめて知った。
Nodeのコードからコンポーネントを直接`require()`できるようにするためのスタブ。
その都度`complie()`して返すだけのちょっとしたコードだった。