Nuxt.jsのSPAモードで作ったアプリケーションをFirebase Hostingにデプロイしたとき、パスパラメータのあるページでリロードをすると404になってしまう問題に遭遇したので、その回避方法を紹介します。
※ 前提
この記事のサンプルコードでは TypeScript + Composition API を使用しています。
原因
Nuxtでパスパラメータを表現したいときは、以下のようにディレクトリを切ることで動的ルーティングが実現できますよね。
pages
├── users
│ └── _id.vue
└── index.vue
このように定義することで/users/{id}
というページが動的に生成されるようになります。
しかしSPAモードでbuildした場合、こういった動的ルーティングをしているページは静的ページとして生成されないため、リロードすると404になってしまうのです。
回避方法
Firebase Hostingのカスタム404ページを使用し、404ページからもとのパスへリダイレクトさせることでリロードを実現することができます。
カスタム404ページを用意する
pages配下に404ディレクトリを作成し、index.vueを作成します。
pages
├── 404
│ └── index.vue // 追加
├── users
│ └── _id.vue
└── index.vue
ビルド時、ルートディレクトリに404.htmlが生成されるようnuxt.config.jsにgenerateプロパティを追加します。
export default {
generate: {
routes: ['404']
}
}
/404/index.vue
で現在のパスをクエリパラメータにセットし、リダイレクト用ページへリダイレクトさせます。
<script lang="ts">
import { defineComponent, onMounted, SetupContext } from '@vue/composition-api'
export default defineComponent({
setup(_props, context: SetupContext) {
onMounted(() => {
const pathName: string = window.location.pathname
context.root.$nuxt.$router.push('/redirect?path=' + encodeURI(pathName))
})
}
})
</script>
リダレクトページを用意する
pages配下にredirect.vue
を作成します。
pages
├── 404
│ └── index.vue
├── users
│ └── _id.vue
├── redirect.vue // 追加
└── index.vue
クエリパラメータのパスを取得し、もとのページへリダイレクトさせます。
こうすることで動的にページ遷移をする要領でパスパラメータありきのページが表示できるようになり、404エラーを回避することできます。
<script lang="ts">
import { defineComponent } from '@vue/composition-api'
export default defineComponent({
layout: 'empty',
asyncData({ base, redirect, query }) {
const param: string | (string | null)[] = query.path
if (param === undefined || typeof param !== 'string') {
return redirect('/')
}
const redirectPath: string = '/' + param.replace(base, '')
return redirect(redirectPath)
}
})
</script>
これでNuxtのSPAモードでパスパラメータを使用していても、リロードができるようになりました!
同じ問題で困っている方のヒントになれば幸いです。