TL;DR
context
の nuxtState
に layout
プロパティがあるので、そこにlayout値をぶっこむ!
前提
nuxt.jsでユーザー認証ガードをしなくちゃいけないけれども、LocalStorageに情報保持しなくちゃいけないときとかに、
非SSR な plugin をつくって ナビゲーションガード 設定することあると思います。
さらには非同期な処理も叩かなくてはいけないから、async/await にしちゃう!
そこで以下のように実装しました
export default ({app,redirect}) => {
app.router.beforeEach(async (to,from,next)=>{
if( /* 非認証ページ */ ) {
next();
} else if( /* 別途ストアの中に認証用データがないとき */ ){
redirect('/login');
} else {
const auth = await なんらかの非同期メソッド();
if( /* なんらかの非同期メソッドがオッケーだった時 */ ){
next();
} else {
redirect('/login');
}
}
})
}
リダイレクト後のページのlayoutが遷移前のPageComponentのlayoutのママだったんですね。
Vue-devtoolで見てもlayoutそのまま。
これも、universalモードで、直接アクセスしたときにのみ発生してまして、その後CSRで遷移するときは問題ないのです。
対処法
-
redirect
ではなく、routerのnext
でリダイレクトさせても発生 -
redirect
ではなく、location.replace
を使うと問題なし -
redirect
の時期をsetTimeout
すると時間によっては問題なし
2つ目は、layout/error を表示させてからリダイレクトする処理をしてた時に発見したんですが、早すぎてもだめでした。
ここも時間上の制約で深く探ってないです。
で、やっぱりredirectで処理させたかったので、$nextTick ならどうだと思って、
API: コンテキスト - Nuxt.js
でどこからアクセスしようか探してた時に、nuxtState
を発見しました。
こんな感じにすると無事正しいlayoutで表示されるようになりました。
export default ({app,redirect,nuxtState}) => {
app.router.beforeEach(async (to,from,next)=>{
if( /* 非認証ページ */ ) {
next();
} else if( /* 別途ストアの中に認証用データがないとき */ ){
nuxtState.layout = 'login';
redirect('/login');
} else {
const auth = await なんらかの非同期メソッド();
if( /* なんらかの非同期メソッドがオッケーだった時 */ ){
next();
} else {
nuxtState.layout = 'login';
redirect('/login');
}
}
})
}
(ただ、いまだに$nextTickの実行方法がわかりません。app.$nextTickは無いと怒られる...)
発生条件(がわかればいいなぁ)
これ、発生条件が自分には把握できず NuxtのGithubにもissue立ててないんですが、
- nuxt バージョンは 1.4.2
- universalモード
- ナビゲーションガードはクライアントサイドのみ
- コンポーネントが増えてくる前は大丈夫だった(ような気がする)
-
location.replace
だと大丈夫
ぐらいしかわかってません。
ぶっちゃけ、全部middleware内で、SSRでもアクセス可能な形の認証にしたかった。
あと、next
でやってないのOKなのかなって疑問。
時間ができたら再度nuxt側含めて探ってみる予定です。