親バカエンジニアのナレッジ帳

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。

Nuxtのrouterやmetaを自由にカスタマイズしたい

Vue.jsとNuxt.jsのrouterの違い

Vue.jsでは、ルーティングを設定する際にrouter/index.jsなどで自分で自由に設定することができます。
カスタマイズなど自由自在で、pages配下のファイルの置き場所に関係なく、pathやcomponentやname、それにmetaなどを設定することができました。
このあたりを参照。
ti-tomo-knowledge.hatenablog.com
metaは本当に便利ですよね。

Nuxt.jsでのルーティングは便利だけどデメリットも

Vue.jsでは自由にカスタマイズがしやすかったrouterも、Nuxt.jsになってからは仕組みが変わります。
Nuxt.jsでは、pages配下のファイル(ディレクトリ)構成によって、勝手にルーティングが変わってしまうのです。
例えば以下のファイル(ディレクトリ)構成の場合、

pages
  test_dir1
    page1.vue
    page2.vue
  test_dir2
    page3.vue
    page4.vue

page1.vueにアクセスしたい場合
→test_dir1/pages1にアクセス

page2.vueにアクセスしたい場合
→test_dir1/pages2

page3.vueにアクセスしたい場合
→test_dir2/pages3

page4.vueにアクセスしたい場合
→test_dir2/pages4

のように自動で(言い方帰れば勝手に)ルーティングされます。
ルーティングの結果はビルド後に.nuxt/router.jsに作成されます。
単純なルーティングしかないプロジェクトであれば問題ありません。
ただ、例えばpage1.vueのテンプレートを他のURLでも表示させたい場合はどうしたら良いのでしょう。
また、meta要素はどうやって設定するのでしょう。

どうやってNuxtでルーティングをカスタマイズする?

例えばpage1.vueのテンプレートを他のURLでも表示させたい場合の方法についてです。
方法は簡単で、nuxt.config.jsでextendRoutesを使用します。
ja.nuxtjs.org
参照。

例えば以下のようにすれば、「/page5」にアクセスすることでtest_dir1配下にあるpage1.vueのページを開くことができます。

export default {
  router: {
    extendRoutes (routes, resolve) {
      routes.push({
        name: 'page5',
        path: 'page5',
        component: resolve(__dirname, 'pages/test_dir1/page1.vue')
      })
    }
  }
}

ちなみにextendRoutesでは以下のようにmetaを設定することも可能です。

export default {
  router: {
    extendRoutes (routes, resolve) {
      routes.push({
        name: 'page5',
        path: 'page5',
        component: resolve(__dirname, 'pages/test_dir1/page1.vue'),
        meta: {meta1: 'meta1です', meta2: 'meta2です'}
      })
    }
  }
}

ルーティングを設定した後は、sortRoutesを使用して最後にソートをかけた方が.nuxt/router.jsで後から確認がしやすいです。

import { sortRoutes } from '@nuxt/utils'
export default {
  router: {
    extendRoutes (routes, resolve) {
      routes.push({
        name: 'page5',
        path: 'page5',
        component: resolve(__dirname, 'pages/test_dir1/page1.vue'),
        meta: {meta1: 'meta1です', meta2: 'meta2です'}
      })
      sortRoutes(routes)
    }
  }
}

metaの設定は?

metaに関しては、新しくルーティングを追加する場合は上記のようにextendRoutesのroutes.pushで設定可能です。
では、ディレクトリ構成から自動で生成されたルーティングに対してmetaタグを設定する場合はどうしたらよいでしょう?
ちょっと無理矢理な方法になりますが、ここでもextendRoutesを使用します。
.nuxt/router.jsを確認いただければわかるのですが、自動で作成されたルーティングに対してはディレクトリ構成によりnameが付与されています。
test_dir1/pages1であれば「test_dir1-page1」、test_dir1/pages2であれば「test_dir1-page2」のように。
なので、そのnameを持つルーティングに対してmetaの設定を追加すれば良いのです。

export default {
  router: {
    extendRoutes (routes, resolve) {
      routes.forEach(route => {
        if (route.name === 'test_dir1-page1') {
          route.meta = {meta1: 'meta1です', meta2: 'meta2です'}
        }
        if (route.name === 'test_dir1-page2') {
          route.meta = {meta1: 'meta1です', meta2: 'meta2です'}
        }
      })
    }
  }
}


ちょっと応用になりますが、以下のように「test_dir1.vue」や「test_dir2.vue」を設定してその中で「」を置いている場合、routesの階層が1つ深くなります。

pages
  test_dir1
    page1.vue
    page2.vue
  test_dir2
    page3.vue
    page4.vue
  test_dir1.vue
  test_dir2.vue

そのような場合はforEachの中にforEachを設定すれば同じようにmetaの設定が可能になります。

export default {
  router: {
    extendRoutes (routes, resolve) {
      routes.forEach(route => {
        route.children.forEach(childRoute => {
          if (childRoute.name === 'test_dir1-page1') {
            childRoute.meta = {meta1: 'meta1です', meta2: 'meta2です'}
          }
          if (childRoute.name === 'test_dir1-page2') {
            childRoute.meta = {meta1: 'meta1です', meta2: 'meta2です'}
          }
        })
      })
    }
  }
}