はじめに
プロダクトの要件的にSSRは要らないよねという判断でnext.jsをやめSPAとして再構築しました。next.js自体のノウハウやSPAからnext.jsへの移行みたいな記事はよく見るのですが、逆にやめた話は管見の限り(よく調べていないという意味で使っています)、目にした記憶が無いので書く価値があるかなと思いました。決定の経緯や実際の移行に際しての手順などについて書こうと思います。
これがベストプラクティスと主張するつもりはなく、むしろ泥臭くコードを直していっているのでこうすると楽だよというノウハウがあればご教授いただけると嬉しいです。
経緯
すでに簡単に機能が作ってあるプロジェクトに参画
配属された時点ですでにプロジェクトは走り始めており、ある程度の画面や機能が作られていました。next.jsを利用し、バックエンドはfirebaseのauthenticationやfirestoreを利用する構成でした。
SDK使いたいので検討
既存のコードを改修していたところ、不便さを感じるようになりました。firebaseのリソースを操作する際、プロジェクトの要件的な部分やWeb以外の他チャネルとの兼ね合いから独自に実装したAPIを経由してfirestoreを操作する構成を取っていました。しかし、このAPIが他チャネル用の要件に従って実装されており、Web的には困ることがあります。一方でWebのチャネルのために改修を入れていくとAPI仕様が次々と複雑化していくことが目に見えて明らかでした。
そこでWebのクライアントはsdkを利用しつつ要件を実現できないか検討を進めました。結果、sdk利用でも良いだろうという結論にいたり、既存のコードをsdkで代替するように改修を進めました。
SSRでfirebaseを利用しようとすると結構面倒
しかしながら、課題に直面しました。SSRは語義の通りサーバサイドでレンダリングするため、初期化関連で考慮が必要になります。例えば、クライアント側で認証をしていてもサーバ側は認証されていないので認証エラーになります。SPAと同じノリで実装はできないということです。SSR時はサーバ想定でfirebase-adminを使う、CSRする部分ではfirebase-sdkを使うという形で考慮が必要になります。
参考:
https://qiita.com/centerfield77/items/799f2840f48221c2f84d
next.jsのまま、firesbaseを利用しようとすると、この辺の考慮を強いられるということです。
という課題について考えていたときに、SSR自体要らないのでは?という話に
一般にSSRのメリットとしては、
- サーバサイドでレンダリングするので初期表示が早く安定する
- SEOに強い
という点などが挙げられると思います。ですが、要件的にこれらの強みは特に必要ないだろうという結論にいたりました。
今後もSSRを利用しているために別途考慮が必要な点が出てくる可能性があるだろうということが予想され、作り込まれている機能の量も限られていたのでSPAに置き換えようという結論にいたりました。
このあたりは私はそもそもSSRでの開発経験に乏しいので、経験を積んでいる人が考えた場合には、異なる判断をした可能性があると思います。
移行
以下、移行の際にやったことです。
一旦全部消す
最新のmainブランチから切り出した作業ブランチにて、一旦プロジェクトの中身を一通り削除しました。残しつつ置き換えていくと中途半端な状態が続き苦労しそうだなと思ってのことです。git管理しているのですぐ復元できますし。
viteで初期化する
CRAとかsnowpackとか他にも色々ありますが、今回はviteを採用しました。一度viteの速さを知ってしまうとやめられないですよね。
既存で利用されている各種ライブラリを追加する
next.jsに関わりなく、機能を提供する上で必要なライブラリ類をyarn add
しました。
代替するライブラリを追加する
next.jsの機能で提供される機能やサーバサイドで動く前提のライブラリを置き換えました。例えば、以下のようなものです。
ルーティング
react-router-dom
です。v6は使ったことがなかったのでこの際、使ってみようと思いました。今のところ快適です。
jwtのデコード
アプリケーションにはJWTをデコードする処理があるのですが、jsonwebtoken
はnode環境で動く想定で、webだと動きません。jwt-decode
に置き換えました。機能が増えていくにつれこうした考慮が増えそうな予感がしました。
順番にrestoreして置き直していく
そもそもreact非依存なものたちを復活する
githubのワークフローやhuskyのスクリプトなどは基本的にそのまま使える(中身のコマンドは置き換わってますが)のでそのまま復活します。他そのまま流用できるものなどをrestoreしていきました。componentもそのまま利用できるものは様子を見つつrestoreしていきます。
修正が必要なものを直していく
一方で、next.jsのpages/配下のファイルなどはディレクトリ構成がそのままルーティングに利用されるなどしているので、修正が必要です。基本の構成は変えずにRouter.tsx
のようなファイルを作り、ルーティングさせるようにコードを書いていきました。この際、React.lazy
でコード分割するなどの最低限の調整は行いました。
動作確認
最後に一通り動作確認して終了です。
終わりに
今回は逆にnext.jsをやめた話について、その経緯と移行について書きました。要件や限られた時間での調査の範囲から上記のような結論にいたりましたが、そもそもの構築初期から参画していたり、もっとNextJSの開発経験や知識があると違った判断をしていた可能性があるという気もしています。このあたりは今後も手広く経験や知識を深めつつ、その時その時の最善の技術選定ができるようになりたいなと思います。