All six now have robots.txt and sitemap.xml — that part costs
nothing on any of them. llms.txt (the llmstxt.org
convention — a plain-markdown sitemap equivalent aimed at LLM crawlers/retrievers) is
where it splits.
| Stack | robots.txt | sitemap.xml | llms.txt | How it's produced |
|---|---|---|---|---|
| vanilla-static | ✓ | ✓ | ✗ | hand-authored, static |
| vanilla-spa | ✓ | ✓ | ✗ | hand-authored, static |
| site-server | ✓ | ✓ | ✓ | generated at startup from real pages + trails.json |
| react | ✓ | ✓ | ✗ | hand-authored, static |
| vue | ✓ | ✓ | ✗ | hand-authored, static |
| angular | ✓ | ✓ | ✗ | hand-authored, static |
robots.txt/sitemap.xml files were hand-typed once
for this 3-page demo and will silently go stale the moment a page is added, renamed, or
removed. site-server's three files are regenerated from the real wwwroot/pages/
directory and the real trails.json every time the process starts — they cannot
drift from what's actually there. That's the genuine advantage: not "has a file," but
"the file can't lie."
/llms.txt against vanilla-spa (serve -s) and react/vue
(vite preview) returned HTTP 200 with the index.html shell's
content — their SPA-fallback rewrite serves the shell for any unmatched path, not
a real 404. A real production deploy configured the same way would do the same thing to a
crawler checking for the file, which is arguably worse than a clean 404: it looks like
content exists when it doesn't. angular's static server (no fallback flag) correctly
returned a real 404 instead.