kanakanho / しばいぬ

About me

Works

Posts

Contact / Links

esaのマークダウンに任意のfrontmatterをつけてGitHubにコミットする

2024/11/2

はじめに

Astro を使ったポートフォリオサイトを自作する中で、esaで編集したマークダウンからwebサイトの記事を更新するような実装をしたので、備忘録を兼ねてまとめておきます

ちなみに今回実装したサイトはこちらです

また esa のマークダウンに任意の frontmatter をつけてGitHub にコミットする機能のみを実装したレポジトリはこちらです

https://github.com/kanakanho/esa-frontmatter-rewrite-push-github

esa からGitHub にコミットする

コミットする方法

esa から GitHub へのコミットは管理者権限さえあれば比較的に簡単にできます。

この方法については既に esa の方がまとめて下さっているのでそちらの記事を貼っておきます docs.esa.io help / GitHub Webhook (β)

簡単に説明すると https://{teamName}.esa.io/team/webhooks にアクセスして

下の Webhook を追加 から image.png (121.1 kB)

GitHub を選んで必要な項目を入力すると特定の esa Root Category に投稿された post の記事が GitHub へ共有されます image.png (194.2 kB)

自動的に追加される frontmatter

[!TIP] Frontmatter とは markdown ファイルの先頭について、ファイルについて追加の情報を記述するためのフォーマットです --- で区切られる場合 yml 形式が適応されます

esa には自分で編集したマークダウンに加えて下に示すような frontmatter が追加されます。

.md
title=".md"
title=".md"
title=".md"
---
title: post のタイトル
category: posts/yyyy/mm/dd
tags:
created_at: 'yyyy-mm-ddTtt:mm:ss+00:00'
updated_at: 'yyyy-mm-ddTtt:mm:ss+00:00'
published: true
number: 123
---

Astro でマークダウンの frontmatter を分析する

任意の frontmatter を追加したマークダウンを GitHub にコミットする Astro では frontmatter を解析して本文とは別の情報を取得するための方法があります。

getCollectionAstro.glob() を使ってマークダウンファイルを読み込むと frontmatterの情報がプログラムの中で扱えるようになります。

読み込む方法についても簡単なコードを置いておきます

