sc
Scott avatar
ttwillsey

More on Astro, Image Optimization, and Markdown

Astro

Part of the Astro series

I’ve talked a lot about image optimization and RSS feed handling with Astro. I’m about to talk about it some more. I presume you’re like me and obsess endlessly about these topics, so you should enjoy this.1 In my case, I don’t know how much of it is enjoyment and how much of it is a compulsive search for a better way.

Now that Astro has support for full post content RSS feeds with the compiledContent property for markdown content, I modified Friends with Brews to use standard markdown files (.md) instead of MDX (.mdx). My reasoning was that, since I almost never include images in the show notes for Friends with Brews and since using standard markdown would let me use compiledContent to put full episode show notes in the podcast RSS feed, it was an automatic must-do.

Unfortunately for me, the second I made the switch, I needed to add an image to the show notes of an upcoming episode, which would make it the second time I’ve had to add an image to FwB show notes. The first time was back on episode 8, Satan is not normally depicted as being purple, and that was the critical piece of visual information known as the Chonk Chart.

If I have to do anything more than once, it means I will have to do it several times, and that means I have to support it properly. And that means being able to combine image optimization AND standard markdown in Astro, and that’s not currently possible - the Astro Image components are only supported in Astro and MDX files, for the obvious reason that they’re components, and markdown can’t execute components.

I can continue to process the usual images of episode brews (coffee, beer, tea) with Astro image in my layout templates, as well as all the other images used on the site, so that’s not a problem. Those brew images are not actually in the show notes. Instead, I have a JSON file of brews that contains a bunch of information about them, including which episode(s) they’re associated with. So I only have to concern myself with how to optimize the inline images in the show notes markdown files.

The good news is that manually writing Picture elements complete with sources and srcsets and default images is simple. And if it’s simple for a human, it’s simple for a script. I can easily assume a certain standard width for images I’m going to put in my show notes, and then generate optimized images for that size plus 2x and 3x resolutions, as well as the original for linking to. Then the html for the Picture element associated with the optimized images can be generated fairly simply. Ben Holmes, who now works for Astro, has a post about this approach using eleventy-image. Because eleventy-image can be manipulated directly in JavaScript, it’s a great candidate for this.

So here’s the plan:

  • Continue to optimize permanent site images and episode brew images using the Astro Image components in my Astro layout files,
  • Use eleventy-image to optimize inline show notes images to predetermined widths and image formats,
  • Figure out how to insert the associated Picture elements for the optimized images into my markdown files. This step might take the most work.

If you noticed that the last step of the plan looks a bit like the Far Side cartoon with scientists drawing out a diagram of the creation of the universe with a “and then a miracle occurs” note tagged onto the end, it’s true. The good news is, there are several places in my writing and publishing workflow I can inject the html. I’ll write more about that as I start implementing a system.

Footnotes

  1. If you aren’t endlessly obsessed with these topics, we need to talk about that.

Astro RSS 1.2.0 Update

Astro

Part of the Astro series

Earlier today I posted about the new compiledContent() property for use in Astro RSS. What I didn’t mention was that Astro RSS 1.1.0 had a bug in its XML parsing that ignored custom content (which in my case I am using for audio enclosures) and also choked on my link constructors for my post and audio file links.

Today Astro RSS 1.2.0 was released with a fix for this, thanks to a pull request from Matt Stein, so now my RSS layout for Siracusa Says looks like this:

src/pages/rss.xml.js
import rss from "@astrojs/rss";
import config from "config";
import path from "path";
import sanitizeHtml from "sanitize-html";
import { rfc2822 } from "../components/utilities/DateFormat";
const episodeImportResult = import.meta.globEager("../content/episodes/*.md");
let episodes = Object.values(episodeImportResult);
episodes = episodes.sort(
(a, b) =>
new Date(b.frontmatter.pubDate).valueOf() -
new Date(a.frontmatter.pubDate).valueOf(),
);
export const get = () =>
rss({
title: config.get("title"),
description: config.get("description"),
site: config.get("url"),
items: Array.from(episodes).map((episode) => ({
title: episode.frontmatter.title,
link: `${new URL(
path.join(config.get("episodes.path"), episode.frontmatter.slug),
config.get("url"),
)}`,
pubDate: rfc2822(episode.frontmatter.pubDate),
description: episode.frontmatter.description,
customData: `<enclosure url="${new URL(
path.join(
config.get("episodes.audioPrefix"),
episode.frontmatter.audiofile,
),
config.get("url"),
)}" length="${episode.frontmatter.bytes}" type="audio/mpeg" />`,
content: sanitizeHtml(episode.compiledContent()),
})),
});

I noticed today that on my enclosure links I wasn’t providing the domain in the enclosure link url, just the path. This fixes that and also makes sure that my post links (which are also used by Astro RSS for item entry GUIDs) are always correct. I hadn’t had any problems with them, but this is a safer way of making sure I don’t ever get any extra slashes or other malformed URL issues.

Astro RSS Compiled Content

Astro

Part of the Astro series

It’s been awhile and I have lots of news, but just a short one today: Astro now supports full RSS feed content if you use md files for your content. It works like this:

src/pages/rss.xml.js
export const get = () =>
rss({
title: config.get("title"),
description: config.get("description"),
site: config.get("url"),
items: Array.from(episodes).map((episode) => ({
title: episode.frontmatter.title,
link: `${config.get("url")}${config.get("episodes.path")}${
episode.frontmatter.slug
}`,
pubDate: rfc2822(episode.frontmatter.pubDate),
description: episode.frontmatter.description,
customData: `<enclosure url="${config.get("episodes.audioPrefix")}/${
episode.frontmatter.audiofile
}" length="${episode.frontmatter.bytes}" type="audio/mpeg" />`,
content: sanitizeHtml(episode.compiledContent()),
})),
});

