Skip to content

Update the realtime compiler to serve the sitemap and RSS feed#2497

Draft
emmadesilva wants to merge 2 commits into
masterfrom
serve-sitemap-and-feeds
Draft

Update the realtime compiler to serve the sitemap and RSS feed#2497
emmadesilva wants to merge 2 commits into
masterfrom
serve-sitemap-and-feeds

Conversation

@emmadesilva

@emmadesilva emmadesilva commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

The realtime compiler already serves docs/search.json on the fly (it's regenerated on every request instead of being read from a stale build on disk), but sitemap.xml and the RSS feed were never wired up the same way — requests for them fell through to static-asset proxying and either 404'd or served a stale cached copy from a previous hyde build. This PR closes that gap.

  • GET /sitemap.xml and GET /{rss.filename} (default feed.xml) are now generated fresh on every request, using the same SitemapGenerator/RssFeedGenerator classes that back hyde build.
  • Both routes work without a production site URL configured. The realtime compiler always overrides hyde.url to the local server address for normal requests, so there's no need to set a real domain just to preview your sitemap/feed locally.

Architecture decisions

Why a virtual route instead of a real Hyde route

docs/search.json works today because it's backed by a real Hyde RouteDocumentationSearchIndex is an InMemoryPage with a compile() method, registered into the page/route collection. The realtime compiler just special-cases it in Router::shouldProxy() so it isn't treated as a static asset, and lets the normal PageRouter resolve and compile it per request.

Sitemap/RSS have no such route — they're produced only by GenerateSitemap/GenerateRssFeed PostBuildTasks that file_put_contents() straight to disk during a full hyde build. Two ways to close the gap were considered:

  1. Turn sitemap/RSS into real Hyde routes (exactly mirroring DocumentationSearchIndex), removing the PostBuildTasks in favor of the normal per-page compile loop.
  2. Register them as virtual routes inside the realtime-compiler package (the same mechanism already used for /ping, /dashboard, /_hyde/live-edit), calling the generator classes directly, and leaving hyde build untouched.

Went with option 2. Option 1 is the more literal parallel to how search.json works, but it changes production build output: SitemapGenerator iterates all routes, so sitemap.xml would end up listing itself (and feed.xml) as an entry, and the existing PostBuildTasks would need to be deleted to avoid generating the files twice. That's a real behavior change to hyde build for every user, not just realtime-compiler users, for a dev-server-only convenience. The virtual-route approach gets the same on-the-fly behavior in the dev server with zero risk to hyde build.

Dropping the site-URL requirement for local dev

Features::hasSitemap()/hasRss() both require Hyde::hasSiteUrl() — a real, production-looking hyde.url — since that's what hyde build needs to emit correct absolute <loc>/<link> URLs. Registering the virtual routes gated on that check directly in the service provider's boot() meant the routes were only available if you'd already configured a production site URL, which defeats the point of a local preview: you'd get a RouteNotFoundException for /sitemap.xml on a fresh project.

But Router::overrideSiteUrl() already always replaces hyde.url with the local server address (e.g. http://localhost:8080) for every request, specifically so previews don't reference production — unless hyde.server.save_preview is enabled, in which case the override is deliberately skipped so a local URL doesn't get baked into a persisted preview build.

So instead of checking the feature flags at ServiceProvider::boot() (before the override runs), the sitemap/RSS routes are now registered by a new Router::registerDynamicVirtualRoutes(), called after overrideSiteUrl(). This means:

  • In normal dev mode, hasSiteUrl() is always satisfied by the local override, so sitemap/RSS "just work" with no config needed — matching how any other compiled page behaves locally.
  • In save_preview mode, the override is skipped, so the original site-URL requirement still applies, preserving the original safety rationale (no localhost URLs baked into a persisted, production-like build).

Verified against a live hyde serve instance: curl localhost:8080/sitemap.xml returns 200 with valid XML using local URLs, with no SITE_URL configured anywhere.

Known limitation

Router::shouldProxy() decides whether to proxy a request before the Laravel app is booted (a deliberate perf optimization — booting costs ~80ms and most requests are static assets that shouldn't pay for it). That means config('hyde.rss.filename') isn't resolvable at that point. sitemap.xml is hardcoded in the framework so that's an exact match either way, but the RSS check falls back to matching the default filename (feed.xml). If a project customizes hyde.rss.filename, requests to that custom filename will still be proxied as a static asset instead of generated on the fly. This is called out in a code comment at the check site. I believe that customizing the RSS feed filename is such a rare thing to do, that we don't need to slow down everything else to accommodate it. // Emma

@emmadesilva emmadesilva force-pushed the serve-sitemap-and-feeds branch from 85607a1 to b8a26f7 Compare July 4, 2026 00:09
@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (e2c0d70) to head (9b178e1).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff             @@
##              master     #2497   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
  Complexity      1615      1615           
===========================================
  Files            169       169           
  Lines           4074      4074           
===========================================
  Hits            4074      4074           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@emmadesilva emmadesilva force-pushed the serve-sitemap-and-feeds branch from b8a26f7 to 9b178e1 Compare July 4, 2026 00:56
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