Blog Setup
I’ve tried:
- Writing HTML & CSS from scratch: repetitive.
- Using Jekyll (for GitHub pages): Annoying to set up and manage - ran into rough edges with Ruby.
- Writing a homebrew blog that compiles Markdown: Nice for just markdown!
- Extending my homebrew blog with MDX plus server- and client-side components: frustrating to manage the complexity.
- Next.js with MDX: Took some effort to set up, static site generation broken out of the box, and broke when I tried upgrading (from 14 to 15). Their website even recommends against using it for a complex personal blog.
And finally, I’ve settled on:
- Astro: Decent initial blog set up, with MDX (!), easy to add Tailwind, and static site generation just works!
Issues & Fixes
A few random issues I’ve run into so far, and how I fixed them.
Font preloaded but not used within a few seconds
I’m including the Inter font locally (global.css):
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.ttf');
}
But I kept getting this error:
The resource http://localhost:8000/fonts/inter.ttf was preloaded
using link preload but not used within a few seconds from the window’s load event.
Please make sure it has an appropriate as
value and it is preloaded intentionally.
My issue is that I wasn’t specifying format("truetype")
:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.ttf') format("truetype");
}
Optimizing images
To use optimized images in your MDX posts, you have to move the images
somewhere into /src/
(I’m using /src/content/images/
), and then follow
the Astro guide to dynamically import them.
Note that in Markdown, they must be relative links, not absolute:
- Good:

- Bad:

Generating Favicons
I drew a square SVG in Inkscape. You can use an SVG for
your favicon (in <head>
) with:
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
But some browsers might still look for a .ico
, so I also created that with
ImageMagick & icoutils (nix-shell -p imagemagick icoutils
):
magick src/icons/my_icon.svg -resize 32 /tmp/favicon_32x32.png
magick src/icons/my_icon.svg -resize 64 /tmp/favicon_64x64.png
icotool -c -o public/favicon.ico /tmp/favicon_32x32.png /tmp/favicon_64x64.png
Ban generative AI scrapers
Or, at least, the ones with crawlers that respect robots.txt
.
Also, include your Astro sitemap. In pages/robots.txt.ts
:
import type { APIRoute } from "astro";
const disallowedAgents = [
// OpenAI training generative AI foundation models
// https://platform.openai.com/docs/bots
"GPTBot",
// FB training AI models
// https://developers.facebook.com/docs/sharing/webmasters/web-crawlers
"meta-externalagent",
// Google Gemini generative APIs
// https://developers.google.com/search/docs/crawling-indexing/google-common-crawlers
"Google-Extended",
];
export const GET: APIRoute = ({ site }) => {
// prettier-ignore
return new Response(
`User-agent: *
Allow: /
${disallowedAgents.map(a =>
`User-agent: ${a}
Disallow: /`).join('\n\n')}
Sitemap: ${new URL("sitemap-index.xml", site).href}`);
};
Example generation:
User-agent: *
Allow: /
User-agent: GPTBot
Disallow: /
User-agent: meta-externalagent
Disallow: /
User-agent: Google-Extended
Disallow: /
Sitemap: https://julian.guide/sitemap-index.xml