Nuxt.jsには指定したルートが存在するか調べる方法は一応あったが…

シェアする:

この記事をおすすめしたい人

  • Nuxt.jsで指定したルートが存在するか確認したい人
  • Nuxt.jsで動的ルーティングの存在チェックをしたい人
  • つまりオレ

今回はNuxt.jsで「指定したルート(URL)が存在するのか?」を確認できる方法を調べていきます。

いやまぁ、あるにはあったんだが…

仕組み上、難しそうだよね…みたいな話をしたいと思います。

WordPressの上でな!

※ このブログはWordPress製です

VueRouterのresolve()を使う

Nuxt.jsというかVue.jsの方の機能、VueRouterのresolve()を使います。

resolve()は1~3の引数を持てるようで、第1引数に調べたいルート、第2引数は現在のルート、第3引数は第2引数にパスの追加のようなので今回は使用しません。

第1引数に調べたいパスを入れ、この↓ような形でチェックします。


this.$router.resolve('/test/')

これは本来は、指定したルートの情報を取得する関数のようで、その戻り値の中身から存在チェックができないかを見ていきます。

resolve()の戻り値

以下の要素を持つオブジェクトです。

  • 「href」
    第1引数で指定したパスが入っています。
  • 「location」
    hash・params・path・queryを要素に持つオブジェクト
  • 「normalizedTo」
    テスト環境では「location」と同じ中身でした
  • 「resolved」
    今回のメインターゲット。詳細は後で。
  • 「route」
    「resolved」と同じ内容でした

resolvedの中身

  • 「fullPath」
    第1引数で指定したパスが入っています。
  • 「hash」
    テスト環境では空の文字列でした。
  • 「matched」
    第1匹数にマッチしたルートの配列が返っているっぽいです。
  • 「meta」
    テスト環境では空の文字列でした。
  • 「name」
    ページのタイトルではなく、ルートの種類?とでも言うのか、テスト環境では「post-slug」が入っていました。
  • 「params」
    動的ルーティングのパラメータが入っています。
  • 「path」
    第1引数で指定したパスが入っています。
  • 「query」
    GETのパラメータが入っています。

存在するURLでVueRouterのresolve()の挙動を確認

まずは存在しているのが分かっているページを指定します。


this.$router.resolve('/')

トップページです。

実行結果↓。
(戻り値の中のresolvedの中身です)

  • 「fullPath」
    「/」
  • 「hash」
    空の文字列
  • 「matched」
    1個の要素が入っていました。詳細は後述。
  • 「meta」
    空の配列
  • 「name」
    「index」
  • 「params」
    空の配列
  • 「path」
    「/」
  • 「query」
    空の配列

「/pages/test.vue」に対する挙動

「/pages/test.vue」を作成します。 ルートは「/test/」になります。

空の要素を除外し、トップページと異なった部分の実行結果↓。

  • 「fullPath」
    「/test/」
  • 「name」
    「test」
  • 「path」
    「/test/」

なんとなくの予想通りです。

「/pages/test/index.vue」に対する挙動

「/pages/test/index.vue」を作成します。 ルートは先ほどと同じ「/test/」になります。

  • 「fullPath」
    「/test/」
  • 「name」
    「test」
  • 「path」
    「/test/」

同じ結果になりました。

「name」はページ名を表していそうだけど、「○○○.vue」の部分の名前を使っているわけではないことが分かります。

「name」=「index」はトップページのみ。

「/pages/test/test.vue」に対する挙動

「/pages/test/test.vue」を作成します。 ルートは「/test/test/」になります。

  • 「fullPath」
    「/test/test/」
  • 「name」
    「test-test」
  • 「path」
    「/test/test/」

これもなんとなく予想通りです。

「name」が「test」ではないことから、階層構造も持っていることが分かります。

「/pages/index/index.vue」に対する挙動

「/pages/test/index.vue」を作成します。 ルートは「/index/」になります。


[vue-router] Named Route 'index' has a default child route.
When navigating to this named route (:to="{name: 'index'"), the default child route will not be rendered. 
Remove the name from this route and use the name of the default child route for named links instead.

そもそもページを作った段階で怒られてしまいました。

「will not be rendered」と言っているので試しに「/index/」にアクセスしてみると404でした。

一応、resolve()の結果を見てみるとこの↓ように。

  • 「fullPath」
    「/index/」
  • 「name」
    「null」
  • 「path」
    「/index/」

matchedは空の配列になっていました。

「/pages/test/index/index.vue」に対する挙動

「/index/」はトップページ直下だったからダメなのかと考え、「/pages/test/index/index.vue」を作成します。 ルートは「/test/index/」になります。


[vue-router] Named Route 'test' has a default child route. 
When navigating to this named route (:to="{name: 'test'"), the default child route will not be rendered. 
Remove the name from this route and use the name of the default child route for named links instead.

同じく怒られました。

「/index/」を含むルートがそもそもダメっぽい。

resolve()の結果は先ほどと同様です。

