microCMS

Nuxt.jsで大量に記事がある場合のgenerateにかかる時間を調べてみた

エンジニアリング
2020/03/11 松田 承一

Nuxt.jsなど静的サイトジェネレータを使うにあたっての懸念点としてビルドに時間がかかることがよく挙げられます。
弊社ではmicroCMSという静的サイトジェネレータとの相性が非常に良いヘッドレスCMSを運用しています。
そのため「数百記事あるんだけど公開から実際の反映までどのくらいかかりますか?」などといった問い合わせをいただくことも多いです。

そこで、本記事ではNuxt.jsを使っていて大量の記事がある時のページ生成(generate)にどの程度の時間がかかるのかを調査してみます。
Nuxt.jsはVue.js(JavaScript)ベースで静的サイトジェネレータとしても非常に人気があるフレームワークの一つです。

検証環境とテストプロジェクト

今回は手元のMacBook Pro(13-inch, 2017)にてテストを行いました。

  • macOS Catalina(10.15.3)
  • 3.1GHz Core i5
  • メモリ16GB


また、テストプロジェクトは非常に簡易的なNuxtプロジェクトを用意しました。
コードの全てはこちらからダウンロードできます。

テストプロジェクトの簡単な仕様は下記の通りです。

  • /blogs/{id} にブログ記事を書き出し
  • 記事の本文には小説「坊ちゃん」の冒頭約5000文字を表示(一般的なブログより多めの文字数)


nuxt.config.jsの内容を抜粋して以下に示します。プロジェクト内に含まれるcontent.txtに本文データが記載されており、ファイル先頭のblogCountの数だけブログ詳細ページを生成します。

const blogCount = 1000

...

generate: {
  routes() {
    //本文をファイルから取得しておく(実際にはこの部分がAPIなどから取得する想定)
    const content = fs.readFileSync('./content.txt').toString()

    //ブログ個別ページを生成
    return [...Array(blogCount).keys()].map(index => ({
      route: `/blogs/${index + 1}`,
      payload: { title: `${index + 1}番目のブログ記事`, content }
    }))
  }
}

計測結果

ビルドは以下の条件で行いました。

  • generate時にHTMLを生成するためNuxtのmodeはuniversalとする
  • ブログ個別ページ(/blogs/{id})以外の生成は行わない
  • ビルド成果物の格納ディレクトリであるdistは毎回削除する
  • blogCountの値は10、100、1000、1万、10万の5種類で検証する
  • 結果のバラつきを考えてそれぞれの値でビルドを10回実行する
  • ビルドコマンドはデフォルトの $ npm run generate(実体としてはシンプルなnuxt generate)を使用する
  • 計測はtimeコマンドの実時間(real)で見る


上記の条件を加味し各blogCountに手動で設定後、以下のようなコマンドでgenerate処理を走らせました。

$ (for i in {0..9};do rm -rf dist; time npm run generate; done) &> ~/Desktop/blogCount1000_result.log

【結果】ブログ記事が10個

  • ビルド時間(10回実行)
    • 13.04秒、13.01秒、13.40秒、13.00秒、13.04秒、12.96秒、13.92秒、13.24秒、12.96秒、12.69秒
  • 平均値:13.13秒
  • 中央値:13.03秒

【結果】ブログ記事が100個

  • ビルド時間(10回実行)
    • 13.49秒、13.64秒、13.43秒、13.54秒、13.47秒、13.42秒、13.53秒、13.51秒、13.57秒、14.96秒
  • 平均値:13.66秒
  • 中央値:13.52秒

【結果】ブログ記事が1,000個

  • ビルド時間(10回実行)
    • 21.83秒、21.53秒、21.15秒、20.74秒、20.94秒、20.86秒、21.63秒、21.92秒、21.55秒、20.77秒
  • 平均値:21.29秒
  • 中央値:21.34秒

【結果】ブログ記事が10,000個

  • ビルド時間(10回実行)
    • 73.35秒、73.00秒、73.74秒、73.07秒、72.32秒、73.71秒、72.17秒、73.41秒、73.28秒、73.61秒
  • 平均値:73.17秒
  • 中央値:73.32秒

【結果】ブログ記事が100,000個

  • ビルド時間(10回実行)
    • 580.92秒、586.71秒、573.38秒、582.63秒、561.36秒、569.45秒、586.54秒、581.36秒、578.21秒、571.87秒
  • 平均値:577.24秒
  • 中央値:579.57秒


これらの結果を表でまとめると以下のようになります。

考察

今回は記事数を10個から10万個までと幅広くビルド時間の計測を行いました。
microCMSでお問い合わせをいただくケースとして最も多いのは数千件程度ですので、この程度の件数であれば理論的には1分以内程度でページ生成が終わります。
実際にはCIの初期動作やデプロイなど前後の動作もあるため、ページへの反映まで2~3分といったところでしょうか。
この程度であれば許容できる場合も多いのではないかと思います。

今回の結果でわかったことは「ページ数が増えるとビルド時間が増える」ということは事実である一方、Nuxtのビルド自体が致命的なほどの時間を取るわけではなさそうということです。
さすがに10万件のコンテンツでは10分弱とある程度の時間はかかるものの、単純な量とIO処理を考えると現実的なラインと見ても良さそうです。

一方でこれまでの弊社の実例として「500記事ほどをページ生成するのに15分ほどかかる」といったお客様もいらっしゃいました。
このような場合、大きな原因は以下の2つがあげられます。

  • ほぼ全ページでAPIやファイルを読み込むなど、コンテンツ内容の取得タイミングが悪い
  • ページ自体が非常に長く、書き出し後のファイルサイズが大きい


これらをまとめて表現するとIO処理の量や回数によって遅くなるケースがある、ということです。
例えばブログ記事でカテゴリ情報を全ページの生成時に都度取得するような実装をしてしまうと、ページ生成にかかる時間はとてつもなく増えていきます。
generate処理の中で一度だけ全カテゴリを取得するなど、IO処理の回数を減らす工夫が必要です。

また、書き出されるページのサイズにも注意が必要です。
全ページを一度に書き出す都合上、その一つ一つのサイズが大きいと結果としてたくさんの時間がかかってしまいます。
ページ内に不要な要素がないか、サーバサイドに移せるものはないかなど十分に検討を重ねましょう。

おわりに

Nuxt.jsで大量のページを生成する場合のビルド時間の計測を行いました。
ページ数が増えるとビルドに時間がかかるというぼんやりとしたイメージを持つだけではなく、実際の運用に耐えうるかという観点で検討を進めるきっかけになれば幸いです。
今後、Nuxt.js以外の静的サイトジェネレータ等でも同様の計測・検証を行っていく予定です。
ご希望のフレームワークなどありましたらぜひご連絡ください!

-----

microCMSは日々改善を進めています。
ご意見・ご要望は管理画面右下のチャット、公式Twitterメールからお気軽にご連絡ください!
引き続きmicroCMSをよろしくお願いいたします!

ABOUT ME

松田 承一
ウォンタ株式会社の代表 / 家族=👨‍👩‍👧 / ヤフー→大学教員など→現職 / 管理画面付きAPIがすぐに作れるmicroCMSというサービス作ってます。