<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Dean Nelson: writing</title>
    <link>https://www.deannelson.co.uk/blog</link>
    <description>Notes on React, TypeScript and building for the web.</description>
    <language>en-gb</language>
    <item>
      <title>How this site is built</title>
      <link>https://www.deannelson.co.uk/blog/how-this-site-is-built</link>
      <guid>https://www.deannelson.co.uk/blog/how-this-site-is-built</guid>
      <pubDate>Wed, 11 Nov 2026 09:00:00 GMT</pubDate>
      <description>A TanStack Start app, prerendered to plain HTML and served from GitHub Pages for free.</description>
      <content:encoded><![CDATA[<!-- Starter post: edit it into your own words, or delete this file and write your first real one. --><p>This site is a <a href="https://tanstack.com/start">TanStack Start</a> app, but there is no server behind it. At build time every route is rendered to a static HTML file, and GitHub Pages serves those files like any other static site.</p>
<h2>Why not a plain single-page app?</h2>
<p>A client-rendered React app ships an empty <code>&lt;div id=&quot;root&quot;&gt;</code> and fills it in with JavaScript. That works for people, but it is a poor fit for a blog: search engines and link previews see far less, and the first paint waits on the bundle.</p>
<p>Prerendering gives the best of both. Each page arrives as complete HTML, then React hydrates it and navigation between pages is instant, client-side routing as usual.</p>
<h2>The important bit of config</h2>
<pre><code class="language-ts">tanstackStart({
  prerender: {
    enabled: true,
    crawlLinks: true,
  },
})
</code></pre>
<p>With <code>crawlLinks</code> on, the build starts at the home page and follows every internal link it finds, so a new post is picked up as soon as something links to it.</p>
<h2>Writing posts</h2>
<p>Posts are Markdown files in <code>content/posts</code>. They are imported at build time with Vite&#39;s <code>import.meta.glob</code>, so there is no server function involved, which matters because a static host has nowhere to run one.</p>
<h2>Deploying</h2>
<p>A GitHub Actions workflow runs <code>npm run build</code> on every push and publishes the output to Pages. Other repos with Pages enabled show up under this domain at their own path, which is where side projects live.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
