Edited at

Nuxt.js で SSR 時にも永続化された store の値を使う


はじめに

単に store を永続化したい場合について考えてみます。(ここでの store は vuex を指します)

store の永続化には vuex-persistedstate を使うと便利で,

単に永続化するだけであれば ssr false として plugin で読み込めばOKです


https://github.com/robinvdvleuten/vuex-persistedstate#nuxtjs


しかしこの方法だとブラウザ上で vue が読み込まれるタイミングまで store のなかみは空っぽになります. なぜなら plugin の設定で ssr を false にしているためです。

// nuxt.config.js

...
plugins: [{ src: '~/plugins/localStorage.js', ssr: false }]
...

場合によっては SSR (サーバーサイドレンダリング) する際に store の値を使いたい場合があるでしょう。

例えば Rest API へアクセスするための token を store に保存しているような場合です。

通常ログイン処理をしたあと一定期間の間はユーザビリティの観点から、ログイン状態を保持したいことが普通です。

普通の website ならセッションに保存する等の方策が取れます. しかしフロント側とバックエンドが完全に切り離されており, バックエンドが rest api で構成されている場合セッション以外の方法で承認を行う場合があります(たとえば JWT). この場合フロント側で JWT Token を保存しておく必要があります。

ブラウザが開いている間なら store の state に token を保存し同時に localstorage にも保存しておけば, ブラウザが閉じられるまでは token を保持できます。しかし一度ブラウザを閉じて再度アクセスしたときフロント側のサーバーでは local storage にアクセスできないため token を参照できません。

このため例えば asyncData など SSR と同時にサーバー内部で実行されるコード部分に, 承認が必要な API へのアクセス処理が入っている場合エラーになります。


SSR 時に使うには?

local storage の代わりに cookie storage を使いましょう。

// @/plugins/cookie-storage.js

// cookie storage による store の永続化

import createPersistedState from 'vuex-persistedstate'
import * as Cookies from 'js-cookie'
import cookie from 'cookie'

export default ({ store, req, isDev }) => {
createPersistedState({
key: 'your-application-name',
storage: {
getItem: key =>
process.client
? Cookies.getJSON(key)
: cookie.parse(req.headers.cookie || '')[key],
setItem: (key, value) =>
Cookies.set(key, value, { expires: 365, secure: !isDev }), // 365日間 cookie storage を保持する
removeItem: key => Cookies.remove(key)
}
})(store)
}

追加で js-cookie が必要なので追加しましょう

yarn add vuex-persistedstate js-cookie

あとはこれを nuxt.config.js に plugins として追記すれば OKです

// nuxt.config.js

module.exports = {
// 中略
plugins: [
'~/plugins/cookie-storage.js',
],
}


NOTE

secure オプションが development 環境以外では true になるようなコードになっています. (!isDev の部分がそれです).

secure=True の時 https でないと cookie は有効になりません。したがって production 環境では https でのアクセスでないと永続化が有効になりません。ちょっと注意。