ふとしたキッカケで Svelte を使ってみた

### 2021/07/08 追記

本記事では日本語での情報についていくつかのデメリットを提示しています。

しかしながら、最近ではかなり状況が改善されており、2020年11月に Discord において日本語の Svelte ユーザーコミュニティである「Svelte日本」が公開されました。

[「Svelte日本」のご紹介](https://qiita.com/am_nimitz3/items/762d774e434c568fe000)

また2021年2月には、その「Svelte日本」において Svelte 公式サイトのドキュメントの日本語化プロジェクトが立ち上がり、翻訳作業が完了し、日本語のドキュメントも整備されました。

[Svelte の日本語サイトが公開されました！](https://qiita.com/myLifeAsaDog/items/0b1432b0200fdec202b9)

従って、Svelteを日本語の情報だけで試せる環境が整備されつつあるため、デメリットの多くは無くなっており、むしろ新たに試してみるにはいい環境になってきています。


ーー 追記ここまで

最近、ふとしたキッカケで JSフレームワークである [Svelte](https://svelte.dev/) を使ってみたので簡単に感想をメモっておく。

### 結論

結論だけいうと、コンパイラなので依存が実質的に何もないし、実際に軽くて早くてコード量が少ないのは事実なので、使い慣れてきたらかなり良さそう。

ただし複数人でコードをいじる場合には、フレームワーク自体のルールがほとんどないので、チーム内での統一ルールなどが無いと扱いにくいかも、特に store 周り

### Svelteの特徴

- JSコンパイラで Vanilla JS としてコンパイル結果を出力する
- 海外ではそれなりに知名度がある
- Vuejs に影響を受けているので書き方や概念が近い
- 軽量かつ高速
- ボイラーブレートコードを忌み嫌っている
- コード量を出来るだけ少なく済むようにしている
- SSRが可能だが試してはいない
- Legacyモードでコンパイルすることにより IE9 対応可能
- store の state を直接バインディングできる
- テンプレート側で Promise の状態を見て分岐ができる

```html:こんな感じ
{#await promise}
  <p>pendingだよ</p>
{:then hoge}
  <p>resolveした</p>
{:catch}
  <p>rejectした</p>
{/await}
```
### 私見
 
- [Riot](https://riot.js.org/ja/) をブラッシュアップした感じ
- 個人的には Riot v4 よりは Svelte の方がコードが少ない上に出来ることが多い印象
- コンポーネントは Vuejs の SFC と感覚としては同様
- 軽量かつ高速なのは体感できるレベルでわかる
- store はかなり使い勝手が違う
- state と props に相当するものがあるが、React や Vuejs とは違うのであんまり気にしない方がいい
- React や Vuejs ですら「重い」という環境で採用されている模様
- router は [svelte-spa-router](https://github.com/ItalyPaleAle/svelte-spa-router) という超軽量ですぐ使える router がある
- 特徴のひとつであるテンプレート側で Promise が受けられる機能だが、Storeが絡むと使うのが結構難しい上に災いを起こしがち

### メリット

- 依存が無いので環境の立ち上げが楽
- コード量は少ない
- store がビルトインされている
- 学習コストは低い
- コンパイラなのである程度のエラーは事前に検知できる
- 本体リポジトリは議論や更新が活発

### デメリット

- 日本語のドキュメントがない
- 日本のユーザーグループなどもない
- したがって講習会や勉強会などもない
- というか日本語の情報は基本的に無い
- 無いので自分でドキュメント翻訳した -> [Svelteのドキュメントを翻訳してみた](https://qiita.com/myLifeAsaDog/items/5d3036201f37a98e685d)
- React や Vuejs のような便利な devtool がない 

### 微妙にわかりにくい点

- イベントハンドラの書き方

```javascript:eventHandler

const onClick = (params) => { hogehoge }

/* ダメな書き方 */
<p on:click={onClick(fugafuga)}>これはクリックできる</p>

/* 正解はこっち */
<p on:click={() => onClick(fugafuga) }>これはクリックできる</p>
```

- イベントディスパッチャーの引数の取り方

```javascript:eventDispatcher

/* コンポーネント */
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();

/* { code:hoge }を引数に持ったselectイベントを発火させる */
<p on:click={() => dispatch('select', {code: hoge} )}>selectイベント</p>

/* コンポーネントの参照元 */
<fugaComponent on:select={(event) => event.detail.code} />

```

- DOMオブジェクトを直接参照したい場合

```javascript:DOMbinding

<script>
let elementTop;

/* こんな感じでDOMを参照する */
elementTop.getBoundingClientRect();
</script>

<p bind:this={elementTop}>この要素の上位置を知りたい</p>
```

### よくわかっていない点

- store の set/update で state がまるごと更新される（詳細は下記）
- vuex の getter にあたる deriverd というものがある
- store の deriverd 内では非同期処理は扱えない（多分）
- store で readable が選べるが、どういうときに使うのか謎

```javascript:store.js

/* store はこんな感じ */
export const hogeStore = writable(0);

参照するときは $hogeStore 

/* カスタムするとこんな感じ */
const router = () => {
  const { subscribe, set } = writable('index')
  return {
    subscribe,
    index: () => set('index'),
    detail: () => set('detail'),
  }
}

 $router で index が返ってくる、router.detail() で更新、async でも書ける

/* 複数の値を持ちたい場合 */
export const hogeStore = writable({ hoge: '',  fuga: '' });

$hogeStore.hoge で参照
$hogeStore.hoge = 'hogehoge' で普通に更新される

hogeStore.set とかすると $hogeStore が丸ごと更新される
hogeStore.hoge.set() とかそういうことはできないっぽい
```