getCollection を使う方法
src
├── content
│ ├── config.ts
│ └── post
│ ├── first.md
│ └── second.md
├── layouts
│ └── Layout.astro
└── pages
├── index.astro
└── posts
└── [number].astro
.ts
title="content/config.ts"
const post = defineCollection({
type: "content",
schema: z.object({
number: z.number(),
title: z.string(),
date: z.string(),
tags: z.array(z.string()),
image: z.string(),
})
pages/posts/[number].astro
---
import { getCollection, type CollectionEntry } from "astro:content";
type Frontmatter = {
number: string;
title: string;
date: string;
tags: string[];
image: string,
}
export async function getStaticPaths() {
const posts: CollectionEntry<"post">[] = await getCollection("post");
return posts.map((post) => ({
params: {
number: post.data.number
},
props: post,
}));
}
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const post: Props = Astro.props;
const frontmatter: Frontmatter = post.data;
---
<!-- HTMLを記述する -->
Astro.glob()を使う方法
src
├── content
│ └── post
│ ├── first.md
│ └── second.md
├── layouts
│ └── Layout.astro
└── pages
├── index.astro
└── posts
└── [number].astro
pages/posts/[number].astro
---
import type { MarkdownInstance } from "astro";
type Frontmatter = {
number: string;
title: string;
date: string;
tags: string[];
image: string,
}
export async function getStaticPaths() {
const posts: MarkdownInstance<Frontmatter>[] =
await Astro.glob<Frontmatter>("../../content/posts/*.md");
return posts
.map((post) => ({
params: {
number: post.frontmatter.number,
},
props: {
post: {
frontmatter: post.frontmatter,
Content: post.Content,
},
},
}));
}
const frontmatter = Astro.props.post.frontmatter;
---
<!--HTMLを記述する-->

これらを使うことで frontmatter から情報を得られて、frontmatter の情報を元にルーティングを分けたり、タグによるフィルターや日時によるソートが簡単に行えます。

しかしそれらを esa のデフォルトの frontmatter だけで行うのは少し難しいです。 そこで任意の frontmatter をつけた上でコミットする方法を検討しました。

esa の webhook を受け取る API を作る

esa の webhook を受け取るための API はなんでもいいのですが、デプロイの利便さとログの見やすさから CloudflareWorkers + Hono を採用しました。

Hono のエンドポイントを作成する

src/index.ts
import { Hono } from "hono";
import Webhook from "./webhook/Webhook";
const app = new Hono();
app.post("/api/webhook", async (c) => {
return await Webhook(c);
});
export default app;

esa の Generic webhook のデータ形式

Generic webhook では以下のドキュメントに従ってデータが送られてきます

https://docs.esa.io/posts/37

TSの型にするとこのようになる
export type PostCreate = {
kind: "post_create";
team: {
name: string;
};
post: {
name: string;
body_md: string;
body_html: string;
message: string;
wip: boolean;
number: number;
url: string;
};
user: {
icon: {
url: string;
thumb_s: {
url: string;
};
thumb_ms: {
url: string;
};
thumb_m: {
url: string;
};
thumb_l: {
url: string;
};
};
name: string;
screen_name: string;
};
};
export type PostUpdate = {
kind: "post_update";
team: {
name: string;
};
post: {
name: string;
body_md: string;
body_html: string;
message: string;
wip: boolean;
number: number;
url: string;
diff_url: string;
};
user: {
icon: {
url: string;
thumb_s: {
url: string;
};
thumb_ms: {
url: string;
};
thumb_m: {
url: string;
};
thumb_l: {
url: string;
};
};
name: string;
screen_name: string;
};
};
export type PostArchive = {
kind: "post_archive";
team: {
name: string;
};
post: {
name: string;
body_md: string;
body_html: string;
message: string;
wip: boolean;
number: number;
url: string;
};
user: {
icon: {
url: string;
thumb_s: {
url: string;
};
thumb_ms: {
url: string;
};
thumb_m: {
url: string;
};
thumb_l: {
url: string;
};
};
name: string;
screen_name: string;
};
};
export type PostDelete = {
kind: "post_delete";
team: {
name: string;
};
post: {
name: string;
wip: boolean;
number: number;
};
user: {
icon: {
url: string;
thumb_s: {
url: string;
};
thumb_ms: {
url: string;
};
thumb_m: {
url: string;
};
thumb_l: {
url: string;
};
};
name: string;
screen_name: string;
};
};

frontmatter を追加する

任意のfrontmatterを追加するためには esa の post の中に何らかの方法で内容を記述しなければなりません これにマークダウンで本文を記述する前にymlのコードブロックを用意してその中に frontmatter に追加したいいくつかの要素を入れることで対応しました

形式としては以下のようになります

\```yml title=".yml"
isActive: false
tags:
description:
repository:
youtube:
website:
image:
\```
<!--more-->

frontmatter を生成する

最終的に生成される frontmatter
isActive: true
number: 35
title: esa の post のタイトル
date: コミットした日付
options:
tags:
- esa の純正のタグとは関係のないタグ(markdown の中で記述したもの)
description: posts の説明(markdown の中で記述したもの)
repository: posts に関連するレポジトリ(markdown の中で記述したもの)
youtube: posts に関連する youtube (markdown の中で記述したもの)
website: posts に関連するウェブサイト(markdown の中で記述したもの)
image: posts に関連する画像(markdown の中で記述したもの)

上の4つは markdown に yml が記述されているかに関係なく生成が可能なので追加しています それ以外のものは option として yml に書いてあればそれを入れて、なければ null を入れるようにしています

処理はYaml のライブラリを使っています

GitHub へのコミット

Github へのコミットを行う方法については別の解説を書きましたので、そちらを参考にしてください

https://www.kanakanho.dev/posts/id/58

終わりに

esa は編集とマークダウンの管理が便利で大変重宝しています。これまでは esa の中だけでしか編集した文書を利用できなかったのですが、これでどんなところでも使えるようになったのでますます便利さが増えていくと思います。 これからもどんどん記事を書いていきたい!

参考にしたもの

https://queq1890.info/blog/octokit

Postsに戻る