ブログじゃないもん

Nuxtのslugを静的ページ生成すると中身が同じになる現象を1行で解決

3分くらいで読めます

とりあえず解決法

超絶ハマってたのが突然あっさり解決してしまった、というお話。

結論から言うとnuxt.config.jsのgenerateでconcurrencyオプションを1に指定すると中身がきちんと分かれます。

concurrency: 1

こんな感じで入れてください。

export default {
    generate: {
        concurrency: 1
    }
}

これにたどり着くのに3週間かかりました。。

改めて、どんな問題が起こっていたか

問題が起こっていたのがまさにこのサイト「ブログじゃないもん」なんですが、作りはざっくりと以下の流れにしています。

  1. ローカルでMarkdownで記事を書く
  2. processmdでjsonに変換
  3. それを ~/pages/post/_slug.vue で読み込む
  4. 静的ページ生成(generate)したものを本番サーバーにアップロードして公開

nuxt上のファイル構成は以下のような感じ。

/pages
    ├ index.vue
    └ /post
        └ _slug.vue
            ├ /kiji1
            │   └ index.json
            ├ /kiji2
            │   └ index.json
            └ /kiji3
                └ index.json

これを静的ページ生成(generate)すると…

/index.html
    └ /post
        ├ /kiji1
        │   └ index.html ※中身は「kiji3」
        ├ /kiji2
        │   └ index.html ※中身は「kiji3」
        └ /kiji3
            └ index.html ※中身は「kiji3」

3までの部分を localhost:3000 上で確認するには問題なく、きちんと記事URLごとにそれに応じた内容が表示されるように作りました。

しかし最後の静的ページ生成(generate)をすると、slugごとにファイルは生成されるものの、中身がすべて同じ記事になってしまう、という状態でした。

原因は何だったのか

むちゃくちゃググったのですが出てくるのは基本的なslugの使い方とか、ヘッドレスCMSとの連携の仕方ばっかりでした。

基本みんなヘッドレスCMS使ってて、ローカルで書くって人はあんまりいないんでしょうか……?

とにかく情報が全然出てこなかったのでいろいろ試しまくった中で、やっと変化があったのがダメ元で nuxt-generate-cluster のプラグインを入れてみたとき。

/index.html
    └ /post
        ├ /kiji1
        │   └ index.html ※中身は「kiji1」
        ├ /kiji2
        │   └ index.html ※中身は「kiji3」
        └ /kiji3
            └ index.html ※中身は「kiji3」

みたいな感じで、完璧ではないにしても中身に少しバラつきが出たのです。

この nuxt-generate-cluster というのはgenerateの処理を並行化するプラグイン。通常は1ラインで生成するところを、4ライン同時に動かして生成を高速化する、というものです。

ここから推理するとファイルの中身が同じになってしまう原因は、generateの際に変数や繰り返し処理が最後まで動いてからいっぺんにファイル生成されるからではないか、ということ。

だからプラグインでファイル生成のラインを分けると、変数や繰り返し処理の段階にバラつきが出てファイルの中身に差が出てくるのではないか。

……という仮説を元に、ファイル生成が終わってから次の変数処理をする、というように処理スピードを意図的に落とせないか、と調べてみたらそれは一瞬で見つかりました。

むしろnuxt公式ドキュメントの generate プロパティ の最初のオプションとして書いてあった。。

「concurrency」のオプションは「単一のスレッドで同時に生成されるルーティングの生成の数を設定」する、つまり同時に生成するファイルの数を設定するオプション。

これがデフォルトで500になっている(最大500ファイルを同時に生成する)ので、1にしてしまえば1つずつ処理が回るわけです。

concurrency: 1

青い鳥は、こんなところにいたんだ……。

(でも「単一のスレッドで同時に生成されるルーティングの生成の数を設定します。」って普通に読んだら暗号すぎない??)

というわけで一応解決はできたわけですが、生成スピードをあえて落としている、ということなのでページ数が多いサイトには向かない方法かも。

解決のヒントになった nuxt-generate-cluster を入れるなりして、別途高速化を図っていただくのがよいかと思います。

もっと綺麗な解法(生成スピードを落とさないで)を見つけた方は是非Twitterとかで教えてください!