結局、PreactからReactに戻した話

# はじめに
これは [KWC Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kwc) の記事です。

KWCでフロントエンドを担当している、沖縄県在住の @kwc_sunagawa です。
2019年4月に上京し新卒でKWCに入社したものの、リモートワークが標準化したこともあり、
現在は沖縄に戻ってフルリモートで働いております。
本記事では新規開発で **Preact** を採用したものの、様々な問題が発生し、結局 **React** に戻すことになった経緯についてお話しします。

# Preact とは
[Preact](https://preactjs.com/) とは、React の主要な API のみを切り出し、パッケージのサイズを抑えることにより、パフォーマンスの向上を目的としたライブラリです。

https://preactjs.com/

パッケージのサイズは **4KB[^1]** で、 React の44.5KB[^2] と比較すると、10分の1にも満たない小ささです。
また、React の主要な API を利用していることから、UIコンポーネントライブラリやテストライブラリといった、React のエコシステムを活用することができます。

React との違いはこちらに記載されています。

https://preactjs.com/guide/v10/differences-to-react/

ここまで聞くと、React を触ったことがある人であれば、特に追加の知識なしにパフォーマンスの高い SPA を開発することができる夢のようなツールに思われますが、
やはり導入するうえで苦戦する点があったため、ご紹介させていただきます。

[^1]: npm の`Minified + gzip package size`をもとに算出しています。
[^2]: npm の`Minified + gzip package size`をもとに、Reactアプリケーションの構築に最低限必要な`react` と`react-dom`を合算して算出しています。

# Preact を導入したプロジェクトの概要と選定理由
今回 Preact を導入してみたプロジェクトは、**新規お申し込みフォームの開発**を行うというもので、
ユーザーの入力内容をバックエンドの API に送るだけという比較的簡単な SPA の実装でした。
体制は、フロントエンドエンジニア2名でどちらも React の経験がありました。

そこで、軽量なフロントエンドフレームワークである、[Svelte](https://svelte.jp/), [Hyperapp](https://github.com/jorgebucaran/hyperapp), [Preact](https://preactjs.com/) について、
当時の npm trends の伸びや、学習コスト、ベンチマーク、ドキュメントの豊富さなどを元に比較し、Preact に決定しました。

https://npmtrends.com/hyperapp-vs-preact-vs-svelte

何かトラブルがあった場合に、経験のある React に移行しやすいといった点も大きなポイントでした。

# Preact を使っていて発生した問題
実際に開発をはじめてみて、PoCの時点では大きな問題なく順調に進んでいましたが、以下のような細かなバグの発生で React に戻すことになりました。

### SVG のインポートが上手くいかない
React であれば ReactComponent として SVG のファイルをインポートすることができますが、
Preactだとその機能がないため、直接`<svg>`タグを使用して書くことになります。

https://preactjs.com/guide/v10/differences-to-react/#svg-inside-jsx

```jsx: Reactの場合
import { ReactComponent as HomeIcon } from "../public/images/Circle.svg"

const Example = () => {
    return <HomeIcon />
}
```

```jsx:Preactの場合
const Example = () => {
    return (
        // Reactでは属性をキャメルケースで書くが、Preactではケバブケース(SVGの属性そのまま)になる
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
            <circle fill="#000" stroke-width="2" stroke-linejoin="round" cx="24" cy="24" r="20" />
        </svg>
    )
}
```

この仕様の違いにより、これまで使用していたアイコンのコンポーネントをそのまま使うことができず、
Webpack の loader を使用するなど、工夫をする必要がありました。
しかし、今回のプロジェクトでは Storybook や Jest も利用していたため、
それらのビルド設定と互換性が上手く取れず、アプリケーションではアイコンがうまく表示されるものの、
Storybook では表示されなかったり、ユニットテストが通らなくなるといった問題が発生しました。
その時の対応については、別の記事で紹介したいと思います。

### エコシステムの選定を誤った

Preact で React のエコシステムを利用するには、`preact-compat`というライブラリを使用する必要があります。
しかし、`preact-compat`を使用して互換性をとっても、完全に React と同じ動作を保証しているわけではないため、
デバッグが難しくなってしまうのではないかと考えました。
そこで、ルーティングライブラリに普段使用している`react-router`ではなく、Preact が出している`preact-router`というものを使用しました。

https://github.com/preactjs/preact-router

これは完全に調査不足でしたが、`preact-router`は基本的なルーティングの機能のみを備えており、画面遷移時のスクロールの制御やミドルウェアの使用など、少し複雑な実装を行うのには向いていませんでした。

> 💁 Note: This is not a preact-compatible version of React Router. preact-router is a simple URL wiring and does no orchestration for you.
>
>If you're looking for more complex solutions like nested routes and view composition, react-router works great with preact as long as you alias in preact/compat.

### スキル不足
他にも Preact を使用するうえで、躓くポイントは多々あったのですが、エコシステム同士の互換性の問題が主でした。
Preact を使用するうえでは、エコシステムの選定をより慎重に行う必要があると考えます。
また、どの問題も発生した際に自分で解決できるだけのフロントエンドのスキルがあれば、もっとうまく使いこなせたのだろうと思います。
これから精進して参ります。m(_ _)m

# Preact から React へ移行する
先にあげた問題のように、Preact 関連の調査にかかる時間が負担となってしまっていたため、Reactへの移行を決めました。

### 移行にかかった期間

開発していたフォームの画面数は12画面あったのですが、基本的に React と同じ書き方であることから、**2週間ほど**で移行を完了させることができました。

移行にあたっては、ビルドツールに **Vite** を採用し、ルーティングライブラリは **React Router** に変更しました。

### React に移行するにあたって苦戦したところ

今回 Preact から React に移行するにあたって、React のバージョンは **v17** を採用しました。
2022年12月現在、Preact は React **v15, v16** を反映させているため、
移行したタイミングで`useEffect`に破壊的変更が加わってしまい、バグが発生してしまいました。
一箇所ずつ処理を修正する必要があったため、こちらの改修に時間が取られました。

React の破壊的変更については、バージョンごとにたくさん記事が出ているので、そちらをご参照ください。

# もしこれから Preact を利用するなら

今回はスキル不足によって、Preact の良さを最大限活かすことができませんでしたが、
この挑戦を通して、React への知識を深めることができたと考えています。

Preact はなるべく React との互換性を取るように開発されているため、
うまく使いこなせれば、低い導入コストでパフォーマンスの高いアプリケーションを作ることが可能です。
そのためには、バージョンやエコシステム同士の互換性を意識しながら開発を行うことが大切だと思いました。


# おわりに
この記事が少しでも誰かのお役に立てると幸いです。
間違いを見つけた場合や、もっとこうするとわかりやすいなどのご意見があれば、
ぜひコメントしていただけると嬉しいです。

[KWC Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kwc) はまだまだ続きます！明日の投稿もお楽しみに！