
ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #5:静的サイトのビルド
これまで4回にわたりヘッドレスCMSと静的ページを使ったJamstack構成のウェブサイト制作のフローをまとめてきましたが、第5回目の今回はいよいよ静的サイトのビルドを行っていきます。Nuxt.jsではSSGとしてもとても優秀で、さまざまな最適化がされていたりコマンド1つでビルドできるようになっていますが、何も気にせず進めてしまうとページ数が多い場合にはビルド完了までかなり時間がかかったり、API通信が発生している場合ではサーバーエラーを起こしたりすることもあります。今回はビルド時間短縮のための対応についてまとめていきたいと思います。また、これまでの流れについてはこちらの過去記事をご参考ください。
(過去記事)
・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #4:動的ページ(投稿詳細)の実装
・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #3:動的ページ(投稿一覧)の実装
・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #2:フロントエンドでのサイト制作
・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #1:ヘッドレスCMSの構築
これでヘッドレスCMSとSSGを使ったJamstackなサイトを公開することができました。サイトの仕様によってはそれ以外にもいろんな処理が必要になりますが、ベーシックなブログサイトであればそこまでハードルは高く無いのではないでしょうか。ビルド作業の手間はかかるものの、これまでのCMSサイトは基本的にサーバーサイドで動的にページが生成されているので、高速化などのパフォーマンス面から見てもこの方法で構築するのも選択肢の一つとしてはアリなのではないでしょうか。 (過去記事) ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #4:動的ページ(投稿詳細)の実装 ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #3:動的ページ(投稿一覧)の実装 ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #2:フロントエンドでのサイト制作 ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #1:ヘッドレスCMSの構築
SSGのgenerateで時間短縮の対応
Nuxt.jsではSSGもデフォルト機能として用意されていますので、generateコマンドを実行するだけで、HTMLやJavaScriptファイルが生成されます。あとはそのビルドファイルをホストサーバーにアップロードするだけで公開できるようになります。その時に「nuxt.config.js」の設定で、「ssr」のオプションを「true」に、そして「target」のオプションを「static」に指定しておくことが重要になります。こうすることでビルドが静的サイトに最適化されるようになります。例えば、動的ルーティングの指定が不要になったり、データを静的なJSファイルとして保存してそれを読み込むような形にすることで高速化を実現しているなどがあります。 ただし、動的ルーティングのページでAPI通信を使っている場合などは、そのままgenareteを実行してしまうと、毎回のページをビルドする際にAPIで読み込む形になるのでビルド時間が大幅に増えたりAPIサーバーに対して大きな負担がかかってしまいます。そこで「nuxt.config.js」で「genarete」の「route」オプション設定を下記のように加えていきます。 【nuxt.config.js】※一部抜粋import axios from 'axios'
export default {
ssr: 'true',
target: 'static',
......
generate: {
subFolders: true,
routes(callback) {
axios.get('https://example.com/api/blog/')
.then((response) => {
const routeList = response.data.map((post, index) => {
return {
route: `/blog/${post.ID}`,
payload: {
prev: array[index + 1],
current: post,
next: array[index - 1]
}
}
})
callback(null, routeList)
})
.catch(callback)
},
interval: 1000
},
......
}
本来ですと動的ルーティング(参考記事「Nuxt.jsでビルド時にサイトマップの導入と設定方法」)の設定のために使われる処理になりますが、SSGでtargetがstaticになっている場合、ここでAPI経由で読み込んだデータをペイロードデータとして個別ページで使うことができます。そのため、API通信が大幅に減ることになり、ビルド時間の短縮やAPIサーバーへの負担を軽減することができます。また「interval」オプションでは連続するAPI通信の間隔を設定でき、サーバーへのアクセスを分散させることができますので、合わせて設定しておくといいですね。ただし上げ過ぎてしまうとその分ビルド時間も増えてしまうので注意します。
動的ルーティングのページでは下記のように先程読み込んだデータを「asyncData()」メソッドのpayload引数に格納されるようになります。これでページ内にデータを表示させたり、処理で値として使うことができます。その際には、ペイロードデータの有無で通常の開発環境ではAPIを叩いてデータを取得できるようにしておきます。
【pages/blog/_id.vue】
<template>
<div>
<post-detail :post-data="posts" />
</div>
</template>
<script>
import { $axios } from 'axios';
import PostDetail from '~/components/PostDetail.vue';
export default {
components: {
PostDetail
},
async asyncData({ app, payload }) {
if(payload) {
return {
posts: {
nextPost: payload.next,
currentPost: payload.current,
prevPost: payload.prev
}
}
} else {
const response = await app.$axios
.get(`https://example.com/api/blog/${Number(params.id)}`)
.catch((reason) => {
return {
posts: {
nextPost: response.data[0],
currentPost: response.data[1],
prevPost: response.data[2]
}
}
})
if(response.status !== 200) {
error({
statusCode: response.status,
message: response.data.message
})
return
}
}
},
......
head() {
return {
title: this.posts.currentPost.title,
......
}
}
}
</script>
これでビルドを行う準備ができました。コマンドについてはnpm scriptがデフォルトで用意されているので、下記のようにpackage.jsonを確認し、環境に合わせたコマンドを実行します。(参考記事「Nuxt.jsでcross-envを使って本番環境と開発環境のURLを切り分けてみる」)
【package.json】※一部抜粋
{
"scripts": {
.......
"generate": "nuxt generate",
"generate-dev": "cross-env NODE_ENV=development nuxt generate",
"generate-stg": "cross-env NODE_ENV=staging nuxt generate",
"generate-prod": "cross-env NODE_ENV=production nuxt generate",
},
.......
}
では実際に下記のようにコマンドを実行すると静的サイトでのビルドが始まり、どんどんページが生成されていく様子がわかります。
$ yarn generate-prodSSGでgenerateコマンドを使ってビルドした場合には、下記のような形で指定されているビルド用のディレクトリ配下にファイルが生成されます。先述の通り、データは静的なJavaScriptファイルとして、 _nuxtディレクトリ配下にあるstaticディレクトリにデータが格納されているのが確認できました。
/DIST_DIR
┣ _nuxt
┣ static
┣ CHUNK_FILE
┣ ........
┣ HASH_NUM
┣ PAGE_DIR
┣ payload.js
┗ state.js
┣ ........
┣ payload.js
┗ state.js
┣ PAGE_DIR
┣ ........
┣ assets
┣ css
┣ js
┣ images
┣ ........
┣ index.html
┣ 404.html
┣ favicon.ico
┣ .nojekyll
┣ sitemap.xml
┣ ........
あとは、これらのファイル群を一式ホスト用のサーバーにアップロードして実際に表示されるかどうかをチェックしてみます。
API側である程度データの下処理をしておく
API通信で動的ルーティングを含むサイトのビルドでは、都度API通信が行われることを避ける以外にも、API側である程度データを整理しておくことも重要になります。とりあえずデータだけ一括で取得し、それをJavaScriptで加工するとなった場合、使わないデータも数多く含まれるため、できるだけサーバー側のAPIで必要最低限となるデータをクライアント側に返すようにしておきます。そうしないとビルド後のデータが膨大に膨れ上がってしまい、サーバーの容量も圧迫する原因にもなってしまいます。参考までに約800ページ相当のサイトの場合、下記のような差が出るようになりました。うまく設計しないと、ビルド時間がかなり長くなったり、書き出し後のファイル容量が膨大になってしまうので注意しておきたいですね。【Before】 intervalの設定値:3000 generate所要時間:59分 ビルドファイルデータサイズ:3.4GB ↓ 【After】 intervalの設定値:1000 generate所要時間:18分 ビルドファイルデータサイズ:369.5MB
その他ソースコード管理に合わせた対応
Nuxt.jsでビルドされたファイルにはキャッシュ対応のためファイル名がハッシュ値になっているものが存在します。基本的にビルド後のファイルをソースコード管理することは少ないと思いますが、差分を取りたいという場合にはビルド後のファイル名を固定で設定することができます。下記のようにnuxt.config.jsで「build」オプションの「filenames」でそれぞれ静的ファイルの命名ルールを変更することができます。 【nuxt.config.js】※一部抜粋export default {
.....
build: {
filenames: {
app: () => '[id].js',
chunk: () => '[id].js',
css: () => '[name].js',
img: () => '[path][name].[ext]',
font: () => '[path][name].[ext]',
video: () => '[path][name].[ext]'
},
......
},
......
}
また、先述の通りSSGではpayload.jsとstore.jsが生成されますがこのディレクトリ名も、毎回ハッシュ値が当てられるようになっているため、配下のファイルは内容が変わっていない場合でも全て差分として扱われることになります。そこで、このディレクトリ名も固定値にすることで、純粋な差分を取得できるようにします。こちらもnuxt.config.jsで「generate」オプションの「staticAssets」で下記のように固有の値を指定します。
【nuxt.config.js】※一部抜粋
export default {
.....
generate: {
staticAssets: {
version: 'payloads'
},
......
},
......
}
指定後にビルドを行うと、実際にペイロードファイルのディレクトリ名が変わっているのが確認できます。
/DIST_DIR
┣ _nuxt
┣ static
┣ CHUNK_FILE
┣ ........
┣ payloads
┣ PAGE_DIR
┣ payload.js
┗ state.js
┣ ........
┣ payload.js
┗ state.js
これでヘッドレスCMSとSSGを使ったJamstackなサイトを公開することができました。サイトの仕様によってはそれ以外にもいろんな処理が必要になりますが、ベーシックなブログサイトであればそこまでハードルは高く無いのではないでしょうか。ビルド作業の手間はかかるものの、これまでのCMSサイトは基本的にサーバーサイドで動的にページが生成されているので、高速化などのパフォーマンス面から見てもこの方法で構築するのも選択肢の一つとしてはアリなのではないでしょうか。 (過去記事) ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #4:動的ページ(投稿詳細)の実装 ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #3:動的ページ(投稿一覧)の実装 ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #2:フロントエンドでのサイト制作 ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #1:ヘッドレスCMSの構築