Vue Router 4 (Vue.js 3) で 404 ページを表示する
この記事はユアマイスター アドベントカレンダー 2022の 11 日目の記事です。
はじめに
Vue Router は Vue.js で SPA を構築するための公式ルータです。
この記事は、Vue Router 4 で 404 ページを表示する方法を紹介します。
(Vue Router 3 は Vue.js 2 に、Vue Router 4 は Vue.js 3 に対応しています)
※SPA で catch-all としての 404 ページを表示する方法であり、ステータスコード:404 としてページを返す方法ではないことをご了承ください
ルート定義
公式ドキュメントにも記載されていますが、path: '/:pathMatch(.*)*'
をルートの最下部に定義します。
catch-all としてルートマッチし、404 ページを表示します。
※pathMatch
は変数名であるため、任意の名前で問題ありません
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
// ... 省略
import NotFoundView from '@/views/NotFoundView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
},
// ... 省略
// 404 最下部に定義
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: NotFoundView,
},
],
})
export default router
ルート定義の深堀り
path: '/:pathMatch(.*)*'
は一見(冗長な)正規表現のように見えますが、Vue Router が提供する以下のルートマッチシンタックスを組み合わせています。
Custom regex in params
正規表現により柔軟なルート定義を可能にします。
例えば、(設計の良し悪しはさておき、)パラメータが 数字 or 文字列 でルートを分けたい場合、以下のように定義することができます。
const routes = [
// パラメータが数字にマッチ
// 例. department/1, department/99
{
path: 'department/:departmentId([1-9][0-9])',
name: 'department-id',
component: DepartmentIdView,
},
// パラメータが1文字以上の半角英字にマッチ
// 例. department/sales, department/accounting
{
path: 'department/:departmentName([a-z]+)',
name: 'department-name',
component: DepartmentNameView,
},
]
Repeatable params
*
と+
は、ディレクトリ階層を持つルート (例. aaa/bbb/ccc/ddd) にマッチするシンタックスです。
例えば、 都道府県、都道府県/市区町村、都道府県/市区町村/町名 ...など住所の階層を持つルートをまとめて以下のように定義することができます。
const routes = [
// 都道府県、都道府県/市区町村、都道府県/市区町村/町名、 ...にマッチ
// 例. area/, area/tokyo, area/tokyo/setagaya, area/tokyo/setagaya/mishuku ...
{
path: 'area/:area*',
name: 'area',
component: AreaView,
},
]
Custom regex in params と Repeatable params の組み合わせ
Custom regex in params と Repeatable params を組み合わせることができます。(公式ドキュメント)path: '/:pathMatch(.*)*'
は.*
と*
の組み合わせで、
任意の文字列から成る任意のディレクトリの階層、つまりすべてのパスにマッチするルート定義です。
任意のパスを 404 ページとして表示する
パスを指定して 404 ページを呼び出すことができます。pathMatch
キーの値にパスパラメータを配列(ディレクトリ階層がない場合は文字列も可)で指定します。
// パス:/aaa/bbb/ccc/ddd を404ページとして表示する
{ name: 'not-found', params: { pathMatch: ['aaa', 'bbb', 'ccc', 'ddd'] } }
例えば、「タグ一覧ページからタグ別ポスト一覧ページを開くとき、ポストが存在しない場合は空ページの代わりに 404 ページを表示する」というユースケースを以下のように書くことができます。
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import { provideApolloClient } from '@vue/apollo-composable'
import apolloClient from '@/plugins/apolloClient'
import TagsView from '@/views/TagsView.vue'
import ListByTagView from '@/views/ListByTagView.vue'
// ... 省略
import NotFoundView from '@/views/NotFoundView.vue'
provideApolloClient(apolloClient)
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/tags',
name: 'tags',
component: TagsView,
},
{
path: '/tags/:tagSlug',
name: 'list-by-tag',
component: ListByTagView,
props: true,
beforeEnter: async (to, from, next) => {
try {
const tagSlug = to.params.tagSlug
const {
data: { posts },
} = await apolloClient.query({
// ... 省略
})
if (posts.length) {
next()
return
}
next({
name: 'not-found',
params: { pathMatch: ['tags', `${tagSlug}`] },
})
return
} catch (e) {
console.error(e)
}
},
},
// ... 省略
// 404 最下部に定義
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: NotFoundView,
},
],
})
export default router
終わりに
Vue Router 4 で 404 ページを表示する方法を紹介しました。どなたかのお役に立てたら嬉しく思います。