GMOペパボ、ロリポップのエンジニア@sunecosuriです。
昨日は@bake0937による、Macの開発環境をzshで良い感じにする
でした。
ghq + peco の組み合わせ、一度知ったら手放せないくらい便利ですよね。
さて、今回私はNuxt.jsでのlocalStorageを扱う際にハマったお話とTipsのようなものをご紹介したいと思います。
Nuxt.js について
Nuxt.jsはSSR基盤を持ったVue.jsを用いたwebpackベースのフレームワークです。
詳細は公式ページを御覧ください。
Nuxt.jsの認証について
Nuxt.jsで認証を行うにあたって、nuxtServerInit
という
アプリケーションがロードされたとき、サーバーから取得できるデータをVuexのstoreに渡すことができる機構が提供されています。
session認証になりますが、公式にも以下のようにサンプルコードが提供されています。
sessionをそのままstateに渡すといった内容になります。
// store/index.js
export const actions = {
nuxtServerInit ({ commit }, { req }) {
if (req.session && req.session.authUser) {
commit('SET_USER', req.session.authUser)
}
}
}
これを用いて以下のようにlocalStorageからTokenを取得して認証を行おうとすると、初回ロード時にトークンが与えられていないというエラーが出て処理が失敗してしまいます。
//localStorageからtokenを取得できない
export const actions = {
nuxtServerInit ({ commit, state, dispatch }, { req }) {
if (localStorage.accessToken) {
commit('user/setToken', localStorage.token)
}
}
}
原因はライフサイクルにありました。
nuxtServerInitはSSRする際に最初に処理を行うためブラウザにあるlocalStorageにそもそもアクセスできるはずがありません。
Nuxt.jsのライフサイクル
これは、nuxtClientInitといったプラグインを独自に定義することで取得することができます。
やっていることはactionを定義するいたってシンプルなものですがnuxt.config.js で定義しているssr: false
がポイントになります。
// nuxt.config.js
module.exports = {
plugins: [{ src: '~/plugins/nuxt-client-init.js', ssr: false }]
}
// plugins/nuxt-client-init.js
export default async (ctx) => {
await ctx.store.dispatch('nuxtClientInit', ctx)
}
これを用いることでほぼ同じ記述でtokenを取得することができるようになります。
// localStorageからtokenを取得できる
export const actions = {
nuxtClientInit ({ commit, state, dispatch }, { req }) {
if (localStorage.accessToken) {
commit('user/setToken', localStorage.token)
}
}
}
Token認証を扱うにあたって
取得したトークンを認証ヘッダに加えてリクエストを送る際に個人的にハマったポイントがありました。
それは、Client側でトークンを取得しているため、Vue.jsのライフサイクルにおいてbeforeMount以降でないと処理ができないという点です。
所感としては、localStorageから値を表示するだけであれば上記は適していますが、「SSR × SPA」を行っているNuxt.jsにおいてはlocalStorageの値を基にAjaxでリクエストを送り、レスポンスを基に処理を行うといったシーンにおいては機能こそするものの、ページ遷移ごとにカクつきが生じて高速なページ遷移といったSPAとしてのメリットが失われてしまう、複雑な処理になるほどより管理しにくい構造になってしまうといった印象を持ちました。
まとめ
- Nuxt.jsでlocalStorageを用いた認証を行うには上記のライフサイクルを意識する必要がある。
- そもそもSSRする必要があるのかというのを再考する。
認証の結果に応じて表示するなど、場合によってはtemplateブロックにやssr:false
オプションなどを使えば解決できる問題かもしれません。
明日は@gatchan によるVue.jsでモーダルウインドウをつくったこと
についてのお話です。
-> GMOペパボ Advent Calendar 2017