NuxtのSSGのgenerateの改善~payloadちゃんと使えてますか?~
Nuxt の generate の改善を職場ですることがあったので、そこで学んだことを備忘録的に書いてきます。
環境
nuxt v2.15.7
Qiita の API について
Qiita api を使って実際にやってみます。
(Zenn に記事書いてるのに Qiita で申し訳ないですが、サンプルにちょうどよかったので。)
Qiita の API のドキュメントはこちら
一覧の取得のドキュメントはこちら
特定の記事の取得のドキュメントはこちら
100 件の記事を取得するには以下のような感じす。
https://qiita.com/api/v2/items?page=1&per_page=100
題材
QiitaAPI で取得した記事のタイトルの一覧画面
QiitaAPI で取得した各詳細記事のタイトルのみの画面
というすごくシンプルなものです。
axios を使う
axios の install
$ yarn add axios
API のを叩くために axios を利用します。
Nuxt の通常バージョンで generate する
nuxt-link にあるものは自動でビルドしてくれるようです。
参考ドキュメント
まずは以下のようなソースでビルドしてみます。
<template>
<div>
一覧
<ul>
<li v-for="post in posts" :key="post.id">
<nuxt-link :to="`/post/${post.id}`">
{{post.title}}
</nuxt-link>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
async asyncData({app}) {
return await axios.get('https://qiita.com/api/v2/items?page=1&per_page=100',
{
headers: {
Authorization: `Bearer ${app.$config.token}`,
}
}
)
.then(response => {
return {
posts: response.data
}
})
},
}
</script>
<template>
<div>
{{post.title}}
</div>
</template>
<script>
import axios from 'axios';
export default {
async asyncData({app,params}){
return await axios.get(`https://qiita.com/api/v2/items/${params.id}`,
{
headers: {
Authorization: `Bearer ${app.$config.token}`,
}
}
).then(response=>{
return {
post: response.data
}
})
}
}
</script>
503 エラーになる
この状態でyarn generate
をすると、下記のように 503 エラーが出ます。
各記事ページの生成時にも API のリクエストがいきますし、リクエストの間を空けないためそうなっているのでしょう。
interval を使います。
interval プロパティのドキュメント
nuxt.config
に interval:100
を指定します。
export default {
//他のところは割愛
+ generate:{
+ interval: 100,
+ }
}
generate の結果です。
一応ソースコードはこちらにあげてます。
payload を使う
nuxt-link が貼られている path はnuxt.config
のgenerate
プロパティに記載してくても、ページ生成はされます。
参考
ただ、payload
を使うためには、generate
プロパティに記載する必要があります。
詳細記事のルーティングを作るために API にアクセスしたときに、
そこで 100 件分の記事のデータを取るなら、
そのデータを payload に入れて、
各記事のページでも payload
を使うことで API のアクセスを減らせます。
nuxt.config
に以下のようなコードを追記します。
+ import axios from 'axios';
export default {
generate:{
+ async routes(){
+ const posts = (await axios.get('https://qiita.com/api/v2/items?page=1&per_page=100',
+ {
+ headers: {
+ Authorization: `Bearer ${process.env.TOKEN}`,
+ }
+ })
+ ).data
+ const postRoutes = posts.map(post=>{
+ return{
+ route:`/post/${post.id}`,
+ payload:post
+ }
+ })
+ return [
+ {
+ route:"/post",
+ payload: posts
+ },
+ ...postRoutes
+ ]
+ }
}
}
<template>
<div>
一覧
<ul>
<li v-for="post in posts" :key="post.id">
<nuxt-link :to="`/post/${post.id}`">
{{post.title}}
</nuxt-link>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
async asyncData({ app, payload }) {
//payloadを使う
const posts = payload !== undefined ? payload
: (await axios.get('https://qiita.com/api/v2/items?page=1&per_page=100',
{
headers: {
Authorization: `Bearer ${app.$config.token}`,
}
}
)).data
return { posts }
}
}
</script>
<template>
<div>
{{post.title}}
</div>
</template>
<script>
import axios from 'axios';
export default {
async asyncData({app, params, payload}){
//payloadを使う
const post = payload !== undefined ? payload
: (await axios.get(`https://qiita.com/api/v2/items/${params.id}`,
{
headers: {
Authorization: `Bearer ${app.$config.token}`,
}
}
)).data
return {post}
}
}
</script>
今回の場合であれば、payload
によって API のアクセスは 1 度で済むようになったので、
interval
もセットする必要がなくなりました。
generate
にかかる時間も速くなりました。(22.02→12.27)
ここまでのソースはこちらです
payload は dev では undefined になる
yarn dev
では payload
はundefined
になるので、注意する必要があります。
payload 自体の動作確認はyarn generate
してから yarn start
する必要があります。
まとめ
Nuxt の SSG の generate 時には payload を上手く使うことで、不要な API のアクセスを減らすことができます。
もし、generate に時間かかっているなら、不要にデータを取得してないか見直してみるといいかもしれません。
Discussion