背景
Nuxt.js(SPA)+APIでWebサービスを公開しているのですが、SPA側をアップデート後に
ユーザ「エラーが出ます / 表示が崩れます」
私「キャッシュを消して再読み込みしてみてください」
ユーザ「直りました」
の流れが良くあります。
(キャッシュの消し方がよくわからないという問い合わせも受けたりします)
キャッシュさせずに毎回読み込ませれば良い話ではあるのですが、
SPAなので初回読み込みに時間がかかるため、
できれば必要な時だけうまく再読み込みさせたい・・・という悩みがありました。
解決方法の概要
以下のようにして解決しました。
処理
- API側に「期待するクライアントのバージョン」を返すエンドポイントを作成する
- クライアント側はページ遷移ごとにそのAPIをコールし、
「期待するクライアントのバージョン」と実際に動作しているクライアントのバージョンを比較
クライアントのバージョンのほうが古い場合はスーパーリロードを促す
アップデート時の手順
- アップデートさせたい更新がある場合はクライアント側バージョンをインクリメントしてデプロイ
- クライアント側のデプロイが完了したらAPI側が「期待するクライアントのバージョン」を上げる
(先にAPI側を上げると無限スーパーリロード地獄になるので注意)
詳細
簡略化して雰囲気で記載しています。
API側
省略。ここでは http://localhost:8080/version
をコールしたら以下のレスポンスが返ってくるものとします。
{
"expect_client_version": 1
}
私はサボってDBでバージョン番号を管理し、それを返すだけにしています。
Nuxt.js側
ページ遷移ごとにチェックさせたいので、middleware
を使います。
axios
については設定の記載を省略していますが、
baseURL
にhttp://localhost:8080
が設定されています。
const version = 1 // 簡単のためここにクライアント側バージョン直書き
export default async function({ app }) {
const res = await app.$axios.$get('/version')
// 期待するバージョン以上なら何もしない
if (res.client_version <= version) return
// 反映させるためにスーパーリロードを促す
if (
window.confirm(
'新しいバージョンが配信されているため最新バージョンに更新します。'
)
) {
location.reload(true)
}
}
コメントにある通り、クライアントが期待されるバージョンよりも低かった場合はダイアログでスーパーリロードを促します。
export default {
// ...省略
router: {
middleware: ['version']
},
// ...省略
}
これでページ遷移ごとにversion.js
の内容が実行されるようになります。
アップデート時
クライアント側のバージョンを上げる
const version = 2
// ...省略
クライアント側をデプロイする
この時点で以下の状態になります。
- APIから返ってくる「期待するクライアントのバージョン」は1
- ユーザが利用しているクライアントのバージョンは1と2が混在
APIが返す「期待するクライアントのバージョン」を上げる
DB管理ならupdateなど。
{
"expect_client_version": 2
}
を返すようにします。
これでバージョン1のクライアントを使用している人だけ再読み込みを促され、
再読み込みするとバージョン2になります。
余談
要件次第ですが、APIのレスポンスに常に「期待するクライアントのバージョン」を含めて、
axios
の呼び出しの度にチェックするのもありだと思います。