この記事で達成すること
この記事では、Nuxt.jsにgenerate
プロパティを追加して、動的なルーティングの静的ファイルを出力する設定を行います。
nuxt.config.js
は?動的?静的?なんやそれ?と思われた方、心配ありません。順に説明して操作に入ります。
まず、現状を確認しましょう。
現状の問題点の確認
デモブログのトップページに移動して、「この記事をみる」をクリックし記事を表示してみてください。
どうですか?ちゃんと記事が表示されましたね。
それでは、その記事ページをリロードしてみてください。
エラーが出ました。「そんなページ無いよ」と怒られました。
これはなぜでしょう。
答えはサーバーにHTMLファイルがないから
答えは簡単です。
指定されたURLを見に行っても、その場所にはHTMLファイルが無いからです。
今の状態が、サーバー側でHTMLファイルを生成出来ていない、いわゆる「サーバーサイドレンダリング」が出来ていない状態です。
トップページを経由した場合に表示できるのは何故?
それでは何故、トップページを経由した場合は記事が表示されるのでしょうか。
それは、クライアント(ブラウザ)でHTMLファイルを生成しているからです。
これが「シングルページアプリケーション」の仕組みです。
あれ?トップページは表示できるけど...
あれ?また疑問が出てきました。
トップページは何度リロードしても表示されますね。
それはHTMLファイルが存在するからです。
トップページは「サーバーサイドレンダリング」が出来ているんですね!
記事ページだけレンダリングが出来ていないのはなんで?
記事ページだけサーバーサイドレンダリングが出来ていないのは、Nuxt.jsの仕組みにあります。
その前にまず、レンダリングの仕組みを説明します。
サーバーサイドレンダリングの仕組み
Nuxt.jsは、generate
コマンドが実行された際、ルートごとにHTMLファイルを生成し、distディレクトリに吐き出します。
サーバー側では、そのdistディレクトリを参照し、HTMLファイルを探します。
あ、思い出しましたか?
このチュートリアルを最初からやっている方は勘付くと思いますが、前回Netlifyにこのセッティングをしましたね。
Nuxt.jsは動的なルーティングのレンダリングを無視する
記事ページだけレンダリングが出来ていない理由に戻ります。
上で、ルートごとにHTMLファイルを生成すると説明しましたが、この時にNuxt.jsは動的なルーティングを無視してレンダリングを行います。
動的なルーティングとは、デモブログの記事ページのような、パラメーターごとに表示を切り替えるページのことを言います。
このページは、すべて
理由はわかった。解決策を教えろ
Nuxt.jsがレンダリングを無視するなら自分でセッティングするしかありません。
具体的には、generate
コマンド実行時に「このルートのHTMLファイルを生成してね」という設定です。
nuxt.config.js
export default {
generate: {
routes: [
'/posts/1',
'/posts/2',
'/posts/3'
]
}
}
generateプロパティ内のroutes
に 動的なルーティングのパスを配列として渡してあげれば、HTMLファイルを生成してくれます。
ただこれ、毎回追加するの。。。😱
.
.
.
いいえ、大丈夫です。
伝えたかったことは「routes
にパスの配列を渡す」ということです。
ここまでのまとめ
作業の入る前に、ここまでの情報を整理します。
-
現状の問題点
記事ページをリロードすると「Page Not Found」のエラーがでる
-
何故か?
サーバー側にHTMLファイルが無いため
-
Nuxt.jsレンダリングの仕組み
generateコマンドが実行された時に、ルートごとにHTMLファイルを生成する
-
何故、記事ページはレンダリングされないのか?
Nuxt.jsは、動的なルーティングを無視してレンダリングを行うため
-
解決策
generateプロパティの
routes
に、動的ルーティングのパスを配列で渡す
以上が、ここまでの説明になります。
作業開始!! nuxt.config.jsにgenerateプロパティを追加する
それでは作業に移りましょう。
generate
プロパティを追加しします。
そしてcontentfulからblogPostを取得して、routers
にパスの配列を渡します。
nuxt.config.js
const client = require('./plugins/contentful').default // 追記
export default {
// 追記
generate: {
routes() {
return Promise.all([
client.getEntries({
content_type: process.env.CTF_BLOG_POST_TYPE_ID
})
]).then(([ posts ]) => {
return [
...posts.items.map(post => {
return { route: `posts/${post.fields.slug}`, payload: post }
})
]
})
}
}
}
-
payload
mapメソッドでルートの配列を作成する際に、postオブジェクトをpayloadに登録しています。
ここに登録することで、
/posts/_slug.vue からpayloadへとアクセスできます。結果、postを再取得する必要が無くなり、ルーティング生成の高速化を実現します。
(参考)/posts/_slug.vueでpayloadを取得する
async asyncData ({ payload }) {
if (payload) return { currentPost: payload }
}
正しく設定できたか確認してみよう
generate
プロパティは、本番環境で実行されるので"http://localhost:3000"で確認することができません。
そこで、yarn generate
コマンドを実行して、ターミナルでルーティングが生成されているか確認を行います。
$ yarn generate
...
ℹ Generating pages ✔ Generated /
✔ Generated posts/sample03
✔ Generated posts/sample04
✔ Generated posts/sample02
✔ Generated posts/sample01
✔ Generated posts/sample05
記事ページのパスが表示されたら成功です。
これで、サーバー側にもHTMLファイルが生成されました。
本番環境でも確認してみよう
ここまでの変更をpushします。
今回は新規作成したファイルが無いので、いつものgit add -A
せずに-am
コマンドで一気にコミットします。
$ git commit -am "add_generate_property"
$ git push
Netlityのデプロイログを確認する
Netlityにログインし「Deploys」メニューから最新のデプロイを確認してみましょう。
先ほどのターミナルと同じように表示されていれば成功です。
デプロイが完了したら、記事ページをリロードしてください。
今度はちゃんと表示されますね。
まとめ
今回は、Nuxt.jsにgenerate
プロパティを追加して、サーバー側に各記事ページのHTMLファイルを生成しました。
SNSで記事のURLを貼り付けても表示できるようになりますね。
これが、Nuxt.jsユニバーサルモードの強みでもある「サーバーサイドレンダリング」のメリットです。
さて、次回は?
今回、記事オブジェクトをpayloadに登録したので、contentfulからAPIを取得するロジックを大きく変更します。
middlewareの使い方も説明しますねー。
お楽しみに。