Jamstack構成で作ったサイトのバナーをmicroCMSで管理してみた
はじめに
メンバーズルーツカンパニーの岸本です。
メンバーズルーツカンパニーのHPはAstro + microCMSを利用したJamstack構成になっています。Jamstackについては「非エンジニアにもわかるJamstack - ヘッドレスCMS導入時によく採用されるJamstackとは?」で詳しく解説しているので、ぜひご覧ください。
HPの右下にバナーを表示しているのですが、バナーのデータはmicroCMSと連携しておらず、ソースコードの中にハードコーディングされています。
せっかくmicroCMSを使っているので、バナーもmicroCMS管理にしました。
現在の構成
現在、HPの構成は以下のようになっています。
- SSGフレームワーク:Astro
- ヘッドレスCMS:microCMS
- ソース管理:AWS CodeCommit
- ホスティング環境:AWS Amplify
- 本番
- ステージング
今回は、microCMSでのバナー作成から、AstroでSSG処理の作成を行い、microCMSにAWS AmplifyのWebhook設定を行うところまでの流れを紹介します。
実装手順
実装手順は以下のようになります。
- バナーの仕様を考える
- microCMSにバナー管理用のコンテンツAPIの作成
- AstroとmicroCMSを連携してバナーを表示する処理の作成
- Webhookの設定
バナーの仕様を考える
バナーの仕様は以下のようにしました。
- microCMSで複数のバナーを投稿可能
- 投稿されているバナーのうち、公開中のものをランダムに1つ表示
- microCMSには以下の入力欄がある
- 画像(入力必須)
- 画像のalt属性(任意入力)
- クリック時の遷移先URL(入力必須)
- クリック時に新しいタブで開くかどうか
- デフォルトで新しいタブで開く
microCMSにバナー管理用のコンテンツAPIを作成
microCMS上でバナー管理用のコンテンツAPIを新しく作成します。
名前はバナーでエンドポイントはbannerにしました。
スキーマは以下のように作成しました。
画像とURLとalt属性を入力できる形にし、クリックした時に新しいタブで開くか現在のタブで開くか選択できるボタンを用意しています。
is_externalの詳細設定から初期値が設定できるので、初期値をtrueにしてデフォルトで新しいタブで開くようにしました。
出来上がった入力画面はこのような感じです。
AstroとmicroCMSを連携してバナーを表示する処理の作成
microCMSにAPIを作成することができたので、Astroにバナー表示の処理を作成していきます。
バナー表示部分を管理しているコンポーネントを編集します。現状は以下のようにコードの中に直接コンテンツが記載されています。
// src/components/Banner.astro
---
import closeIcon from '@/assets/icons/popup-close.png'
import bannerImage from '@/assets/banner.png'
---
<div id="popup">
<div id="close-button">
<img src={closeIcon.src} alt="閉じるボタン" />
</div>
<div>
<a href={'https://marke.members.co.jp/membersroots_paper11.html'}>
<img
src={bannerImage.src}
alt="第一地銀62行・メガバンクデジタル広告出稿比較レポート(2023年6月実施 独自WEBサイト調査より)"
/>
</a>
</div>
</div>
バナーの型を作成
今回のHPの環境ではmicrocms.tsにmicroCMS関連の型や関数を記載しているので、新しくバナーの型をmicrocms.tsに記載します。
// src/libs/microcms.ts
// バナーの型
export type BannerType = {
image: MicroCMSImage
alt?: string
link: string
isExternal: boolean
}
バナー取得処理の作成
microCMSのデータ一覧を取得する関数はすでに作成しており、他のページで使用しているものがあるので利用します。
// src/libs/microcms.ts
// コンテンツ全件取得
export const getAllContentList = async <T>(
apiName: string,
queries: MicroCMSQueries = {}
) => {
const contents = await client.getAllContents<T>({
endpoint: apiName,
queries
})
return contents
}
microCMS JavaScript SDKのgetAllContentsを利用しています。
この関数を使用しmicroCMSからバナーを取得する処理をAstroに記載したものが以下になります。
// src/components/Banner.astro
---
import closeIcon from '@/assets/icons/popup-close.png'
import { getAllContentList, type BannerType } from '@/libs/microcms'
// バナー取得処理
const banners = await getAllContentList<BannerType>('banner')
// バナーが0件の時は描画しない
if (banners.length === 0) {
return;
}
---
<div id="popup">
<div id="close-button">
<img src={closeIcon.src} alt="閉じるボタン" />
</div>
<div>
{
banners.map((banner) => {
return (
<a href={banner.link} target={banner.isExternal ? '_blank' : undefined}>
<img src={banner.image.url} alt={banner.alt} />
</a>
)
})
}
</div>
</div>
Astroではビルド時の処理を---(ハイフン3つ)で囲まれた中に記載する必要があるため、そこでmicroCMSからデータを受け取る処理を記載しました。microCMSから受け取ったデータをmapで回して設置しています。
試しにバナーをmicroCMSに登録して、devサーバーを起動(npm run dev)して表示を確認してます。
バナーのデータをmicroCMSから取得して表示することができました。
しかし、バナーが1つの時は問題なさそうですが、2つ以上ある時に全て表示されてしまっているので、ランダムで1つ表示するようにします。
バナーランダム表示処理の作成
バナーを表示部分のaタグをdivで囲い、bannerクラスをつけます。
<div class="banner">
<a href={banner.link} target={banner.isExternal ? '_blank' : undefined}>
<img src={banner.image.url} alt={banner.alt} />
</a>
</div>
bannerクラスにはdisplay: none;のスタイルを付与し、最初は全て非表示状態にします。
<style>
.banner {
display: none;
}
</style>
JavaScriptでページにアクセスするたびにランダムで1つだけdisplay: block;を付与します。
<script>
const banners = document.querySelectorAll<HTMLDivElement>('.banner')
// バナーが0件じゃない時に処理
if (banners.length !== 0) {
// 0からバナーの数までのランダムな数値を取得
const bannerNum = Math.floor(Math.random() * banners.length)
// ランダムに1つだけ表示
banners[bannerNum].style.display = 'block'
}
</script>
ソースコード全体はこのような形になります。
// src/components/Banner.astro
---
import closeIcon from '@/assets/icons/popup-close.png'
import { getAllContentList, type BannerType } from '@/libs/microcms'
// バナー取得処理
const banners = await getAllContentList<BannerType>('banner')
// バナーが0件の時は描画しない
if (banners.length === 0) {
return;
}
---
<div id="popup">
<div id="close-button">
<img src={closeIcon.src} alt="閉じるボタン" />
</div>
<div>
{
banners.map((banner) => {
return (
<div class="banner">
<a href={banner.link} target={banner.isExternal ? '_blank'
: undefined}>
<img src={banner.image.url} alt={banner.alt} />
</a>
</div>
)
})
}
</div>
</div>
<style>
.banner {
display: none;
}
/* 〜その他のスタイル〜 */
</style>
<script>
const banners = document.querySelectorAll<HTMLDivElement>('.banner')
// バナーが0件じゃない時に処理
if (banners.length !== 0) {
// 0からバナーの数までのランダムな数値を取得
const bannerNum = Math.floor(Math.random() * banners.length)
// ランダムに1つだけ表示
banners[bannerNum].style.display = 'block'
}
// 〜その他のJS処理〜
</script>
Astroでは1つのファイルの中でビルド時の処理、HTML、CSS、JavaScriptを記載できるので、それぞれCSSはstyleタグで囲い、JavaScriptはscriptタグで囲って設置しています。
バナーを2つ登録して確認してみます。
無事アクセスするごとにランダムで表示するバナーの処理を作成できました。
メンバーズルーツカンパニーHPの開発環境では、AWS CodeCommitにpushすると自動でビルドされてAWS Amplifyにて公開される環境が構築されているため、pushして完了です。
Webhookの設定
最後にバナーを追加、削除した際に自動でビルドをしてもらうためにmicroCMSにWebhookを設定します。
HPをAWS Amplifyでホスティングしているため、microCMSでバナーを更新するたびにAWS AmplifyのWebhookに通知を送ってもらいます。
AWS Amplifyのビルド設定から本番環境(main)とステージング環境(staging)のWebhookをそれぞれコピーします。
microCMSに移動し、作成したバナーのAPI設定からWebook設定で設定します。
追加ボタンからAWS Amplifyを選択します。
先ほどコピーしたURLを貼り付けて、本番環境(main)の通知タイミングの設定を行います。
設定した通知タイミングでAWS Amplifyに通知が行き、自動でビルドを行ってくれるようになります。
今回は以下のように設定しました。
下書き周りやコンテンツの並び替えなどはオフにしています。
同じものをステージング(staging)用でもう1つWebhook設定を作成したら完了です。
おわりに
メンバーズルーツカンパニーHPのバナーをmicroCMS管理にしたので、その手順を紹介してみました。
今回紹介したコードでは、バナーを表示しているページのビルドごとにmicroCMSのAPIにアクセスする処理になっているので、少しビルドに時間がかかってしまいます。実際に開発した際は、一度取得したバナーのデータを使い回すようなキャッシュ処理を作成し、ビルド時間がより短くなるようにしました。
キャッシュ処理を用いたビルド時間短縮方法については、「microCMS + AstroのJamstack構成でキャッシュを活用し、ビルド時間を90%以上短縮した方法」で紹介しているので、ぜひご覧ください。
この記事がmicroCMS + Astro開発の参考になれば幸いです。