Replace Next.js build with a custom Rust SSG#2320
Open
hockeybuggy wants to merge 2 commits intomainfrom
Open
Conversation
The site was built on Next.js 15 (Pages Router) with React 19. Even though every page used getStaticProps/getStaticPaths with fallback: false — making the output functionally static — the build still required Node, a React runtime, the Next.js Netlify adapter, and a substantial JS dependency tree. The only real client-side behaviour was the nav menu toggle. This commit introduces a Rust static site generator in ssg/ that reads content/ + styles/ + templates and writes a flat directory tree to dist/. The package.json build/start/dev scripts now invoke cargo rather than next. The Netlify publish target is updated from .next to dist and the lambda functions config is dropped. The Rust SSG uses pulldown-cmark for Markdown, minijinja for Jinja2-style templates, serde_yaml for YAML frontmatter, chrono for date parsing/formatting, and grass for compiling the existing SCSS unchanged. An Atom feed (public/blog/index.xml) and sitemap (public/sitemap.xml) are generated as part of the same cargo run. Client-side JS is reduced to a single 41-line nav.js that handles the hamburger menu toggle; the Plausible snippet stays as inline script in base.html. A custom Node static server (serve_static.js) replaces `next start`. It serves dist/ on port 4000 and resolves directory URLs to index.html in-place without trailing-slash redirects, which is required because the Puppeteer e2e tests assert page.url() === the original URL. All 87 e2e tests and 5 prebuild tests pass against the new output.
The build-site action was written for Next.js and had two problems after the switch to a Rust SSG: 1. No Rust toolchain was installed, so `cargo run` would fail immediately on every CI run. 2. The cache paths referenced `.next/` and `public/`, which are no longer the build outputs. The built site now lives in `dist/`. This commit installs the stable Rust toolchain via dtolnay/rust-toolchain@stable, adds a Cargo registry/target cache keyed on Cargo.lock (so dependency rebuilds are skipped when deps haven't changed), and updates the output cache to point at `dist/`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The site was built on Next.js 15 (Pages Router) with React 19. Even though every page used getStaticProps/getStaticPaths with fallback: false — making the output functionally static — the build still required Node, a React runtime, the Next.js Netlify adapter, and a substantial JS dependency tree. The only real client-side behaviour was the nav menu toggle.
This commit introduces a Rust static site generator in ssg/ that reads content/ + styles/ + templates and writes a flat directory tree to dist/. The package.json build/start/dev scripts now invoke cargo rather than next. The Netlify publish target is updated from .next to dist and the lambda functions config is dropped.
The Rust SSG uses pulldown-cmark for Markdown, minijinja for Jinja2-style templates, serde_yaml for YAML frontmatter, chrono for date parsing/formatting, and grass for compiling the existing SCSS unchanged. An Atom feed (public/blog/index.xml) and sitemap (public/sitemap.xml) are generated as part of the same cargo run. Client-side JS is reduced to a single 41-line nav.js that handles the hamburger menu toggle; the Plausible snippet stays as inline script in base.html.
A custom Node static server (serve_static.js) replaces
next start. It serves dist/ on port 4000 and resolves directory URLs to index.html in-place without trailing-slash redirects, which is required because the Puppeteer e2e tests assert page.url() === the original URL.All 87 e2e tests and 5 prebuild tests pass against the new output.