Blogging frameworks are fun

Blogging frameworks are fun

Web Dev
Published August 16, 2022
Setting up a blog has been a bit of an experience for me.
This summer is sorta the first time I’ve put a significant amount of effort into personal projects. It’s been fun, and I’ve gone from making little web services to tease my friends to a fairly simple discord bot.
I also started to work on some personal websites - I got a simple alternative to Linktree using Hugo and Lynx, and I’ve been working on a personal website too.
But the biggest project I’ve been wanting thus far has been a blog.
I’ve tried to set one up before, using Jekyll and GitHub Pages. But I only ended up writing one blog post - a comparison of various compression tools.
You won’t find that blog post anywhere on here, by the way. At least not yet. I’ll redo it eventually. I had some methodological errors that I didn’t properly account for in it.
This isn’t about the methodological errors of my previous blog though. This is about the process of me getting to this setup.

Starting with something new

My first goal with setting up a blog was to have something that wouldn’t need to be on its own subdomain. I was wanting it to be on instead of
My personal site,, is made in Vue. You can probably tell that pretty easily, since I haven’t actually implemented much of a custom theme (yet, I swear I’ll get around to it).
A screenshot of
A screenshot of
My first idea for how to set up a blog was to use VuePress. It’s a fairly simple static site generator that, in my testing, works fairly well on Cloudflare Pages.
There’s two problems though.
First off, Cloudflare Pages doesn’t support “200 Redirects” - where instead of actually redirecting the user to a page, the server acts as a reverse proxy to another page.
Second, VuePress isn’t really optimized for blogs.
I’m making use of VuePress and VitePress on my documentation site, and both of them work quite well there. But I didn’t feel like they were really compatible with my own use case.
I also tried out Nuxt, but I sorta just got annoyed with one of the CLI’s dependencies and gave up.

Trying something familiar

A prototype blog using Jekyll
A prototype blog using Jekyll
My next idea was to just use Jekyll. It’s a nice static site generator, and I’ve used it in the past.
I stumbled upon a theme that I liked called Chirpy, which had most of what I was looking for in terms of visuals.
The issue I ran into here was that Jekyll didn’t work all that well with Cloudflare Pages.
A lot of this is probably able to be fixed somehow, but I wasn’t able to make the blog actually build on Cloudflare’s servers. So I had to manually build it locally, and them manually upload it to cloudflare.
The Jekyll blog in the Cloudflare Pages dashboard
The Jekyll blog in the Cloudflare Pages dashboard
This probably would’ve worked fine, but it wasn’t really ideal. I’d rather have it automatically build on pushes.
I could’ve also hosted it on GitHub Pages, but that comes with its own issues. GitHub Pages is primarily difficult for some of my sites because things like a _redirects file can’t be utilized to handle redirecting with HTTP. Instead, JS or HTML http-equiv redircets have to be used.

Trying something… else

Another prototype blog using Eleventy
Another prototype blog using Eleventy
Eleventy is another little framework I tried out, which looked like it might be what I was looking for.
I got introduced to an Eleventy version of the Chirpy Jekyll theme, which looked like it might be able to suit my needs.
It did have some minor CSS-related issues when I was adapting it to my own purposes (namely it expects a linkedin link, which I wasn’t interested in including), but after fixing them, it worked fine.
The main issue I ran into here was Tailwind CSS, which had a breaking change to deal with. I’ve never used Tailwind CSS before, so dealing with just that breaking change (which Dependabot reminds me about frequently) was going to be a nuisance.
It’s easily the smallest issue I’ve run into thus far though, and the page built without issue on Cloudflare.

Looking into CMS

So up until this point, all my blog attempts have just used markdown documents for content management. It’s a fine enough method to make pages, especially for a static site generator, but it’s also hard for me to say that I really like markdown (or at least, GitHub Flavored Markdown. I do like Pandoc.)
A cat friend of mine has been using another tool called Ghost for his blog. I’ve been curious about it for a while now, but if I’m being honest here, I didn’t even really know what a CMS was (Ghost didn’t really give me any hints to what it was, since its website mostly focuses on monetization and not content.)
Ghost’s website puts monetization front and center, but I just want to know what it is.
Ghost’s website puts monetization front and center, but I just want to know what it is.
Once I figured out what it was, Ghost did look like a compelling option to use eventually. Right now, I’m rather limited in what I can do because of one simple issue - I can’t feasibly host stuff on my internet. At school, I can get a stable internet connection that is perfectly sufficient for hosting my site (albeit with some jank involved in getitng it to work). But at home? 6Mbps uploads aren’t really ideal for a server.
With that idea shelved, I ended up putting this project on hold for a while. I did have something I wanted to write - an exploration of various jamstack hosting providers. But I had my focus elsewhere.

Stumbling upon Next.js

