Svelte 製ウェブアプリに IPFS 本機能を実装しました

---

**warning** この記事は js-ipfs の説明が不十分です。詳細は以下記事が参考になります。

https://blog.ipfs.io/2021-06-10-guide-to-ipfs-connectivity-in-browsers/#%F0%9F%8C%9F-webrtc-star


---

今年の９月に、目線移動無くサクサク読めるオープンソースツール「[Svelte Shield](https://ampcpmgp.github.io/svelte-shield/)（前身: Riot Shield）」を公開しました。

以下のように、テキストを入力して再生ボタンを押すと、枠内に分割された文字が流れます。


![20201114122417.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85111/f03fca58-3501-b563-6997-ccab1ff8192b.gif)


このアプリの一機能として、分散型ファイルシステムの IPFS と連携し、他者と共有可能な本機能、「IPFS本」モードを追加しました。

今までは読み上げるテキストを毎回張り付ける必要がありましたが、この対応により URL を共有すると他の人も同じ文章が読めるようになります。

---

 Wikipedia の「睡眠」記事をライセンスに従って転載したページが以下です。

https://ampcpmgp.github.io/svelte-shield/#/books/QmULjPTtPNk1hoQFnV27eh3Nz2B7dr1BBNxY49LBEHdpcU

![20201217214744.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85111/2e40e590-d624-def9-c2fa-85f1e385e877.gif)


※ページを開いても、データを持っている Peer を見つけるのに時間がかかったり、見つからないこともあり得ます。ご了承ください。🙇‍♀🙇



本の登録から共有までの、具体的なデータはざっくり以下になります。

```
* アプリの初期化時に IPFS node を立ち上げる
* アプリ画面から入力した本のデータを、上記 IPFS node に追加する
* ページを開いている間は、本データが共有可能になる
* 返ってきた hash を URL の一部に入れ、本詳細ページを開く
* 上記 URL を他者に共有する
* 画面を開くと、 IPFS ネットワーク上で該当の hash を持っている Peer を探索する
* Peer が見つかればダウンロードを開始し、本を表示する
```

より詳細なドキュメントは [IPFS](https://ipfs.io/) や [JS IPFS](https://js.ipfs.io/) から読めます。

---

また、ハッシュタグ [#IPFS本](https://twitter.com/search?q=%EF%BC%83ipfs%E6%9C%AC&src=saved_search_click&f=live) からは、「ツイートする」ボタンから共有された本の一覧を見ることが出来ます。

前置きはこれくらいにして、 Svelte の話に移ります。



## Svelte で最も工夫した点

今回はコンポーネントのフォルダ構造に工夫を入れてみました。もともと `src/components/` 配下に、以下の構成で作っていて

* `containers/` - レイアウト・状態管理のみを行う Component 群
* `parts/` - 見た目だけを担う Component 群
* `routes/` - ページごとのエントリポイント
* `App.svelte` - Svelte のエントリポイント

https://github.com/ampcpmgp/svelte-shield/tree/master/src/components



今回からページも増えたことで、 `containers/` に入れるコンポーネントの種類を、以下の構成で作りなおしました

* `!Common/` -> ページ間をまたいで共通で使う Component 群
* `Home/` -> メインページだけで使う Component 群
* `Books/` -> 本一覧ページだけで使う Component 群
* `Book/` -> 本詳細ページだけで使う Component 群

https://github.com/ampcpmgp/svelte-shield/tree/master/src/components/containers



`containers/` 配下は、役割・グループ名ごとにフォルダを作っていたのですが、「この Component はどう考えても、このページでしか使わないな」みたいなことが増えてきて、ページをまたいで使えるもの、そのページだけで使うもの、を分け隔てたくなり、共通フォルダと、各ページフォルダを用意しました。共通フォルダに `!` を入れてる理由としては、ファイル並び替えの際に先頭に来る文字であることと、共通フォルダを強調したい二つの意味を込めました。

また、 router 等といった Component 上位層ではなるべく複雑なコードにせず、平坦に並べるように意識して、 utils 関数フォルダ内や、下位コンポーネントで必要な処理を行うよう努めました。本一覧ページの Route ファイルなんかは平坦化が出来ていて、予備知識が無くとも直感的に読みやすくなっていると思います。

https://github.com/ampcpmgp/svelte-shield/tree/master/src/components/routes/Books.svelte 



## Svelte で最も苦戦した点

今回は環境設定周り、特に Svelte ファイルの自動フォーマットに最もハマりました。この開発をする前は、 lint-staged で commit 時に lint & format をかけていたのですが、それだと体感明らかにコミットが遅く感じていて、良い方法が無いかなと思ってました。 VSCode 拡張機能の [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) でやりたいことが出来そうと思い、公式ドキュメントに従って自動フォーマットの設定をしてみたんですが、どうにもうまく行かず。

色々調べてみたところ、 VSCode の User Settings の中で、以下の設定が必要でした。

```json
{
    "eslint.validate": [
        "javascript",
        "svelte"
    ],
}
```



色々と issue を探って、間違った設定を繰り返していたため、これに辿り着くのに時間がかかってしまいました。競合する Svelte 拡張機能も入れていたのも、解決に時間がかかる要因になってたかもしれません。



## 改めて Svelte を使ってみて

とにかく心地良く書けます。今回は比較的大きめなエンハンスだったので、全体の構造も見直しながらリファクタをしていましたが、 Svelte のコードは見通しがとても良く、常に新鮮な空気を吸っているようでした。

加えて、 Svelte を過小評価していたと感じました。というのも、 Svelte & JavaScript では React & TypeScript にメンテナンス性でだいぶ劣ると考えていて、仕事でもそのように提案したことが何度もありました。

Svelte に大量の関連ライブラリはありませんが、 router など最小限のものは揃っています。そして `bind:this` や `svelte:window` といった、ブラウザ API を触りやすくしているという点です。大量のライブラリを利用していると、大抵何らかの問題があり issue を探したり  Stack Overflow で質問を探したりということがありますが、ライブラリ利用は最小限にして、特殊なことをやりたいときはブラウザ API を利用することで、ブラウザの仕様と向き合えるため、 wrap したライブラリを利用することに比べて、ブラウザへの理解も深まり根本的な解決策に向けて動きやすくなったと思います。

また、型情報が無くとも、ある程度は相殺できるメリットを感じました。
型を使うと安全性は間違いなく上がります。 現に Svelte & JavaScript での開発中、型を誤って指定し、実行時まで気づかないということは何度かありました。実行前に分かったほうが嬉しいので明確にデメリットです。ただ、型を作る以前に、コードを簡潔に分かりやすく書くことの重要性を感じていて、 Svelte はそれを達成させやすくしていると感じました。エディタ上やバンドルツールでの型チェックも簡素化されるため、保存から反映までの時間が体感早くなったことも大きいです。

流行るかどうかでは無く、良いものかどうかで見ると、新規案件で採用を検討する価値が十分にある、一つの選択肢であると改めて思いました。



## 開発全体を振り返って

ここでは深くは触れませんが、要件定義にだいぶ苦戦しました。 IPFS のような今まで使ったことがなく、実装への影響度が大きいものに関しては、要件検討と技術調査を何度も行き来し、当初の要件を根本から変えたこともありました。

実装中にも細かい変更や、想定していなかった分岐が見えてくることもあり、練り直す作業は大変でしたが、 Svelte はそれに追随しやすいと感じました。要件変更に強い印象が今も残っています。

今後は大規模開発にも挑戦していきたいと考えています。


## 終わりに

この IPFS 本は学問や教養の公共財化を目標に、色々な用途に対応していけたらと思ってます。次は IPNS と連携した更新可能な本棚機能も検討したいと考えています。

質問や機能要望などありましたら、ここのコメントや Github Issue などから、是非連絡ください🙇‍♀🙇

* Repository - https://github.com/ampcpmgp/svelte-shield
* Twitter - https://twitter.com/am_nimitz3



最後まで読んでいただき有難うございました。