Setting up webmention with Cloudflare and AstroJS 2
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.
Credit
reply for the test
Sun, 01 Oct 2023replied!
Sun, 01 Oct 2023- Trying out this guide to sending webmentionsSat, 01 Jul 2023
@ahmadalbakri reply from fediverse
Sat, 21 Oct 2023@ahmadalbakri im a banana
Sat, 21 Oct 2023This is a list of everything I read while researching and implementing Webmentions in no particular order:
- IndieWebify.Me - a guide to getting you on the IndieWeb
- Using the Webmention.io API : Random Geekery
- An In-Depth Tutorial of Webmentions + Eleventy
- Adding webmentions to your static blog | Jan Monschke
- Using Webmentions in Eleventy | Max Böck
- Adding Webmentions to Your Site • Robb Knight
- Setting up webmention with Cloudflare and AstroJS - ahmad.build
- Integrating Webmentions with Next.JS • Deloughry.co.uk
- Getting Started With Webmention and NextJS
Further reading
- Displaying Webmentions on My Site | James’ Coffee Blog (there’s lots of other webmention posts here too)
- Adding reply context to my social pages | James’ Coffee Blog
- The fediverse and the indieweb
- IndieWeb - A Primer | Not Someobody Else’s Problem - Mine. IndieWeb - A Primer | Not Someobody Else’s Problem - Mine.
- Let’s talk about making IndieWeb weirder and easier
- Wars of Conflicting Webs
- You’re not wrong. The problem is the ActivityPub spec by itself doesn’t give you enough to implement a working system, and Mastodon filled in the rest with decisions they made on their own. So what actually exists is mostly a Mastodon-specific protocol built on the ActivityPub framework.
External services I’m using
- Bridgy - Most sites do not send webmentions, so Bridgy fills this gap by automatically scanning various social sites and then sending a webmention to your site.
- Webmention.io - My site is a static site, and I don’t want to host or implement a Webmention receiver myself. This external service is the webmention receiver. I can include some HTML that tells Bridgy to call that.
Displaying WebMentions
There’s a lot of ways the various types of webmentions can be displayed visually. However, there are specific semantic patterns via microformat classes that should be used. Many sites seem to skip this unfortunately. The indieweb wiki fortunately gives several examples where this is doing correctly.
The general format for all of these are as follows. Notice usage of
h-entry
,p-author
,h-cite
,u-comment
, etc.<div class="h-entry"> <h1 class="p-name">The Main Entry</h1> <p class="p-author h-card">John Smith</p> <p class="e-content">A few insights I've had:</p> <h2>Comments</h2> <div class="u-comment h-cite"> <a class="u-author h-card" href="http://jane.example.com/"> Jane Bloggs </a> <p class="p-content p-name">Ha ha ha great article John.</p> <a class="u-url" href="http://jane.example.com/c12"> <time class="dt-published">2015-07-12 HH:MM</time> </a> </div> <div class="u-comment h-cite"> <a class="u-author h-card" href="http://kim.example.net"> Kim Codes </a> <p class="p-content p-name">What were the insights?</p> <a class="u-url" href="http://kim.example.net/k23"> <time class="dt-published">2015-07-12 HH:MM</time> </a> </div></div>
Another example, this time of likes:
<li class="p-like h-cite"> <a href="https://instagram.com/p/4CPkIKDckd/#liked-by-341817" class="u-url"> <span class="p-author h-card"> <img class="u-photo" src="https://pkcdn.xyz/igcdn-photos-b-a.akamaihd.net/ae05b7dcc1946a0f6c26ff1d293e41122f532dff7d778152b30a4229ac1db68d.jpeg" data-src="https://pkcdn.xyz/igcdn-photos-b-a.akamaihd.net/ae05b7dcc1946a0f6c26ff1d293e41122f532dff7d778152b30a4229ac1db68d.jpeg" height="36"` /> </span> </a> <a style="display:none;" class="p-name u-url" href="http://instagram.com/strangeways"> Ankur </a></li>
Debugging and other stuff
- Webmentions are Great (Mostly) - As webmentions and the various implementations and tools being somewhat open ended and not consistent, some badly formatted webmentions can be sent (in this case from a poorly written Wordpress plugin, surprise…). Need to ensure this sort of sanity checking is applied; “empty” replies with an emoji should be handled.
The webmentions for this note look like this. Here is an early experiment with fetching and displaying webmentions in Astro:
Sun, 06 Oct 2024