See the last line of code?

content: sanitizeHtml(episode.compiledContent());

That’s directly telling Astro RSS that for a given item, the content is equal to the post’s compiledContent property (and run through sanitize-html for good measure).

You can find the Astro docs for it here: Including Full Post Content

There is one caveat I need to mention that directly affects this site. If you use mdx instead of md for your posts like I do here, compiledContent() doesn’t work. Since I don’t like my current RSS feed generation tweak for this site in order to get full content RSS items, my plan is to work on converting back to md and figuring out a way to process images such that I get the benefit of Astro Image’s Picture and Image components while using standard markdown files.

The Mastodon Webfinger Domain Search Super Trick

I promised an article about whether or not Mastodon and the Fediverse were going to solve all our problems and make us happy humans with a long species survival probability, but work and other tech projects have intervened. More on that later.

In the meantime, if you ARE on Mastodon and don’t want to run your own instance but would like people to be able to search for you there using your own domain name instead of the domain name of the instance you’re on, Maarten Balliauw has a really cool trick for this:

In other words, if you want to be discovered on Mastodon using your own domain, you can do so by copying the contents of https://<your mastodon server>/.well-known/webfinger?resource=acct:<your account>@<your mastodon server> to https://<your domain>/.well-known/webfinger.

You can read Maarten’s post on the webfinger method on his blog.

Title Case

Astro

Part of the Astro series

A good system should never make you remember its implementation details in order to use. That extends to blogging platforms. Since my blogging platform is a self-created, self-hosted website built on Astro, the onus of making myself not have to remember how it works just to use it rests solely on me.

Today I started writing a post about Mastodon and the Fediverse and why it’s not the solution to all your problems that you might think it is, and I realized I couldn’t remember if I write my blog post titles in Title Case or Just the first word capitalized or in camelCase.1 It’s not the first time I’ve had to ask myself this question, and that means it’s a problem I don’t want to think about anymore. So here’s a very simple Title Case generator:

export function titleCase(str) {
return str.replace(/\b[A-Za-z]/g, (x) => x.toUpperCase());
}

Running the first paragraph of this blog post through it results in this:

A Good System Should Never Make You Remember Its Implementation Details In Order To Use. That Extends To Blogging Platforms. Since My Blogging Platform Is A Self-Created, Self-Hosted Website Built On Astro, The Onus Of Making Myself Not Have To Remember How It Works Just To Use It Rests Solely On Me.

So now my blog post titles are generated like this:

<h1>
<a
href={new URL(
path.join(config.get("posts.path"), content.frontmatter.slug),
config.get("url"),
)}
>{titleCase(content.frontmatter.title)}
</a>
</h1>

Speaking of camelCase, I also took the opportunity to add a camelCase function that outputs what we called camelCase when I was a juvenile programmer-wannabe.

export function camelize(str) {
return str
.toLowerCase()
.replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase());
}

I’ll be back next time with some reasons why Mastodon and the Fediverse aren’t suitable for most people in their current incarnations.2

Footnotes

  1. You modern whippersnappers probably think ThisIsCamelCase, but when I was a boy, thisWasCamelCase. So put that in your programming pipe and smoke it.

  2. Hint: it’s not a technical problem, it’s a people problem.

Friends With Brews

Peter and I decided a little while ago to convert the Friends with Beers podcast to Friends with Brews podcast. Our reasoning is pretty simple: we don’t always want to drink beer quite as often as we want to talk, and we both like coffee and tea.

But Clay Daly pointed out another huge benefit: the podcast is more inclusive as Friends with Brews, because some people won’t care about beer, but they might be interested in coffee or tea. And coffee and tea, you may be shocked to learn, are brewed. They qualify as brews. So there will be times on the podcast that we’re both drinking beer, or we’re both drinking coffee, or one of us is drinking beer and tea, or just tea, or just coffee, or… The permutations aren’t endless, but they may as well be for all the effort I’m going to exert in calculating them.1

Anyway, I think that the change will be seamless if you subscribed through Apple Podcasts or Overcast. If you subscribed directly to our RSS feed, then please delete it and resubscribe to the Friends with Brews RSS feed.

By the way, the Friends with Brews website is an upgrade. It features a fully indexed search capability, accessible both from the home page and from the brews page, which will return matches for the site in general and for the different drinks more specifically. I think it also looks a lot nicer than the previous incarnation of the site, but I am biased since I’m the one who built it.

Footnotes

  1. Hint: zero effort

Friends With Beer 2.0

I think I mentioned in my Responsive Image Rabbit Hole Series that I have been building an Astro version of the Friends with Beer website, and it’s finally live!

Friends with Beer now features a nicer look, redesigned beer detail pages, and a fully indexed search capability that returns results for episodes AND for beer! That means you can search for a beer we talked about in an episode and find it immediately. The search UI shows up on the home page and on the beer cooler page.

I still need to tweak the custom 404 by updating it for the new build, so it is basically an un-styled page at this point.

Having finished this, my work isn’t even done yet, because now I need to tweak the site to meet our new goal of being Friends with Brews! That’s right, we want the flexibility to drink not just beer, but coffee and tea instead. Those are brewed, beer is brewed, and it means less beer drinking for times a beer really doesn’t sound right.

More on that soon, hopefully…