Nuxtで独自のルーティングを追加・拡張する

create
2021年02月22日
update
2021年02月22日

はじめに🐕

Nuxt では通常、ルーティングはディレクトリ構造から自動的に算出される。
一方で、ディレクトリ構造によらない独自のルーティングを手動で追加したいときもある(リダイレクト処理だけしたいときやエイリアスを利用したいときなど)。

そのようなルーティングを拡張するための方法として、nuxt.config.js ファイル内で router.extendRoutes プロパティを使う方法について説明する。

Table 1. 環境
App Version

Nuxt.js

2.14.12

router.extendRoutes プロパティ🛰️

nuxt.config.js ファイルの route プロパティにおける extendRoutes からルーティングを追加できる。
下記は設定の一例。

Example 1. nuxt.config.js
import { sortRoutes } from '@nuxt/utils'

export default {
  router: {
    extendRoutes(routes, resolve) {
      routes.push({
        path: '/blog/page/:id',   (1)
        component: resolve(__dirname, 'pages/blog/index.vue'),   (2)
        name: 'blog-page-id',     (3)
      })

      sortRoutes(routes)  (4)
    },
  },
}
1 追加するルートパスを指定。
例では動的ルーティングを追加している。
2 ルートパスに対応するコンポーネントのファイルを指定。
3 (オプション)ルートの識別名となる任意の値。
4 (オプション)ルートをソートしている。
要は vue-router の設定を行っている。スキーマなどの詳細はそちらを参照。

上記例では pages/blog/index.vue ファイルを指定しているため、/blog パスと /blog/page/:id パスとも有効かつ同一コンポーネントを利用している。

ルーティング拡張の設定例🧪

extendsRoutes の設定方法については Vue Router のガイドを参考にやればいい。
以下ではそのうちのいくつかをピックアップ……というか個人的なメモ。

ルートを複数設定するとき

routes.push() の引数にルートの設定オブジェクトを複数指定できる。

Example 2. ルートの設定オブジェクトを複数指定
nuxt.config.js
export default {
  router: {
    extendRoutes(routes, resolve) {
      routes.push(
        {
          // 1つ目のルート設定
        },
        {
          // 2つ目のルート設定
        },
        {
          // ...
        }
      )
    },
  },
}

リダイレクトさせたいとき

extendRoutes プロパティにて、ある URL でリダイレクトさせたい場合は次のように記述すればいい。

Example 3. /from → /to へとリダイレクトさせたい場合
nuxt.config.js
export default {
  router: {
    extendRoutes(routes, resolve) {
      routes.push({
        path: '/from',    (1)
        redirect: '/to'   (2)
      })
    },
  },
}
1 リダイレクトの対象となる元の URL パスを指定。
2 リダイレクト先の URL パスを指定。

ルートコンポーネントにプロパティを渡す

ルートコンポーネントに対して props を渡すこともできる。
単体テストをしやすくしたり拡張ルーティングか否かを判定したりするのに便利そう。

Example 4. propsを渡す
nuxt.config.js
export default {
  router: {
    extendRoutes(routes, resolve) {
      routes.push({
        path: '/sample/:slug',
        component: resolve(__dirname, 'pages/sample.vue'),
        props: { isExtendRoute: true, userId: 123 }   (1)
      })
    },
  },
}
1 この例では isExtendRoute プロパティと userId プロパティを渡している。
この props にはプロパティの値を返す Function オブジェクトを渡すこともできる(参考)。

meta タグを設定したいとき

HTML のヘッダ情報を表す MetaInfo オブジェクトをルートコンポーネントに渡し、その値を Vue インスタンスの head() メソッドで返すようにすればいい。

とはいえ .vue ファイル内で設定したほうが素直でよさそうなので、使い所は少ないかも。
特定の URL で canonical タグや noindex タグを付けたいときに使えそう。

meta プロパティが指定できるので直接 HTML の <meta> 要素として設定できそうだができない。
この meta プロパティはあくまで vue-router のルートメタフィールドでしかなく、HTML の要素とは無関係。
Example 5. metaタグを定義して渡す
nuxt.config.js
export default {
  router: {
    extendRoutes(routes, resolve) {
      routes.push({
        path: '/sample/page/:id',
        component: resolve(__dirname, 'pages/sample.vue'),

        /** @return {{metaInfo: import('vue-meta').MetaInfo}} */
        props: (route) => {   (1)
          return {
            metaInfo: {   (2)
              title: `${route.params.id}ページ目`,
              meta: [{ name: 'robots', content: 'noindex' }],   (3)
            },
          }
        },

        // meta: { ... }   (4)
      })
    },
  },
}
1 <head> 要素を返す関数を定義。この返り値がルートコンポーネントに props として渡される。
2 対象のプロパティに渡す MetaInfo オブジェクトを定義。
3 meta タグの設定。例では noindex メタタグを設定している。
4 vue-router のルートメタフィールド。HTML の <meta> 要素とは無関係なので今回は使用しない。
pages/sample.vue
<script lang="ts">
import { Component, Prop, Vue } from 'nuxt-property-decorator'
import { MetaInfo } from 'vue-meta'

@Component
export default class Sample extends Vue {
  @Prop({ required: false }) metaInfo?: MetaInfo  (1)

  head(): MetaInfo {  (2)
    return this.metaInfo != null
      ? this.metaInfo
      : { title: 'Sample page' }
  }
}
</script>
1 <head> 要素を受け取るプロパティ。
2 <head> 要素を定義するメソッド。

おわりに😎

Nuxt はディレクトリ構造からルーティングしてるから「カスタマイズしたいときは hook とか使わないといけないのかなー」と思ってたけど、簡単に独自設定もできる仕組みだった。

あんまり頻繁に使うものでもないけど、覚えておくとちょっと幸せになれそう。