概要
Nuxt.js の plugin に渡ってくる context から route を取り出しても、それは plugin が初期化される時点の route なので、その後 SPA 遷移によって変化していく route を捕捉できない。
ここでは Nuxt.js の middleware に頼らずに、plugin からリアクティブに route を扱う方法を書く。
実例
app に生えてる router の hook で変更を検知していく。
以下が url hash をリアクティブに扱う例。
hash.tsimport { Context } from '@nuxt/types';
import { defineNuxtPlugin, ref } from '@nuxtjs/composition-api';
const makePlugin = ({ app }: Context) => {
const hash = ref('')
app.router?.beforeEach((to, from, next) => {
hash.value = to.hash
next();
});
watch(hash, (newHash, oldHash) => {
console.log(newHash, oldHash)
})
return {
hash,
};
};
export default defineNuxtPlugin((ctx, inject) => {
inject('sample', makePlugin(ctx));
});
export type HashPlugin = ReturnType<typeof makePlugin>;
/*
setup() {
const { $sample } = useContext()
console.log($sample.hash.value) // #hoge
}
*/
以下がサインインページに遷移する前の URL path を SessionStorage に保存しておく例。@vueuse/core
を利用している。
signinRedirectPath.tsimport { Context } from '@nuxt/types';
import { defineNuxtPlugin, ref } from '@nuxtjs/composition-api';
import { useSessionStorage } from '@vueuse/core';
const sessionStorageKey = 'signInRedirectPath'
const makePlugin = ({ app }: Context) => {
const path = useSessionStorage(sessionStorageKey, '');
app.router?.beforeEach((to, from, next) => {
if (to.name === 'signin') {
path.value = from.path
}
next();
});
return {
get path() {
return path.value
},
clear: () => {
path.value = ''
}
};
};
export default defineNuxtPlugin((ctx, inject) => {
inject('signInRedirectPath', makePlugin(ctx));
});
export type SignInRedirectPath = ReturnType<typeof makePlugin>;
/*
setup() {
const { $signInRedirectPath } = useContext()
console.log($signInRedirectPath.path) // /hoge/
}
*/
なお上記の2例では ReturnType で plugin の型を定義しているので、plugin 利用側が plugin の実装に依存する。
依存性を逆転させたい場合は interface を別途定義した上でそれを満たすようにすると良い。
まとめ
VueRouter のフックを使いたいからと、plugin と middleware に処理が分散するとコードを追いづらいしテストを書くのも面倒。
app.router のフックを利用すれば一箇所に記述をまとめられ、@nuxtjs/composition-api と組み合わせれば Ref として扱える。
コンポーネントでやるのと同じように watch や computed に利用できる上に、 @vueuse/core
といった composable も利用できる。