Nuxt.jsのvue-routerの自動生成で詰んだ話

まさあき(@masaaakikunsan)です。
Nuxt.js を触っていますか？ 僕は、0→1の開発の場合大体 Nuxt.js でやらせてもらっています。
今回は Nuxt.js の便利な機能の一つの vue-router の自動生成で詰んだ話を書きます。

# TL;DR

- pages配下にスネークケースのファイルを作るとPage Not Foundになる
- generate の動的なルーティングの配列をセットすると治る

## Nuxt.js の Vue Router のルーティング定義自動生成

Nuxt.js では pages ディレクト内の .vue ファイルの構造に沿って、自動的に Vue Router の設定を生成してくれます。

例えば、下記のようなファイルの構造のときは

```
page/
--| index.vue
--| news.vue
--| user/
----| _id.vue
```

以下のような定義が自動的に生成されます。

```js
router: {
  routes: [
    {
      name: 'index',
      path: '/',
      component: 'pages/index.vue'
    }, {
      name: 'news',
      path: '/news',
      component: 'pages/news.vue'
    }, {
      name: 'users-id',
      path: '/users/:id?',
      component: 'pages/users/_id.vue'
    }
  ]
}
```

このように、.vue ファイル名またはディレクトリ名にアンダースコアのプレフィックスを付けるとパラメータを使って動的なルーティングを定義できます。
Vue.js ではルーティングを自分で定義する必要がありますが、 Nuxt.js では自動でやってくれるので非常に楽になります。

実際に見てみます。

<img width="302" alt="スクリーンショット 2018-05-01 19.43.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/186521/3d2f41c5-4c9b-00c6-4f44-01646f34f071.png">

このようなファイル構造で index.vue に nuxt-link で各ページに遷移できるようにしましょう。

```html:pages/index.vue
<template>
  <section class="container">
    <div>
      <nuxt-link to="news">News</nuxt-link>
      <nuxt-link to="user/1">User</nuxt-link>
    </div>
  </section>
</template>
```

実際の挙動は以下のようになります。

[![Screenshot from Gyazo](https://gyazo.com/69db7bc2a4fc00b34821f04fdd60178e/raw)](https://gyazo.com/69db7bc2a4fc00b34821f04fdd60178e)

ルーティングの定義通りになっているのがわかります。

## スネークケースのファイルを作るとPage Not Foundになる

上記の通り、非常に強力で便利な機能ですが、ルーティングにアンダースコアをつけると問題が生じます。

通常、 /hoge_hoge などの形式にすることはあまりないとは思いますが、クライアントからの要望でそうせざるを得ない場合を想定しましょう。

pages 配下に company_about.vue というファイルを作成後、 index.vue に以下を追加してみましょう。

```html:pages/index.vue
<template>
  <section class="container">
    <div>
      <nuxt-link to="news">News</nuxt-link>
      <nuxt-link to="user/1">User</nuxt-link>
      <nuxt-link to="company_about">Company About</nuxt-link>
    </div>
  </section>
</template>
```

実際の挙動を見て見ましょう。

company_about ページには nuxt-link で遷移して正しく表示されますが、リロードやURLを直で入力するとPage Not Foundになります

[![Screenshot from Gyazo](https://gyazo.com/f66375b9dd9fd6c7e846ad63f22616cf/raw)](https://gyazo.com/f66375b9dd9fd6c7e846ad63f22616cf)

https://trusting-lichterman-09c131.netlify.com/company_about
上記をクリックすると Page Not Found になるかと思います。

## 解決方法

問題を正しく認知するため、まずは generate で吐き出された dist を見て見ます。

<img width="301" alt="スクリーンショット 2018-05-01 20.07.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/186521/2e0e4ca5-b9f6-6270-2991-e10846d219eb.png">

company_about ディレクトがないのがわかります。

次に .nuxt ディレクトリの router.js を見て見ましょう。

<img width="384" alt="スクリーンショット 2018-05-01 20.08.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/186521/f2811d41-0b58-2458-771e-c89ab87f1a8b.png">

path が /company:about になってしまっています。

これらからわかるように、 Nuxt.js ではアンダースコアを含むと全て動的ルーティングとして判断してしまっています。
generate コマンドでは動的なルーティングは全て無視されるので、 nuxt.confing.js に /company_about のルーティングを追加してあげる必要があります。

```javascript:nuxt.config.js
generate: {
  routes: [
    '/company_about'
  ]
}
```

上記の記述をしたのちに generate をして dist を見て見ましょう。

<img width="301" alt="スクリーンショット 2018-05-01 20.16.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/186521/5fba07df-fb9e-e8ac-4762-615ce39be1a2.png">

company_about ディレクトリがあるのが確認できました。
これで URL の直叩きやローディングしても Page Not Found になりません。

## まとめ

そもそも、 routing にアンダースコアが含まれることはほぼないと思いますが、クライアントの要望によってはそうせざるを得ない場合があるのでその場合は generate にルーティングを追加してあげましょう。

当然 Nuxt.js のドキュメントにもこのようなケースの対処方法は記載していないので、この記事が役に立てばなと。