Skip to content

Add Eleventy SSG: pre-render partials, minify HTML/CSS/JS#33

Open
noahbaculi wants to merge 2 commits intostagingfrom
feat/eleventy-ssg
Open

Add Eleventy SSG: pre-render partials, minify HTML/CSS/JS#33
noahbaculi wants to merge 2 commits intostagingfrom
feat/eleventy-ssg

Conversation

@noahbaculi
Copy link
Owner

@noahbaculi noahbaculi commented Mar 5, 2026

Problem

Every page load triggered 4–6 sequential fetch() calls to inject the header, navbar, subnavbar, side menu, and footer from assets/html/*.html fragments. This caused:

  • Noticeable layout shift on slower connections (content visible before nav appeared)
  • Extra network round trips on every page load
  • Unminified HTML, CSS, and JS served to the browser

Solution

Introduce Eleventy as a build step that pre-renders all shared partials into each HTML page at build time, and adds CSS/JS minification as a post-build step.

Design decisions

Why Eleventy over Hugo:
Hugo's implicit page-kind lookup (list/single/home) doesn't map cleanly to this site's flat structure. Eleventy's explicit layout: base.njk front matter declaration is more readable and the learning curve is lower for a small static site.

Why clean URLs (no .html extensions):
Eleventy's default output is clean URLs (contact.html_site/contact/index.html, served at /contact/). Since Netlify has "Pretty URLs" enabled and all existing _redirects already target paths without .html, there's no reason to override this. The only exception is 404.html, which keeps an explicit permalink: /404.html so Netlify recognizes it as the custom 404 page. Internal links across all _includes/ and page files have been updated to use clean URL paths.

Why html-minifier-terser as a transform rather than a plugin:
The originally planned @11ty/eleventy-plugin-html-minifier-terser package does not exist on npm. html-minifier-terser is already installed as an Eleventy transitive dependency, so a one-liner addTransform in eleventy.config.js achieves the same result with zero extra dependencies.

Two layouts instead of one:
base.njk handles all pages identically. home.njk exists only because the homepage has a unique animated SVG tagline header and directly embeds the top_professional / top_projects snapshot sections — content that lives in the layout rather than the page body so it doesn't clutter index.html.

Standalone pages left untouched:
baculicall.html (no nav) and projects/guitar-tab-generator.html (Twind CSS, fully custom structure) don't use the standard layout. Eleventy processes them as pass-through Nunjucks templates and outputs them unchanged.

What changed

Area Before After
Partials assets/html/*.html fetched at runtime _includes/*.njk inlined at build
main.js loadSection(), replaceWithSection(), initNavbars(), loadHomepageSections() Removed; highlightCurrentPages() + initMenu() called directly
HTML pages Full <!doctype> wrappers, placeholder divs YAML front matter + body content only
CSS/JS Unminified Minified post-build (clean-css + terser)
HTML Unminified Minified inline (whitespace + inline CSS/JS)
URLs .html extensions Clean URLs (/contact/, /professional/aldras/)
Netlify build None configured bun run build_site/

Verification checklist

  • bun run build completes with no errors, _site/ populated
  • Professional page (/professional/aldras/) — header, subnavbar, footer inlined, no fetch calls in DevTools Network
  • Hobbies page (/hobbies/music/) — hobbies subnavbar present
  • Homepage (/) — animated SVG tagline, experience + projects snapshots visible without layout shift
  • Nav active-page highlighting works (current page link highlighted)
  • Mobile slide-out menu opens/closes correctly
  • No console errors
  • _site/assets/css/main.css is minified (single line, no comments)
  • _site/assets/js/main.js is minified
  • _site/404.html exists at root (not _site/404/index.html)
  • Netlify deploy succeeds

🤖 Generated with Claude Code

noahbaculi and others added 2 commits March 5, 2026 13:01
Eliminates 4-6 runtime fetch() calls per page that caused layout shift on
slower connections. Shared partials (header, nav, footer) are now inlined
at build time via Eleventy + Nunjucks templates.

Build pipeline:
- eleventy.config.js: processes all .html pages through Nunjucks, copies
  static assets, minifies HTML output (collapseWhitespace, minifyCSS, minifyJS)
  via html-minifier-terser transform
- scripts/minify-assets.js: post-build CSS minification (clean-css) and JS
  minification (terser) on _site/assets/

Layout system:
- _includes/layouts/base.njk: all pages — inlines header, navbar, conditional
  subnavbar (section: professional|hobbies), side_menu, footer, main.js
- _includes/layouts/home.njk: homepage only — inline animated SVG tagline,
  top_professional and top_projects snippets; no subnavbar needed
- _includes/head.njk: shared <head> accepting title, description, noindex,
  extraCss[], preJs[], extraJs[] front matter variables

Pages:
- Each .html file now has YAML front matter (layout, title, description,
  section) and contains only its unique body content
- professional/index.html and projects/index.html use {% include %} to inline
  top_professional.njk / top_projects.njk rather than fetch()-filling divs
- Standalone pages (baculicall.html, projects/guitar-tab-generator.html)
  left unchanged — no layout needed
- familytree.html and 404.html use extraCss/extraJs front matter for their
  additional stylesheet and script dependencies

main.js:
- Removed: loadSection(), replaceWithSection(), initNavbars(),
  loadHomepageSections() and their top-level invocations
- Kept: highlightCurrentPages() (active nav link), initMenu() (mobile drawer)
- Both called directly on script load (no async dependency on fetch)

Routing:
- _data/eleventyComputed.js overrides Eleventy's default clean-URL output
  (foo/index.html) to preserve .html extensions (foo.html), keeping all
  existing internal links and Netlify redirects valid
- Output directory: _site/ (added to .gitignore)
- Netlify build: command = "bun run build", publish = "_site"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove _data/eleventyComputed.js which forced .html output paths.
Eleventy's default clean URL output (contact/ instead of contact.html)
is correct since Netlify has Pretty URLs enabled. Strip .html extensions
from all internal absolute links across _includes and page files.
Fix /xxx/index links to /xxx/. Add permalink: /404.html to 404.html
so Netlify serves it as the custom 404 page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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