Setting up webmention with Cloudflare and AstroJS
Posted on Tue, 08 Aug 2023 , edited on Fri, 24 Nov 2023 #webmention #astro #cloudflare #github #POSSE #snippetThis is part of effort to own my content. Rather than posting the content elsewhere, post it on my platform instead (this blog).
Basic Idea
- get our data from webmentions.io, and store within
src/content/webmentions
folder, - create new Astro collection called webmentions,
- consume the data - get the collection from step 2 and call wherever,
- push to GitHub,
- link Cloudflare with GitHub
1. Get data from webmentions.io
I’m using script from Jan Monschke with a bit of modification. This script will be executed by GitHub action and auto commit to specified folder (in this case, src/content/webmentions
folder).
import * as https from "https";
import * as fs from "fs";
import { getSlugFromPathName, getFileName } from "../utils/common.js";
const { WEBMENTIONS_IO_TOKEN } = process.env;
const { HOSTNAME } = "ahmad.build";
async function fetchMentions() {
const url = `https://webmention.io/api/mentions.jf2?domain=${HOSTNAME}&token=${WEBMENTIONS_IO_TOKEN}&per-page=999`;
return new Promise((resolve, reject) => {
// create Promise here
}).then((response) => {
return response.children;
});
}
fetchMentions().then((webmentions) => {
console.log(`Fetched ${webmentions.length} webmentions`);
webmentions.forEach((webmention) => {
// check if mention exist on disk. If exist, fetch new and overwrite. Else, create new mention.
// write the mention to disk
});
});
WEBMENTIONS_IO_TOKEN
value need to be set on GitHub environment.
2. Create new Astro collection
To create new collection, we need to edit src/content/config.ts
. Remember, Astro allow user to have multiple collections, e.g. notes, webmentions, activity etc. Case below, I’m creating new collection called webmentions
.
const webmentionsSchema = z.object({
url: z.string(),
published: z.coerce.date(),
"wm-property": z.string(),
"wm-received": z.coerce.date(),
content: z
.object({
text: z.string().optional(),
html: z.string().optional(),
})
.optional(),
author: z.object({
type: z.string(),
name: z.string(),
photo: z.string(),
url: z.string(),
}),
});
const webmentions = defineCollection({
type: "data",
schema: z.array(webmentionsSchema),
});
3. Consume the webmention data
Now that the collection is ready, we can customize it to our liking. In my case, I’m getting like
and reply
. For that, create 2 component : WebmentionList.astro
and WebmentionLike.astro
WebmentionList.astro
---
const { wm } = Astro.props;
let likeCount: any = [];
wm.map((wm: any) => {
if (wm["wm-property"] === "like-of") {
likeCount.push(wm);
}
});
const hasLike = wm.some(function (wm: any) {
return wm["wm-property"] === "like-of";
});
---
{
wm.length > 0 && (
<div class="webmentions">
<div class="wm-header">
<h3 id="webmentions">Webmentions</h3>
{hasLike && (
<div class="wm-like">
<ul>
{wm.map(
(wm: any) =>
wm["wm-property"] == "like-of" && <WebmentionLike {wm} />
)}
</ul>
<WebmentionLikeCount {wm} />
</div>
)}
</div>
<ul class="wm-list">
{wm.map((wm: any) => (
<WebmentionCard {wm} />
))}
</ul>
</div>
)
}
WebmentionLike.astro
---
const { wm } = Astro.props;
const { photo, name, url } = wm.author;
---
{
(
<li>
<a href={url}>
<img class="avatar" width="32" height="32" src={photo} title={name} />
</a>
</li>
)
}
4. Push to GitHub
Second last step is to push the code to GitHub. Don’t forget to set WEBMENTIONS_IO_TOKEN
on GitHub environment.
5. Linked Cloudflare with GitHub
Last step is to create new site on Cloudflare and link the site with GitHub repository on previous step.