なぜやるのか
SPA は、新しいコードがデプロイされた後もリロードしない限り古いコードで動き続ける。 例えば古い API を廃止したいのに、古いコードで使い続けているユーザーがいると困る。 新しいコードがあったら新しいコードを使うようにするための方法を考えてみた。
実現方法の検討
ユーザーにアクションしてもらうか
まずはバージョンを更新するときにユーザーのアクションが必要かどうかを考える。 更新方法を 2 種類に分けて考えてみる。
- ユーザーに通知してリロードしてもらう
- 勝手にアップデートする
ユーザーにアクションしてもらうのが 1、してもらわないのが 2。
で、1 は以下の理由から NG。
- 放置される
- いずれ更新通知があるのが当たり前になる
- スマホの OS やアプリの更新通知が出てもアップデートしない人がほとんど
- ユーザー側に判断の権利をもたせる意味がない
- バージョンコントロールをしたいのは開発側なのに?
- ユーザーの手間・認知負荷が増える
- 「え、これってアップデートしていいの?」
- 「なんか出てきたんですけど、これってどうしたらいいんですか?」
- 「とりあえず『いいえ』っと……」
ということで「2. 勝手にアップデートする」は確定。
アップデートしたことを通知するか
不要。 なぜならユーザーはバージョンを気にしておらず、使えればいいから。
随時リリースを採用しているプロダクトでは、場合によっては 1 分ごとに更新通知が出る。 画面の一部に通知が出っぱなしになっているサービスは、自分は使いたいと思わない。
バージョン更新の手法
次に、バージョンを更新するときの具体的な手法はどうするか。
前提として、JS はまるっとビルドしたものをクライアントに配信する。 これはたいてい複数のファイルに分かれている。 それらは一回のビルドで作られたもの同士でうまく動くように作られるが、別のタイミングでビルドしたものと一緒には動かない(基本的には)。
ということで、すべてのソースを更新するのが間違いない上にシンプルで導入しやすいと思う。 開発では HMR が使えるが、本番環境で使うことは想定されていないはず。 一番楽なのはリロードすること。 普通の Web に乗った作りだからバグもそれほど発生しないのでは。
パフォーマンス
せっかくの SPA なのにリロードしてしまっては、ユーザーがソースをダウンロードする時間がかかってしまう。 これは、最近のメタフレームワークを使っていれば、すべて一つにまとめるのではなくチャンクに分かれているので、それほど時間がかからないと踏んでいる。 もちろん計測は必要。
いつバージョンを更新するか
ユーザーが入力している内容が消えるのはダメ。 つまり適当なタイミングでリロードさせるのはダメ。
ユーザーが絶対に入力していないとき、つまり画面遷移時にリロードさせるのが一番丸そう。 例外はあって、ローカルでデータを複数画面で引き継いでいて、サーバー側にデータを保存していないときは対象外にする必要がある。 サーバーに投げるには重いファイルをローカルで読み込んでいる、とか。 これは sessionStorage などで引き継いでリロードしちゃうのもあり。
それより長いスパンでリロードできるところがあるか考える。 強いて言えばログイン時だが、これはスパンが長すぎるし、サービスによってはログアウトされずに使い続けられちゃうので難しい。
更新検知
次に、バージョンが更新されていることをどうやって判断するか。
SPA の場合は何もしないと何もしない(バージョンが更新されていることがわからない)ので、バージョンが更新されていることを明示的に取ってくる必要がある。 バージョン情報を取得できる API を作って叩き、バージョンがローカルと違っていたら次の画面遷移時にリロードを挟むのがいいというか楽。
バージョン情報の取得は、ショートポーリングでもいいしページ遷移時でもいい。
まとめ
ユーザーが画面遷移したとき、もし新しいコードがデプロイされていたら、画面をリロードさせる(一部対象外の画面あり)。 新しいコードがデプロイされているかどうかは、専用の API を使って取得する。
これは頭の中で考えたことなので、実際に作ってみたら微妙かもしれないが。