Skip to content

Generate redirects and sitemap exclusions from front matter - #2032

Merged
benbalter merged 1 commit into
mainfrom
audit-frontmatter-redirects
Sep 27, 2026
Merged

benbalter merged 1 commit into
mainfrom
audit-frontmatter-redirects

Conversation

@benbalter

Copy link
Copy Markdown
Owner

Why

redirect_from, redirect_to, and sitemap: false are in the content schema, but nothing read them. Redirects lived in a hand-maintained public/_redirects, and sitemap exclusions were a hardcoded list in astro.config.mjs. The two were kept in sync by hand. This PR makes front matter the source of truth.

Approach

  • src/utils/front-matter-routes.ts (plus tests) reads src/content/{posts,pages} front matter with gray-matter, which is already a devDependency. It maps each entry to its URL: posts go through getPostUrl, and pages use permalink or /id/. From that it derives:
    • Sitemap exclusions: sitemap: false, plus redirect_to entries, since those URLs 301 off-site.
    • Redirect rules: redirect_from -> entry URL 301 and entry URL -> redirect_to 301. Each directory-style source is emitted in both /foo/ and /foo forms, matching the existing convention.
    • A throw if a redirect_from shadows a real page.
  • astro.config.mjs
    • Loads the entries once at config load.
    • Feeds the exclusions into the @astrojs/sitemap filter. The non-content routes stay hardcoded: 404, _not-found, fine-print, resume/linkedin, and resume/print.
    • Adds a small front-matter-redirects integration that appends the generated rules to dist-astro/_redirects in astro:build:done. It fails the build if a source appears in both public/_redirects and front matter.
  • public/_redirects keeps only the non-content rules: feed, sitemap, retired pages, and legacy slug fixes with no front matter.
  • CI: astro-e2e.yml and build-and-deploy.yml now run script/validate-redirects dist-astro/_redirects after the build. The pre-build check on public/_redirects in ci.yml is unchanged.
  • e2e: redirects.spec.ts and the redirect block in pages.spec.ts now read the built file, lazily.
  • post-metadata.ts and the schema are untouched, so isExternal via redirect_to still works.

Before/after: effective redirect rules

These are the sorted non-comment rules in dist-astro/_redirects, from a build of main compared with this branch.

Identical: 63 rules both ways, empty diff.

Of those, 22 lines moved out of public/_redirects and into generated output. None were added and none were dropped. The moved lines are:

  • Page renames (8 lines): /books, /books-for-geeks, /recommended-reading, and /cv, from other-recommended-reading.md and resume.md.
  • Syndicated posts (6 lines): the three redirect_to posts.
  • Slug corrections (8 lines): rules-of-communicating-at-github, types-of-pull-requests, eight-things-i-wish-i-knew-my-first-week, and moderating-open-source-conversations.

script/validate-redirects dist-astro/_redirects reports 63 redirects and 0 issues, with no duplicate sources and no loops.

Before/after: sitemap URLs

204 -> 201. The only removals are the three redirect_to posts:

  • /2012/04/23/enterprise-open-source-usage-is-up-but-challenges-remain/
  • /2015/04/27/eight-lessons-learned-hacking-on-github-pages-for-six-months/
  • /2023/10/04/how-to-communicate-like-a-github-engineer/

This is the one intentional behavior change. Those URLs 301 off-site in production (curl -I on the 2012 URL returns a 301 to TechCrunch), so they shouldn't be in the sitemap. No content file currently sets sitemap: false, so there are no other changes.

Follow-up (not in this PR)

About 11 legacy slug-correction posts have redirects in public/_redirects but no redirect_from in front matter. Examples are what-is-a-hacker, open-collabortion, source-disclosed, jekyll-collections, and cathedral-bazaar-management. Moving them into front matter would finish the migration. I left them alone to avoid touching post files here.

Verification

  • npm run check: 0 errors.
  • Vitest: 15 new tests in front-matter-routes.test.ts, plus post-metadata.test.ts, all pass.
  • SKIP_PDF=1 npm run build: succeeds and logs Appended 22 front matter redirects to _redirects.
  • Redirect and sitemap diffs against a baseline build of main, as above.
  • script/validate-redirects passes on both public/_redirects and dist-astro/_redirects.
  • Playwright: redirects.spec.ts and the pages.spec.ts redirect tests, 22 pass.
  • eslint on the new files and knip are clean.

🤖 Generated with Claude Code

redirect_from, redirect_to, and sitemap: false were accepted by the content
schema but did nothing; public/_redirects and the EXCLUDED_PAGES list were
kept in sync by hand.

- src/utils/front-matter-routes.ts reads posts/pages front matter at config
  load (gray-matter), maps entries to their URLs, and derives sitemap
  exclusions and _redirects rules.
- A front-matter-redirects integration appends the generated rules to
  dist-astro/_redirects in astro:build:done and fails the build on a source
  duplicated between public/_redirects and front matter.
- The 22 now-generated lines are removed from public/_redirects. The
  effective rule set in the built file is unchanged (63 rules).
- redirect_to posts are dropped from the sitemap: their URLs 301 off-site.
- CI validates the built dist-astro/_redirects; the redirects e2e spec
  reads the built file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@benbalter
benbalter merged commit 1869fd2 into main Sep 27, 2026
17 checks passed
@benbalter
benbalter deleted the audit-frontmatter-redirects branch September 27, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant