🚀
microCMSとAstroでお知らせ一覧作ってみた
概要
microCMSでお知らせ一覧を管理し、Astroで表示するところまでやっていく。
仕事で、microCMSとLaravelを使って、お知らせ一覧を返すAPIを作るような仕様で話が進んでいて、それってAstroで十分なのでは?と思ったので、検証してみる。
APIを作成
この画面を見るまで知らなかったが、都合よくお知らせ一覧用のテンプレートがあるらしいのでありがたく利用させてもらう。
APIの作成が終わったらこのような画面になった。
適当にお知らせがほしいので、Chat GPTにお願いしてみる。
これで記事の用意はできた。
Astroで表示する
microCMSの記事を参考にしつつ設定していく。
テンプレートからプロジェクトを作成する
❯❯ yarn create astro
tmpl How would you like to start your new project?
Use blog template
deps Install dependencies?
Yes
ts Do you plan to write TypeScript?
Yes
use How strict should TypeScript be?
Strict
git Initialize a new git repository?
Yes
❯❯ yarn astro add tailwind
microcms-js-sdk
をインストールする
yarn add microcms-js-sdk
.env.local
にmicroCMSのドメインとAPIキーを書く
VITE_MICROCMS_DOMAIN=xxxxx
VITE_MICROCMS_APIKEY=thisisapikey
Astroのテンプレートで作った場合は、 .env.local
が .gitignore に入ってないらしいため、追加しておく
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,8 @@ pnpm-debug.log*
# environment variables
.env
.env.production
+.env.local
+.env.*.local
データフェッチのロジックをコピペで作成
src/library/microcms.ts
//SDK利用準備
import { createClient, MicroCMSQueries } from "microcms-js-sdk";
const client = createClient({
serviceDomain: import.meta.env.VITE_MICROCMS_DOMAIN,
apiKey: import.meta.env.VITE_MICROCMS_APIKEY,
});
//型定義
export type News = {
id: string;
createdAt: string;
updatedAt: string;
publishedAt: string;
revisedAt: string;
title: string;
content: string;
};
export type NewsResponse = {
totalCount: number;
offset: number;
limit: number;
contents: News[];
};
//APIの呼び出し
export const getNews = async (queries?: MicroCMSQueries) => {
return await client.get<NewsResponse>({ endpoint: "news", queries });
};
export const getNewsDetail = async (
contentId: string,
queries?: MicroCMSQueries
) => {
return await client.getListDetail<News>({
endpoint: "news",
contentId,
queries,
});
};
お知らせリストを取得してみる
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 26f070d..1605c54 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -3,6 +3,9 @@ import BaseHead from '../components/BaseHead.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
+import { getNews } from '../library/microcms';
+
+const response = await getNews({fields: ['id', 'title']})
---
<!DOCTYPE html>
@@ -44,6 +47,16 @@ import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
>astro-blog-template
</a> by <a href="https://twitter.com/Charca">Maxi Ferreira</a>.
</p>
+ <section>
+ <h2>News</h2>
+ <ul>
+ {response.contents.map(content =>
+ <li>
+ <a href="http://">{content.title}</a>
+ </li>
+ )}
+ </ul>
+ </section>
</main>
<Footer />
</body>
この記事を参考にして、ニュース一覧ページを作成
src/pages/news/page/[page].astro
---
import BaseHead from '../../../components/BaseHead.astro';
import Header from '../../../components/Header.astro';
import Footer from '../../../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../../../consts';
import { getNews, News } from '../../../library/microcms';
import type { GetStaticPathsOptions } from 'astro';
export const getStaticPaths = async ({ paginate }: GetStaticPathsOptions) => {
const pageSize = 3 // 3記事ずつにページを分割
const response = await getNews({
fields: ['id', 'title'],
limit: 1000,
orders: '-publishedAt',
})
return paginate(response.contents, { pageSize });
};
const { page } = Astro.props;
export interface Props {
page: {
url: {
prev: string
next: string
}
currentPage: number
data: News[]
}
}
---
<!DOCTYPE html>
<html lang="en">
<head>
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
</head>
<body>
<Header title={SITE_TITLE} />
<main>
<h1>News</h1>
<ul class="p-8">
{page.data.map(content =>
<li>
<a href="http://">{content.title}</a>
</li>
)}
</ul>
<nav class="flex justify-between w-full">
<a class="p-2 border border-slate-400 rounded-sm" class:list={[{'pointer-events-none': !page.url.prev, 'opacity-30': !page.url.prev}]} href={page.url.prev}><</a>
<a class="p-2 border border-slate-400 rounded-sm" class:list={[{'pointer-events-none': !page.url.next, 'opacity-30': !page.url.next}]} href={page.url.next}>></a>
</nav>
</main>
<Footer />
</body>
</html>
このように3件ずつページを分けることができる。
次は、ニュースの個別ページ
src/pages/news/[id].astro
---
import BaseHead from '../../components/BaseHead.astro';
import Header from '../../components/Header.astro';
import Footer from '../../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../../consts';
import { getNewsList, getNewsDetail } from '../../library/microcms';
export const getStaticPaths = async () => {
const response = await getNewsList({ fields: ['id'], limit: 1000 });
return response.contents.map((content) => ({
params: {
id: content.id,
},
}));
};
// Astro.paramsから各ルーティングのidを取得
const { id } = Astro.params;
const news = await getNewsDetail(id as string);
---
<!DOCTYPE html>
<html lang="en">
<head>
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
</head>
<body>
<Header title={SITE_TITLE} />
<main>
<h1>{news.title}</h1>
<div set:html={news.content}></div>
</main>
<Footer />
</body>
</html>
--- a/src/pages/news/page/[page].astro
+++ b/src/pages/news/page/[page].astro
@@ -40,7 +40,7 @@ export interface Props {
<ul class="p-8">
{page.data.map(content =>
<li>
- <a href="http://">{content.title}</a>
+ <a href={`/news/${content.id}`}>{content.title}</a>
</li>
)}
</ul>
これで、個別ページもできました。
できあがったコードはこちら。
思ったよりmicroCMSもAstroも使いやすくて簡単でした。
お知らせ一覧を作る程度で、Laravelを構築するようなことにならずに済みそうです。
Discussion
続き。
GitHub Actionsの設定
baseURLを考慮しなくてはならない点に注意。
コンテンツ更新時に自動更新されるように設定
GitHubでパーソナルアクセストークンを作成
https://github.com/settings/personal-access-tokens/new
Create a repository dispatch event を読む限り、
metadata:read
とcontents:read&write
だけ権限があればよさそう。イベントタイプを追加
repository_dispatchにtypeを設定する必要があるらしいので追加。
https://github.com/KazukiMiyazato2021/astro-microcms/commit/a7ef899cfb13ab89bd2f8146e00557227b7fe819
microCMSでWebhookを追加
https://my-service.microcms.io/apis/news/settings/webhook
astro/imageの結果をキャッシュするように変更