🧹
ReactのSPAで外部ライブラリを整理するためにやったこと
はじめに
同プロジェクトでは設計段階からのリファクタリングを並行して進めており、この記事では外部ライブラリを整理した話についてご紹介します。
リファクタリングの全体像はこちらをご覧ください。
課題
まずはリファクタリング前の課題です。
使用している外部ライブラリは開発が開始された2020年12月頃にインストールされたバージョンのままで、Reactもv16.13.1でありhookは入っているもののメジャーバージョンが2つ遅れている状況でした。
その結果
- 外部ライブラリの新機能が使えない
- 新しいライブラリが使えない
- ライブラリのバグがそのままになっている
- 情報が古いため技術的な調査に時間がかかる
- 脆弱性が発覚した際の対応に時間がかかる
などの課題があり、開発速度の低下につながっていました。
またGreenfile.workの各アプリケーションでは共通の内製Componentライブラリを使用しており、その内製ライブラリもバージョンがメンテされていなかったため、各アプリケーションの外部ライブラリのバージョンが上げづらくなっていました。
どのように外部ライブラリを整理していったか
大きく以下の4ステップで進めました。
- React16からReact18へのアップデート
- webpack4からviteへの移行
- ReduxをswrとuseContextに移行
- その他のライブラリのバージョンアップ
React16からReact18へのアップデート
まずはReactのバージョンアップです。
Reactのバージョンが古いと既存ライブラリのバージョンアップや新しいライブラリの導入など、全てに制約がかかるため最初に対応しました。
対応方針
具体的な対応方針としては
- 今回はGreenfile.workの他のアプリケーションのバージョンアップはやらない
- 定期メンテナンスの指針や方法などは決めない
- 関連ライブラリはReactのバージョンを上げるために必要な最小限の範囲でのみバージョンを上げる
と決め「Greenfile.work入退場のReactのバージョンを最新にする」をゴールとして、最小限のスコープで進めることにしました。
これはReactのバージョンがGreenfile.workの他のリファクタリングのボトルネックになっていたため、最速で対応するためです。
具体的な対応作業
内製ライブラリとGreenfile.work入退場のそれぞれで破壊的変更の対応を行いました。
内製ライブラリはreact18対応済と未対応でブランチを分け、他のGreenfile.workのアプリケーションに影響がでないように運用することにしました。
- React17の破壊的変更の対応
- イベント委譲の変更
- [開く]ボタンをクリック
- root elementに登録されたhandleOpenが発火してになり、にが登録される
- root elementはdocumentの内部にあるためバブリングしdocumentに登録されたhandleOutSideClickが発火して、になる
v17の破壊的変更の中で対応が必要だったのはイベント以上の変更のみでした。
React公式の図がわかりやすいですが、v16まではに登録されていたイベントハンドラがroot elementに登録されるようになりました。
この変更によってモーダルのような外側をクリックしたら閉じるComponentの挙動が変わったため対応しました。
具体的には
のようにが外部かどうかを判定して閉じるハンドリングをすると、v17では
となり、開いた瞬間閉じてしまいます。
そのため以下の記事を参考に、内部のモーダルの最も外側の要素でイベントのバブリングを止めるような実装に変更しました。
また一部上記の方法だと対応しきれないComponentは、documentをroot elementに置き換えて対応しました。
- React18の破壊的変更の対応
- renderからcreateRootに変更
- React.FCの暗黙的なchildrenの削除とReact.VFCのdeprecate
- StrictModeの挙動の変化
- その他に対応が必要だったライブラリ
- @testing-library/react-hooks
- connected-react-router
- @testing-library/react
- react-select
- typescript
- @typescript-eslint/eslint-plugin
- @typescript-eslint/parse
v18はReact自体のアップデートはスムーズでしたが関連ライブラリの対応が多かったです。
Greenfile.work入退場はリファクタリング中にTypeScriptへ移行した際にReact.VFCを使ってComponentを定義し、明示的にchildrenの型を指定していたため→から置換するのみでした。
内製ライブラリはComponentの型定義の方法が揃っていなかったため、必要に応じてchildrenの型を指定して対応しました。
関連ライブラリはエラーの出ないミニマムのバージョンまで上げ、最新まで上げるのは で対応しました。
@testing-library/reactの13系からhookに関するAPIも統合されてため削除しました。
react-router-domのバージョンに合わせてバージョンを上げました。
reactのバージョンに合わせてバージョンを上げました。
reactのバージョンに合わせてバージョンを上げました。
react-router-domのバージョンに合わせてバージョンを上げました。
typescriptのバージョンに合わせてバージョンを上げました。
typescriptのバージョンに合わせてバージョンを上げました。
webpack4からviteへの移行
次はビルドツールの対応です。
viteへの移行の背景
選択肢として上げたのは以下です。
- webpack v5に上げる
- Next.jsへの移行
- viteへの移行
結果としてviteへの移行を選択したのは技術的な側面よりも弊社の状況に合わせた消去法的な理由です。
まず全員がフロントエンドやバックエンド間やアプリケーション間を跨ぎながら開発をする環境で、webpackを運用していくのは難しいと考え、webpackからの乗り換えを決めました。
また現状、「内製ライブラリのComponentがReact Routerに依存しておりルーティング手法の変更がすぐにはできない」かつ「CSRのみで要件が満たせる」という理由で、Next.jsではなくviteへ移行を決めました。
ただNext.js含めフレームワークへの乗り換えは「今ではない」という判断です。
あくまで今回は外部ライブラリが起因による開発上の制約を外すのが目的であり、現状だと現環境による制約が強く技術を純粋に比較できないため、今後負債解消が進んだ段階で再度フレームワークへの乗り換えは検討するかと思います。
移行作業
viteへの移行は想像していたよりもスムーズでした。
既存のアプリケーションコードへの変更は
- 環境変数の参照先の変更
- index.htmlの移動
- の削除
くらいで、あとは既存のディレクトリ構造に合わせての設定をしました。
Hot Module Replacement(HMR)が出来るようになった
実はこれまでHMRが使えずソースコードの変更を反映させる際はその都度画面をリロードしていました。
HMR自体はwebpackでも可能ですが、弊社の開発環境ではminikube + telepresenceを採用しておりteleprensenceでinterceptしながらだとホットリロードが使えない問題がありました。
以前から何度かwebpackやminikube, telepresenceの設定を変更し修正を試みては解消できずにいたのですが、viteでと設定することでHMRが効くようになりました。
reduxをswrとuseContextに移行
次はreduxからの移行です。
reduxはバージョンアップとは別に状態管理手法として課題感があり、swrとuseContextへの移行を進めていました。
reduxは関連ライブラリが多いため先にreduxからの移行が終わってからの方が、外部ライブラリ全体のバージョンアップもスムーズに進むと思い、先に移行を進めました。
Global State管理ライブラリを使わずにuseContextを採用した理由
サービスの性質上stateのほとんどはServer CacheかLocal Stateであり、現在もGlobal Stateはほとんどありません。
そのため今はuseContextを使い、今後機能数が増えGlobal Stateの種類が増えてきたタイミングで、用途に合った適切なGlobal State管理ライブラリに乗り換えようと考えています。
その他ライブラリのバージョンアップ
最後に残ったライブラリのバージョンアップです。
破壊的変更の対応が難しいReact Routerなどを含む4つのライブラリを除く、外部ライブラリのバージョンまとめて上げてリリース時点で47/51の外部ライブラリのバージョンが最新になりました。
また不要なライブラリの削除や本番ビルドに不要なライブラリのdev dependenciesへの移行も行いました。
これから改善していきたいこと
最後にこれから改善していきたいことです。
外部ライブラリの定期メンテナンス
今回のリファクタリングでほとんどの外部ライブラリのバージョンを最新まで上げることが出来たので、今後は定期的にバージョンをメンテナンスできるようにしていきたいです。
内製ライブラリの外部ライブラリの整理
内製ライブラリはReactのバージョンを最新にしたものの、他の外部ライブラリのバージョンはまだ古いままなので引き続き上げていきたいです。
まとめ
外部ライブラリを整理してバージョンを上げたことで、機能開発や改善をする上での枷がなくなり全体的に色んなことが進めやすくなりました。
今後はこの状態を維持しつつ他の改善も進めていきたいです。最後まで読んでいただきありがとうございました。
さいごに
シェルフィーではエンジニアを中心に積極的に採用をしております!
技術以外にも、「コンテック(Con-Tech)って何?」「面白い?」「働き方は?」といった気になるご質問すべてに正直にお答えいたします。
ぜひ一度お話しましょう!下記からご連絡ください◎