Skip to content

Converts from Next.js to 11ty, no more React runtime - #34

Merged
jonrh merged 19 commits into
mainfrom
11ty-v3
Jul 13, 2026
Merged

Converts from Next.js to 11ty, no more React runtime#34
jonrh merged 19 commits into
mainfrom
11ty-v3

Conversation

@jonrh

@jonrh jonrh commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Migrates jonrh.is from Next.js + React to 11ty (Eleventy) 3.1.6. Pages and layouts are now Preact JSX rendered to static HTML at build time. No React runtime and no client-side JavaScript ships. Blog posts remain Markdown.

Why

The site moved to Next.js v10 in October 2020 (from Gatsby v1). I picked Next.js at the time because Gatsby was becoming cumbersome to work with and I wanted to get hands-on familiarity with Next.js which I would go on to use in many other projects and conversions over the following years.

That frees this website to try and learn something new. Initially the plan was to have this site being dynamic. However, over the past 6 years it has not contained anything dynamic. It is fully static. With this conversion the idea was to go back to basics and get rid of React and JavaScript entirely in the runtime. I considered Astro but decided to try 11ty first. It produces the same static output with far fewer dependencies while keeping JSX for authoring pages and Markdown for posts.

A secondary motivation was to see how well an LLM would handle a conversion like this. It performed well and saved a lot of time on the rote, mechanical parts of the migration. The first 2 commits on this branch. Although I still had to take it over the finish line myself, e.g. stripping out old Next.js assumptions and requirements that the mechanical conversion left behind.

JSX

Fable 5 initially converted the site to use Nunjucks. It was fine but for now I still prefer stateless functional "components" using JSX. It is what I have used for the past 12 years. Using Preact allows for using class instead of className and other various niceties.

What changed

Framework & tooling

  • Swapped next / react / react-dom / @mdx-js/* for @11ty/eleventy, preact, preact-render-to-string, and tsx (build-time JSX transpile).
  • package.json is now "type": "module"; scripts are dev: eleventy --serve and build: eleventy.
  • Added eleventy.config.js (registers the .11ty.jsx extension, directories, passthrough copies) and removed next.config.js / pages/_app.js.
  • vercel.json now builds to _site/ with trailingSlash: false.

Templating

  • Pages/layouts converted to .11ty.jsx Preact templates (index, blog, about, portfolio, tools, plus layout and post in _includes/).
  • CSS is read and concatenated into a single inline <style> at build time rather than served as separate stylesheets.
  • Upgraded modern-normalize v1 → v3; fixed a latent font-family bug; simplified body markup to be semantically correct; HTML output is now pretty-printed.

Content structure

  • Migrated Next.js pages/* to 11ty content/*; blog posts co-locate their images in their own content folders (content/[post-name]/).
  • MDX posts converted to plain Markdown.
  • Vacated the /images/ URL namespace and added a single permanent /images/:path*/:path* redirect so old links keep working; repointed the header photo.

Docs

  • readme.md and AGENTS.md updated to describe the 11ty/Preact setup; CLAUDE.md now points to AGENTS.md.

Verification notes

  • URLs preserved via the /images/* redirect; passthrough copy broadened for co-located post images.
  • Meta descriptions are validated (50–160 chars) at build time by post.11ty.jsx.

jonrh and others added 2 commits July 12, 2026 17:13
Pure renames only, no content changes, so that git retains full file history. Content conversion follows in the next commit.

- pages/<slug>/index.mdx -> content/<slug>/index.md (blog posts)
- pages/*.js -> content/*.11ty.jsx (pages)
- components/layout/index.js -> _includes/layout.11ty.jsx
- components/Post.js -> _includes/post.11ty.jsx
- components/layout/layoutStyle.css -> css/layout.css
- next.config.js -> eleventy.config.js

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces Next.js, React and MDX with Eleventy 3.1.6. Pages and layouts are Preact JSX (.11ty.jsx) rendered to static HTML at build time via tsx and preact-render-to-string; no React and no client-side JavaScript is shipped. Blog posts are plain Markdown.

- eleventy.config.js: registers the 11ty.jsx extension, passthrough
  copies for public/, css/ and post co-located images, input dir content/
- _includes/layout.11ty.jsx: base HTML document, header and navigation
- _includes/post.11ty.jsx: blog post template with the 50-160 character
  meta description build validation
- content/*.11ty.jsx: the five pages; portfolio has an inline Dither
  component and tools keeps its dense hand-formatted style
- Posts: <Post> props became front matter (title, dateDisplay,
  metaDescription, sourceFile), layout: post.11ty.jsx
- vercel.json: build command, _site output, no trailing slash to match
  the previous Next.js URLs
- Markdown is not template-preprocessed (markdownTemplateEngine: false)
  so code samples with template-like syntax stay intact

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
jonrh-is Ready Ready Preview, Comment Jul 13, 2026 4:29pm

The original mighty_finder.png file is an animated PNG file comprised of the 512, 256, 128, 32, 16 px resolution variants of the PNG. This is displayed as a rapidly zooming image which is not pleasant to look at. Kept the original image but added a redundant version of the 512x512 px version.
Also restored commented out legacy routes that are not indexed but public.
Return a single default exported function from the tools page instead of creating a <Content> component in-between. Removed 11ty related comments. Comment style changes.
jonrh and others added 2 commits July 12, 2026 22:49
Moves 105 tracked image files from public/images/<name>/ into the
matching content/<name>/ folder (13 posts plus new content/about/ and
content/portfolio/ folders) via git mv so history is retained. Pure
move commit; references are updated in the following commit.

Global assets (header photo, favicon, profile pics) and the unreferenced
image-archive stay under public/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rewrites 76 image references across 15 posts/pages from /images/<name>/
to the co-located /<name>/ path (matching the existing
preview-subdomain-nextj-vercel post), and broadens the content
passthrough glob to cover jpg/jpeg/gif/svg/webp/avif in addition to png
so non-png co-located images are copied to the output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jonrh and others added 5 commits July 12, 2026 23:39
Moves the active header photo (jon-runar-helgason-2026.png/.webp) to the
content/ root so it serves from the site root, and relocates the unused
2017/2019 profile photos and the image-archive set into a top-level
archive/ folder that is kept in the repo but outside content/ and
public/, so it is never deployed.

After this nothing is served under /images/ and public/ holds no images,
which lets a single blanket redirect replace the old per-folder rules
(added in the following commit). Pure git mv; references updated next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Points the header photo references at the new site-root path and adds
one blanket 301 redirect from /images/:path* to /:path* in vercel.json.
Now that nothing is served under /images/, this single rule preserves
every old image URL (co-located post/page images and the header photo),
replacing what would have been 15 per-folder redirects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Inlines all CSS into every page. It's about 4KB so small enough to follow every request. Removed the static file copy passthrough in 11ty, no longer needed.
Removes the React-root leftover div and the .container wrapper. The
body is now the single reading column (max-width, centred, gutter),
with its background propagated to fill the viewport. Uses <header> for
the masthead with <nav> inside it, and wraps each post in <article>
with the source link as its <footer>. Renders identically.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jonrh jonrh changed the title 11ty Converts from Next.js to 11ty, no more React runtime Jul 13, 2026
@jonrh
jonrh merged commit 3494e1c into main Jul 13, 2026
2 checks passed
@jonrh
jonrh deleted the 11ty-v3 branch July 13, 2026 17:16
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