目次
はじめに
今回は SSG フレームワークを Astro、HeadlessCMS を Newt でブログサイトを実装してみた経験を記事にしてみることにしました。
どちらも比較的あたらしいモノで、調べてみても情報がそこまで多くなくて自分の中で苦戦することが多かったので、今後同じようなところでつまってしまった方のお役に立てれば嬉しいです!
内容としては、Astro での動的ルーティング、ページネーションあたりのお話が中心になるかと思います。
Astro での動的ルーティング
それでは、さっそく Astro での動的ルーティングの方法についてみてみましょう!
今回は例としてブログの記事ページみたいなイメージで pages
ディレクトリ直下に用意した記事ページで、動的ルーティングを行う想定で解説していきます。
実装の流れとしては以下のような感じになるかと思います。
- 1.動的にパラメーターを指定したいディレクトリやファイルを
[slug].astro
みたいな感じでブラケット記法を用いて用意しておく - 2.getStaticPaths 関数内で動的ルーティングの処理を行う
- 2-1.Newt から投稿データを取得してくる
- 2-2.Newt から取得してきたデータからファイル名に当てたい値を返す
- 2-3.
[slug].astro
に表示したいコンテンツを返す
それでは、具体的にみていきましょう!
1.動的にパラメーターを指定し…
これは特に説明する必要もなく、そのまま/pages/[slug].astro
という感じで pages
ディレクトリ直下に動的ルーティングさせたいページをブラケット記法で用意しておくだけです。
もちろん、ファイル名は必ず[slug].astro
にする必要はなくて自由にしていただいて問題ないです。
ただ、今回はわかりやすくするためにこのようにしています。
2.getStaticPaths 関数内で動的ルーティングの処理を行う
Next.js を使ったことがあれば、ある程度同じノリが通用するので直感的に理解できると思います。
具体的な実装方法は以下で解説していきます。
2-1.Newt から投稿データを取得してくる
今回は HeadlessCMS に Newt を使用しているので、Newt 側から [slug]
に使いたい値を渡してもらう必要があります。
なので、まずは Newt からデータを取得してくるところからやっていきましょう。
より詳細な内容は以前のブログでも解説しているので、今回は getStaticPaths 関数内での処理だけにとどめます。
export async function getStaticPaths() {
const postsData = await client.getContents({
appUid: 'appuid',
modelUid: 'modeluid',
})
}
こんな感じで Newt からデータを取得してきます。
ただ、postData のままではこんな感じのデータ構造になっているので
{
skip: 0,
limit: 100,
total: 5,
items: [
_id: '',
_sys: [Object],
// ここからはNewt管理画面で設定した内容
title: '',
slug: 'blog-post-1',
thumbnail: [],
date: '',
content: ""
]
}
実際にコンテンツの表示に関わる内容である items の内容が使いやすいように 変数postsContents
を用意しておきます。
export async function getStaticPaths() {
const postsData = await client.getContents({
appUid: 'appuid',
modelUid: 'modeluid',
})
const postsContents = postsData.items
}
2-2.Newt から取得してきたデータからファイル名に当てたい値を返す
それでは、ここからが本番ですね。
先ほど取得してきたデータからファイル名に当てたい値を返していきましょう。
export async function getStaticPaths() {
// Newtのデータを取得
const postsData = await client.getContents({
appUid: 'appuid',
modelUid: 'modeluid',
})
const postsContents = postsData.items
const pages = postsContents.map((postsContent) => {
return {
// [slug].astroに当てたい値を返す
params: {
slug: postsContent.slug,
},
}
})
return pages
}
上記のコードを見ると分かると思いますが、変数page
の中で先ほど取得してきたpostsContents
を展開していって、ブログとして投稿した内容から[slug]
に入る値が欲しいので、postsContent.slug
の値を返します。
今は map で処理されていますが、1 つずつ中身をみてみるとこんな感じになっています。
return [
// 生成対象: /blog-post-1
{ params: { slug: 'blog-post-1' } },
// 生成対象: /blog-post-2
{ params: { slug: 'blog-post-2' } },
// 生成対象: /blog-post-3
{ params: { slug: 'blog-post-3' } },
]
そして、最後にpages
を getStaticPaths 関数の中で返してあげれば動的ルーティングの完成です!
2-3.[slug].astro
に表示したいコンテンツを返す
動的ルーティングで値を返すだけであれば、上記のままで問題ないのですが、そのままでは[slug].astro
ページに表示するコンテンツがないということで、その辺りも簡単に解説していきます!
---
export async function getStaticPaths() {
const postsData = await client.getContents({
appUid: 'appuid',
modelUid: 'modeluid',
})
const postsContents = postsData.items
const pages = postsContents.map((postsContent) => {
return {
params: {
slug: postsContent.slug,
},
// 表示したいコンテンツはここで返す
props: {
postsContent,
},
}
})
return pages
}
// そして、ページ分割されたデータをpostsContentプロパティとして渡す
const { postsContent } = Astro.props
---
// こんな感じで使う
<h1>{postsContent.title}</h1>
ほとんど上記コード内にコメントとして残しましたが、表示したいコンテンツはparams
の方ではなくprops
の方に渡します。
そして、getStaticPaths 関数の外でAstro.props
オブジェクトで分割代入して利用します。
Astro でのページネーション
それでは、動的ルーティングが理解できたところでページネーションの方も見てみましょう!
Astro はコンテンツの豊富な Web サイトに特化しているということもあり、ページネーションもデフォルト用意されています。(さすが!)
しかし、ドキュメントを見る限りでは「前のページ」「次のページ」「現在のページ」程度しか作れないため、仕様によっては自分でこの辺りを調整して実装する必要がありそうです。
この辺りは後ほど解説していこうと思います。
まず、こちらも実装の流れから見てみましょう。
- 1.ページ番号を振りたいファイルを
[...page].astro
みたいな感じでブラケット記法を用いて用意しておく - 2.getStaticPaths 関数内で paginate 関数を使ってページを生成
- 2-1.Newt から投稿データを取得してくる
- 2-2.paginate 関数でページネーションの設定をする
- 2-3.前後送り以外のページネーションも
それでは、具体的にみていきましょう!
1.ページ番号を振りたいファイルを…
例えば、トップページにページネーションをつけたい場合には、/pages/[...page].astro
といった感じでファイルを作成しておきます。
[...page].astro
ではなく[page].astro
でもいいのですが、レストパラメータを使用することで深さに関係なく、すべてのファイルパスを受け取ることができます。
具体的にどういうことかというと、例えばページネーションを作って 1 ページ目 2 ページ目 3 ページ目の表示を作られると、[page].astro
の場合は/1
,/2
,/3
と問題なく作っていくことができますが、トップページの url/
は作成されません。
もし、(というかほとんどの場合トップページは)/1
じゃなくて/
にしたいという場合はレストパラメーターを使って[...page].astro
としておいた方がいいかなと思います。
2.getStaticPaths 関数内で paginate 関数を使ってページを生成
getStaticPaths を使うのは前章で解説した動的ルーティングと同様なのですが、ページネーションを作成するには paginate
という Astro で用意されている関数を使います。
具体的な方法は以下で解説していきます。
2-1.Newt から投稿データを取得してくる
まず動的ルーティングで解説した時と同様に、こちらでも Newt からデータを取得してくるところからはじめていきます。
export async function getStaticPaths() {
const postsData = await client.getContents({
appUid: 'appuid',
modelUid: 'modeluid',
})
const postsContents = postsData.items
}
同じです。
2-2.paginate()関数でページネーションの設定をする
ここからようやくページネーションの実装に入りますが、非常にシンプルです。
export async function getStaticPaths({ paginate }) {
const postsData = await client.getContents({
appUid: 'appuid',
modelUid: 'modeluid',
})
const postsContents = postsData.items
return paginate(postsContents, { pageSize: 10 })
}
getStaticPaths 関数の中でpaginate
関数を返しています。
中身を見てみると、表示したいコンテンツを第 1 引数に、ページ内に表示したいコンテンツの数を第 2 引数に設定しておきます。
簡単ですね!
そのあと、どうやって使っていくかというとこんな感じです。
---
const { page } = Astro.props
---
// 公式より
// 現在のページ
<h1>{page.currentPage}ページ</h1>
// コンテンツの表示
<ul>
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>
// ページネーション
{page.url.prev ? <a href={page.url.prev}>Previous</a> : null}
{page.url.next ? <a href={page.url.next}>Next</a> : null}
getStaticPaths 関数の外でAstro.props
オブジェクトで分割代入して利用します。
2-3.前後送り以外のページネーションも
最後におまけで、公式で用意されている前後送り以外のページネーションじゃ実務で使えないだろ!という方もいると思うので、個人的に作ったページネーションのロジックがあるので、よかったら使ってみてください。
ここでは Astro と Newt の話がメインなので、細かくページネーションのロジックについては触れませんが、使い方としてはPagination
コンポーネントに先ほど作成したpage
を渡してあげると、すべての数字が展開されて邪魔にならないように...が出て省略されるようにしております。
参考
- https://docs.astro.build/ja/core-concepts/routing/
- https://developers.newt.so/apis/cdn
- https://zenn.dev/chabatake_i/articles/astro-microcms
- https://github.com/komosyu4649/frocari
さいごに
今回は Astro と Newt での動的ルーティングとページネーションについて解説してみました。
やはり、Web サイトに特化しているフレームワークというだけあって Astro は割と直感的に実装することができますね。
はじめて触ってみた時も Next.js を経験していたらか、同じようなノリで実装することができたのですんなり進めることができました。
そんな感じで、比較的とっかかりやすいフレームワークだと思うので、気になった方はぜひ使ってみてください。