After this being on the backburner for a bit, I was taking a look at to see if I could find anything that I liked. It’s been the main place I’ve looked for site themes.
I’d passed over this theme before, as I tend to do for light themes. But this time it caught my attention.
Next.js Notion Starter Kit on
Next.js Notion Starter Kit on
I’d tried out Notion a little bit before when I was trying to set up my linktree alternative. But that was with Super, which didn’t really fit what I was looking for at the time. This was my first time actually trying it out.
Turns out, I like it.
The editor is pretty easy to work with, and it’s nice and straightforward to add posts.
And I happen to like the theme provided by this too - it’s nice and clean.
Theoretically, this is where this blog post would end. In pracice, I’ve still got some problems to deal with.

Vercel kinda sucks

So here’s the thing about Next.js.
It’s a very powerful framework capable of a lot of stuff. It works surprisingly well in a lot of regards.
But it can struggle with things like static site generation.
When I started testing things out, I was using Vercel since it was what the guide for the starter kit used. It worked fine - it deployed without issue and loaded without issue.
But I wanted to deploy it to Cloudflare Pages, which requires running next export on the project.
This did not work.
Initially, this was caused by image optimization not working when exported. Which is fine. I eventually figured out that the images.unoptimized option was an experimental option, after which addint it was pretty simple - adding this to the next.config.mjs worked fine.
export default bundleAnalyzer({ // ... experimental: { images: { unoptimized: true, }, }, })
But it failed for reasons beyond just that - a few routes like the RSS Feed, sitemap.xml, and robots.txt were handled server-side instead of them being statically generated.
A confused red panda after figuring this out
A confused red panda after figuring this out
I figured that because of that, it’d probably just be easier to deploy to Vercel and then point the domain to the Vercel deployment.
Unfortunately, you’ve read the title of this section. Working with Next.js was kinda weird. But working with Vercel was a mistake.
Vercel broke
Vercel broke
Here’s the thing - with a lot of stuff that uses lets encrypt, it’s easiest to just not proxy dns records when initially adding them so the cert generates correctly, and then to turn the proxy back on afterwards.
I already do that with Fastmail’s hosting, and it works perfectly fine.
One of my sites hosted on Fastmail, without issue
One of my sites hosted on Fastmail, without issue
But usually, when lets encrypt runs into issues with the Cloudflare Proxy… I’m expecting it to throw out the broken SSL Certificates.
Vercel does not do this. It still lists the broken, unusable SSL Certificates under my account.
Vercel doesn’t allow you to delete system certificates
Vercel doesn’t allow you to delete system certificates
Vercel also won’t let me delete the certificate.
As it stands, when deployed to this domain, Vercel redirects all HTTPS requests to HTTP for… some reason, and Cloudflare redirects all HTTP requests to HTTPS.

Removing Vercel from this site

The first things we can deal with are the robots.txt and the sitemap.
The robots.txt could just be added as a static file in the public folder, but the sitemap has to be updated at build time.
Thankfully, we can the sitemap and the robots.txt can be handled at the same time using next-sitemap. I’m using the following next-sitemap.config.mjs:
/** @type {import('next-sitemap').IConfig} */ const config = { siteUrl: '', generateRobotsTxt: true, robotsTxtOptions: { policies: [ { userAgent: '*', allow: '/', disallow: ['/api/get-tweet-ast/*', '/api/search-notion'], }, ], }, } export default config
After that, I added a step to run next-sitemap -config next-sitemap.config.mjs after running next build.
next-sitemap generates files in the public folder, after which they get included in the output of next export.
I also had to add the output of next-sitemap to my .gitignore
/public/sitemap.xml /public/sitemap-*.xml /public/robots.txt
Generating an RSS feed is a more complicated process that I won’t go into here. I used this tutorial to figure out how to implement it.
Unfortunately, it’s not possible migrate everything over to Cloudflare Pages thanks to the limitations of pages functions.
Ideally, site search would just be implemented using a pages function, but that doesn’t really work because the notion-client is meant for node. As a workaround for that, I set up a little page funciton as a reverse proxy to vercel, and another vercel page project to contain random APIs that it’s easier to host on there.
Social cards are a bit weirder in their generation - the starter kit uses a headless instance of Google Chrome to make some fairly nice looking cards, but it also seems to take a few seconds to generate the image, and it’s not really something I can run in the v8 engine.
My implementation just uses a page function, Cloudflare R2, and some images I made in Figma.
export const onRequestGet: PagesFunction = async ( ctx: EventContext>, ) => { const { request, env } = ctx const url = new URL(request.url) const { searchParams } = url const id = searchParams.get('id') const page = id.replace(/-/g, '') const r2ob = await env.SOCIAL_CARDS.get(`${page}.webp`) const image = r2ob.body if (image) { return new Response(image, { headers: { 'Content-Type': 'image/webp', 'Cache-Control': 'public, s-maxage=31536000, max-age=31536000', }, }) } return new Response('Not found', { status: 404, headers: { 'Cache-Control': 'public, s-maxage=3600, max-age=3600', }, }) }

And with that, the site is working correctly.