Skip to content

Add blog RSS feed and robots.txt - #153

Merged
3mdistal merged 2 commits into
mainfrom
feat/blog-rss-robots
Sep 25, 2026
Merged

3mdistal merged 2 commits into
mainfrom
feat/blog-rss-robots

Conversation

@3mdistal

@3mdistal 3mdistal commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Problem

The live site 404s on /rss.xml, /feed.xml, and /robots.txt. There's no way for feed readers to subscribe to the blog, and no robots.txt to guide crawlers to the sitemap or away from /api/ and the owner-only /owner editing page.

Changes

  • src/lib/server/rss.ts (new): a pure, testable RSS 2.0 serializer, mirroring the existing src/lib/server/sitemap.ts pattern. Exports small focused helpers (escapeXml, toRfc822, wrapCdata/makeCdataSafe, applySubAndSuperMarkers, absolutizeHtmlUrls) plus serializeRssFeed, which assembles the <rss> document with the content and atom namespaces.
    • applySubAndSuperMarkers is the feed-safe (pure string) equivalent of the browser-only subAndSuper in src/lib/notion/utils/blog-helpers.ts — it turns {super:x}/{sub:x} markers into real <sup>/<sub> tags so feed readers (which never run the site's client JS) don't see raw markers. On-site rendering is unchanged.
    • absolutizeHtmlUrls rewrites root-relative src="/..."/href="/..." attributes to absolute URLs; already-absolute and protocol-relative URLs are left alone.
    • CDATA wrapping splits any embedded ]]> so it can't terminate the section early.
  • src/routes/rss.xml/+server.ts (new): a prerendered endpoint (export const prerender = true) that loads all blog posts (loadPostsMeta/loadPostBySlug), renders each with the existing renderBlogMarkdown, and serializes the feed. Channel title is "Alice Alexandra Moore", link is /blog, description reuses the blog index's meta description, and each item includes title, link/guid, pubDate, category, a description (summary, falling back to ogDescription then subtitle), and content:encoded with the full rendered HTML.
  • static/robots.txt (new): allows everything except /api/ and /owner, and points at https://www.alicealexandra.com/sitemap.xml.
  • src/app.html: adds <link rel="alternate" type="application/rss+xml" title="Alice Alexandra Moore" href="/rss.xml" /> to <head> for feed-reader autodiscovery.
  • src/lib/server/rss.test.ts (new): vitest coverage for XML escaping, RFC-822 date formatting, CDATA safety with embedded ]]> (including a real round-trip through fast-xml-parser), absolutizing URLs, sub/super marker replacement, and a full-feed structural test.

Out of scope (per the task): no other SEO/metadata changes, no content-repo changes, no changes to how posts render on-site. Another parallel change was touching src/routes/+layout.svelte and blog route files, so those were intentionally left untouched.

Testing

  • pnpm lint — passes (Prettier + ESLint clean).
  • pnpm check — passes (svelte-check: 0 errors, 0 warnings across 550 files).
  • pnpm exec vitest --run — 54/54 tests pass across 9 files, including the 18 new rss.test.ts cases.
  • Built with svelte-kit sync && vite build, then restored content/career/builder.json (the build rewrites it).
    • .svelte-kit/output/prerendered/pages/rss.xml exists, parses as well-formed XML (python3 -m xml.dom.minidom), and contains exactly 13 <item> entries — one per content/blog/posts.json entry, newest first.
    • No raw {super: / {sub: markers anywhere in the output; spot-checked full-speed-to-dopamine's item and confirmed {super:TM} became <sup>TM</sup> in content:encoded.
    • Spot-checked image URLs in content:encoded (already absolute in source content) and confirmed a root-relative link (/about#connect, present in two posts) was rewritten to https://www.alicealexandra.com/about#connect.
    • .svelte-kit/output/prerendered/pages/blog.html (and other pages, since the link lives in app.html) contains the new <link rel="alternate" ...> tag.
    • .svelte-kit/output/client/robots.txt matches the intended rules and includes the Sitemap: line.
  • Ran vite preview --port 4392 and curled:
    • GET /robots.txt → 200, body matches expected rules and Sitemap line.
    • GET /rss.xml → 200, but vite preview's static file server reports content-type: text/xml, not application/rss+xml. I confirmed this is a pre-existing vite preview quirk, not something new: GET /sitemap.xml shows the exact same text/xml locally despite its +server.ts also declaring application/xml. In production, Vercel serves prerendered .xml files by extension: the live /sitemap.xml (same pattern) comes back as application/xml, so expect /rss.xml to be application/xml too. Feed readers accept that, so no workaround is needed.

Unverified

  • The Vercel preview deployed successfully but is behind Vercel's login, so /rss.xml and /robots.txt couldn't be fetched there. Both will be confirmed on production after merge.
  • W3C feed validator (no network access in this environment); relied on fast-xml-parser/xml.dom.minidom well-formedness checks and manual review of required RSS 2.0 elements instead.

🤖 Generated with Claude Code

The live site 404s on /rss.xml, /feed.xml, and /robots.txt. Add a
prerendered RSS 2.0 feed (with content:encoded and atom:link self)
for the blog, a robots.txt that disallows /api/ and the owner-only
/owner page while pointing at the sitemap, and an RSS autodiscovery
link in the document head.

The feed serializer lives in a pure src/lib/server/rss.ts module
(mirroring the sitemap.ts pattern) with a vitest suite covering XML
escaping, RFC-822 date formatting, CDATA safety for embedded ]]>,
absolutizing root-relative src/href attributes, and replacing the
site's {super:x}/{sub:x} markers with real <sup>/<sub> tags so feed
readers don't see raw markers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
alicealexandra.com Ready Ready Preview, v0 Sep 25, 2026 1:23pm UTC

@3mdistal
3mdistal merged commit 7d93230 into main Sep 25, 2026
3 checks passed
@3mdistal
3mdistal deleted the feat/blog-rss-robots branch September 25, 2026 13:24

This branch was successfully deployed

1 active deployment
Preview — 3d0d87a3 Deployed Sep 25, 2026 by vercel[bot]
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