sc
Scott avatar
ttwillsey

Astro RSS 1.2.0 Update

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

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

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…

Picture Element Sizes Attribute

Part of the Astro series

A couple days ago, I posted some responsive image and Astro Image science experiments. If you read that post, you’ll notice that my examples all assume I want to display my image at 200px wide. The reason is I was performing the experiments on a very specific layout that I use to show what beer we enjoyed on a given episode of Friends with Beer.1

But the sizes attribute of the HTML picture element is a lot more versatile than that. You can get very granular in how you control your image display sizes. I’ll show how to do it using the Astro Image component, specifically its Picture component.

When I wrote the my science experiments post, I had all the images in the article set to display at 400 or 500px width, depending on the image. I debated about the size of some of them being too small to see the details very well, but the images link to the large original, and some of them are quite a bit taller than they are wide and I didn’t want to make a page full of posters.

But more troublingly, setting them with a simple sizes="500px" value made them look bad on mobile devices. For example, here’s my first image in the article shown in the iPhone 12 Pro screen size, and it just shoots out both sides like there’s no guard rails and no cliffs next to the road.

500px wide image on iPhone 12 Pro screen

It’s a little confusing, because it’s an image of me examining images on a web page in Chrome developer tools, but you can see that it’s indeed displaying at my requested 500px width and is too wide for the page on the iPhone as a result.

500px wide image details in Chrome developer tools

Fortunately, sizes has an answer for us: we can specify it to be 500px above a certain screen width, and then just show at 90% of the viewport width below that screen width.

<Picture
src={image1}
widths={[500, 1000, 1500]}
sizes="(max-width: 550px) 90vw, 500px"
formats={["webp"]}
alt="600px wide image displayed at 200px width"
/>

It’s a little unclear how to read that initially. Here’s what it means:

  • For screens up to 550px wide, display the image at 90vw (90% viewport width).
  • For screens that don’t meet the specified condition (ie., they are wider than 550px), display the image at 500px wide.

It works great. Now for wide screens, I get a 500px wide image, and for smaller screens, I get an image better tailored to the display.

Image displaying at 500px wide on bigger screen

Image displaying at 90vw width on small screen

You can get even more granular. For example, I determined that an image I displayed in a different post at 600px wide on big displays worked better if it was only 80% of the viewport width between 650 and 750px screen widths, and 90% of the viewport width below that.

<Picture
src={beerlatest}
widths={[800, 1200, 1800]}
sizes="(max-width: 650px) 90vw, (max-width: 750px) 80vw, 600px"
formats={["webp"]}
alt="Latest episode beer list view"
/>

You may be thinking “Wow, that’s cool!” and also thinking “Wow, I can’t believe you’re going to type all that out every time you want to include a 600 pixel wide image in an article!”.

Yeah. I’m not.

There are a couple different ways to fix that. Both involve me using markdown syntax for my images but adding a display width to it, like this:

![images/image3-1C3FC4F9-AB6B-44DA-B33A-377336BD42B9.png width="500"](images/image3-1C3FC4F9-AB6B-44DA-B33A-377336BD42B9.png)

I’ll also throw in an alt tag value for good measure, of course.

Using that, I have a couple options:

  • I can write a script to run in Drafts, my markdown editor of choice which has excellent scripting support, that converts all my markdown images to Astro Image’s Picture component format with widths and sizes attributes nicely calculated and filled in automatically for me,
  • See if using some kind of rehype plugin in Astro at site build time would be a better way to do it so I don’t even have to actually click a script button in Drafts.

Either way, I absolutely do NOT plan on having to remember the science experiments I did to come up with my sizes attribute values for different image widths. That just goes against the whole point of trying to keep the writing process separate from the need to know about mundane site details, and for me it’s a step backwards.

The end result, regardless of which way I decide to go about it, is that I just have to know markdown image syntax (I do), and how wide I want it to display in the blog post and what I want the alt tag to be. I’ll let a script located somewhere figure out the implementation details for me.

Make computers work for you, not the other way around!

Footnotes

  1. Depending on when you read this, the Friends with Beer website may still be on Eleventy. The Astro version is WIP.