以上の事から「path」「fullPath」にはルートが、「name」には「path」をハイフンで繋いだものが入ることが分かりました。 トップページだけは「name」が「index」となります。

存在しないURLでVueRouterのresolve()の挙動を確認

ルート「/test/」が存在しない状態でresolve('test')を実行してみました。

  • 「fullPath」
    「/test/」
  • 「name」
    「null」
  • 「path」
    「/test/」

「/index/」の時と同様に、matchedは空の配列です。

これまでの実験と合わせると存在しないURLを叩くと、次のようになることが分かります。

  • 「name」が「null」になる
  • 「matched」が空の配列になる

つまり、ページが存在するかどうかは、


this.$router.resolve('/xxxx/')

の戻り値のresolvedの中の、「name」が「null」か「matched」の要素数をチェックすればよさそうです。

動的ルーティングに対しては一気に挙動が変わる

ヘッドレスCMSからコンテンツを取得する場合、ほとんどのページが動的ルーティングになるでしょう。

動的ルーティングのルートに対して存在チェックが可能か調べてみます。

「/pages/test/_id.vue」を作り、IDには1以上の整数が入るものとします。
(CMS側にはID1~10までが存在している)

「/test/1/」に対する挙動

実行結果↓。

  • 「fullPath」
    「/test/1/」
  • 「matched」
    要素1個の配列
  • 「name」
    「test-id」
  • 「params」
    {id:1}
  • 「path」
    「/test/1/」

動的ルーティングなので「params」に値が入ってきました。 今回は別にページ生成するわけじゃないので以降無視します。

「name」がちょっと変わりましたね。 動的ルーティングの場合は動的な部分が追加されるようです(今回はid)。

「/test/11/」に対する挙動

id=11はCMS側には存在しませんが、「_id.vue」内のvalidateのルール上は問題のないIDで、APIを叩いて初めて存在しないことが分かるルートです。 実際に「/test/11/」にアクセスすると、404にはなりませんが、APIからのデータが空なものとして処理されました。

実行結果↓。

  • 「fullPath」
    「/test/11/」
  • 「matched」
    要素1個の配列
  • 「name」
    「test-id」
  • 「path」
    「/test/11/」

ページが存在するときと同様の値が返ってきてしまっています。

「/test/0/」に対する挙動

idは「_id.vue」内のvalidateで「1以上の整数」でなければfalseを返すようにしています。 実際に「/test/0/」にアクセスすると404になります。

これなら存在しないことを検知できるのではと実行してみた結果↓。

  • 「fullPath」
    「/test/0/」
  • 「matched」
    要素1個の配列
  • 「name」
    「test-id」
  • 「path」
    「/test/0/」

なんと、404にもかかわらず、ページが存在するときと同様の値が返ってきてしまいました。

存在しない動的ルーティングはmatchedの中身で判別できないか?

「name」と「matched」の要素数では判別できませんでしたが、「matched」の中身からページが存在するかどうかを判別できるかもしれません。

というわけで、上記実験の「id=1」(確実に存在する)、「id=0」(存在しないしvalidate上も問題あり)のmatchedの中身を比較してみます。


beforeEnter: undefined
components: {default: ƒ}
instances: {}
matchAs: undefined
meta: {}
name: "test-id"
parent: undefined
path: "/test/:id/"
props: {}
redirect: undefined
regex: /^\/test\/((?:[^\/]+?))\/$/i

残念ながら完全一致でした…。

動的ルーティングが存在するか調べる方法はないのか

あります。

APIから記事を取得するときと同様、存在チェックしたい場面でAPIから情報を取得し、結果を返せば存在するし、返さなければ存在しないと判断できます。

存在チェックをする場面でこの処理が可能で、なおかつAPI1回叩くのが無駄ではないなら、やる価値はありそうです。

そうでなければそもそもサイト設計自体を考え直した方がいいのかなという結論に至りました。

なぜNuxt.jsはページの存在を確認しにくいのか

Nuxt.jsの仕組み上、外部APIからコンテンツを取得する場合、「実際に取得してみるまでその内容が分からない」からだと思います。 これは原理的に、Nuxt.jsに限らず、外部APIからコンテンツを取得するフレームワーク全般で同じなんじゃないでしょうか。

どうしても事前に知りたい場合は、その段階でAPI叩いて中身をチェックするしかなさそう。

静的なルーティングに関しては「this.$router.resolve()」で知ることができるようです。

まとめ

Nuxt.jsで指定したルートが存在するか知りたい場合は「this.$router.resolve()」を実行し、戻り値の中のresolvedの中の「name」がnullかどうか、「matched」の要素数が1以上かどうかで判断できそうです。

動的ルーティングの場合はお手軽にはできなさそう。 validateで404にしていても、それすら判別できないっぽい。

どうしても動的ルーティングで存在チェックしたい場合は、API叩いてチェックすればよさそうです。

以上、WordPressからお届けしました!

シェアする: