From feabedd2e91bafc10642e5cb5722c1baccdbced9 Mon Sep 17 00:00:00 2001 From: sec-ml <150138296+sec-ml@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:58:08 +0100 Subject: [PATCH 1/3] test SSG `meta http-equiv="refresh"` redirects Not sure if this is a good solution. For hosting a static site somewhere like GitHub pages, you don't have access to configure the web server. If migrating content from one blog/URL pattern to another, the only option is to create a small html page at each original URL, with a `meta http-equiv="refresh"` directive to redirect the user. This can be set in the astro config, but this change also allows it to be set in the frontmatter of each post, on a post by post basis. The next commit will be the rename of [slug].astro to [...slug].astro, to support redirecting multi/level/paths to path (separate commit for diff reasons). This meta refresh method isn't the best option if using something like vercel, or a platform with a static adaptor (see: https://docs.astro.build/en/reference/configuration-reference/#redirects), but it's possibly useful for anyone wanting to keep each post's content and config together. Mixing and matching should also be possible. --- src/pages/[slug].astro | 76 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/src/pages/[slug].astro b/src/pages/[slug].astro index 5d06155..16f79cd 100644 --- a/src/pages/[slug].astro +++ b/src/pages/[slug].astro @@ -1,24 +1,88 @@ --- import { getCollection, render } from "astro:content"; import PostLayout from "../layouts/PostLayout.astro"; - import { filterBlogPosts } from "../utils/filterBlogPosts"; +import { components } from "../utils/mdxComponentAutoLoader"; export async function getStaticPaths() { const blog_posts = filterBlogPosts(await getCollection("blog")); - return blog_posts.map((post) => { - return { + // build a flat list of entries + // 1) canonical entry for each post + // 2) zero or more redirect entries that mark themselves with props.redirect_to + const entries = blog_posts.flatMap((post) => { + const primary = { params: { slug: post.data.slug }, props: { post }, }; + + const redirects = (post.data.redirects ?? []) + .filter(Boolean) + .map((redirect: string) => ({ + // each redirect is a separate route that points to the canonical post + params: { slug: redirect }, + // use absolute path (to support change to [...slug].astro) + props: { redirect_to: `/${post.data.slug}` }, + })); + + return [primary, ...redirects]; }); + +/* + Not strictly necessary, but useful to add a warning if the same + redirect string is used on multiple posts. +*/ + +// count how many times each redirect string appears across all posts +const redirect_use_count = new Map(); + +// track which canonical targets each redirect points to (set avoids duplicates) +const redirect_targets = new Map>(); + +for (const post of blog_posts) { + // get redirects array from frontmatter + const redirect_list = (post.data.redirects ?? []).filter(Boolean); + + for (const redirect of redirect_list) { + // +1 usage count for redirect + redirect_use_count.set(redirect, (redirect_use_count.get(redirect) ?? 0) + 1); + + // record canonical target for redirect + const targets = redirect_targets.get(redirect) ?? new Set(); + targets.add(`/${post.data.slug}`); + redirect_targets.set(redirect, targets); + } } -const { post } = Astro.props; -const { Content, headings } = await render(post); +// warn when redirect is listed on multiple posts +// doesn't change output, it only logs a message +for (const [redirect, count] of redirect_use_count) { + if (count > 1) { + const targets = Array.from(redirect_targets.get(redirect) ?? []); + console.warn( + `[WARN] Redirect "${redirect}" is defined on ${count} posts` + + (targets.length ? `, targets: ${targets.join(", ")}` : "") + + `.`, + ); + } +} -import { components } from "../utils/mdxComponentAutoLoader"; + return entries; +} + +const { post, redirect_to } = Astro.props; + +/* + This is very much a static site generator... I imagine the performance + would be horrible if using SSR. That said, it seems silly to no include + the actual 301 SSR redirect. +*/ +if (redirect_to) { + return Astro.redirect(redirect_to, 301); +} + +// Canonical render path only below this line +const { Content, headings } = await render(post); --- From 981f5eabb88483d63fdb18d0311885cd32b66508 Mon Sep 17 00:00:00 2001 From: sec-ml <150138296+sec-ml@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:58:45 +0100 Subject: [PATCH 2/3] Rename to support multi/level/paths --- src/pages/{[slug].astro => [...slug].astro} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/pages/{[slug].astro => [...slug].astro} (100%) diff --git a/src/pages/[slug].astro b/src/pages/[...slug].astro similarity index 100% rename from src/pages/[slug].astro rename to src/pages/[...slug].astro From ee6174179c486a7a544aad31fb5e703ec1caf87b Mon Sep 17 00:00:00 2001 From: sec-ml <150138296+sec-ml@users.noreply.github.com> Date: Wed, 8 Oct 2025 21:01:26 +0100 Subject: [PATCH 3/3] Set redirect path for test --- src/dummy_posts/custom-components.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dummy_posts/custom-components.mdx b/src/dummy_posts/custom-components.mdx index 2c2fd76..fbbeb62 100644 --- a/src/dummy_posts/custom-components.mdx +++ b/src/dummy_posts/custom-components.mdx @@ -9,6 +9,7 @@ tags: - MDX - Custom Components redirects: + - cc excerpt: This post will demonstrate built-in custom components for use within MDX files. ---