Skip to content

11ty: retire the second generator - #5795

Merged
ZJvandeWeg merged 10 commits into
mainfrom
nuxt/eleventy-teardown
Sep 25, 2026
Merged

ZJvandeWeg merged 10 commits into
mainfrom
nuxt/eleventy-teardown

Conversation

@dimitrieh

@dimitrieh dimitrieh commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Description

Every page is served by Nuxt, so this removes Eleventy.

  • Moves what src/ still held into nuxt/ (content/, public/, data/, assets/), with no URL changes.
  • Removes .eleventy.js, the Nunjucks templates, the dev proxy and the 11ty dependencies.
  • Keeps sitemap lastmod dates intact across the file moves, and redirects the one old image path that was only served by accident.
  • Adds a test that fails if anything is left in src/, so an older PR cannot land files that are never built.
  • Rewrites the codebase guide (.claude/CLAUDE.md) for a Nuxt-only site.

Merge FlowFuse/github-actions-workflows#232 first.

Related Issue(s)

Closes #5777

Checklist

  • I have read the contribution guidelines
  • I have considered the performance impact of these changes
  • Suitable unit/system level tests have been added and they pass
  • Documentation has been updated
  • For blog PRs, an Art Request has been created (instructions)

@dimitrieh
dimitrieh force-pushed the nuxt/eleventy-teardown-base branch from aad190a to 955d29b Compare September 11, 2026 17:33
@dimitrieh
dimitrieh force-pushed the nuxt/eleventy-teardown branch from e1c10b8 to f7db070 Compare September 11, 2026 17:33
@dimitrieh

Copy link
Copy Markdown
Contributor Author

Preview affected pages:

This PR has no deploy preview of its own. Its base is nuxt/eleventy-teardown-base, a scaffolding branch, and Netlify builds previews against main-targeting PRs.

It changes no rendered page: every route it touches is already served by Nuxt after PRs 1-17. What it moves is where the files live. The check is that the build still produces them, which is what test_website / Build and check verifies here.

Once PRs 1-17 have merged and this is retargeted to main, its preview is the whole site, and the pages worth a second look are the ones whose assets moved:

  • /blog/2024/07/dashboard-new-charts/ (post images moved to nuxt/public/blog/)
  • /changelog/ (same, for changelog entries)
  • /events/hannover-messe-2026/ and /landing/tulip/ (art that was previously copied by Eleventy)
  • /about/ (team data moved to nuxt/data/)
  • /handbook/company/organizational-structure/ (reads the same team data)

@dimitrieh

Copy link
Copy Markdown
Contributor Author

Root cause of the failing test_website / Build and check, for whenever this comes off draft. The build itself succeeds; the link check after it is what exits 1:

Checking 365041 links from 6562 files (1314 documents)
Found some broken links, reading source files
Error: IO error for operation on website/src: No such file or directory (os error 2)

The step runs hyperlink website/nuxt/dist/ --check-anchors --sources website/src, and this PR is the one that deletes src/. --sources only maps a broken link in built HTML back to the file that produced it, so dropping it does not weaken the check.

It is not fixable in this repo. The argument is hardcoded at line 165 of .github/workflows/build_website.yml in FlowFuse/github-actions-workflows, and .github/workflows/test.yml here pins that workflow at tag build_website/v1. FlowFuse/flowfuse consumes the same workflow and tag, so moving the tag changes that repo's CI at the same moment. Not touching it.

Two things to expect when it is fixed: Found some broken links printed before the crash, so there are real broken links underneath that the --sources error masked, and they will surface once the flag is dropped. #5796 fails the same way, since it is based on this branch.

@dimitrieh

Copy link
Copy Markdown
Contributor Author

Rebuilt on current main. Rebasing the original commit conflicted throughout, since main had moved on under src/, so the moves were regenerated by the same rules from today's tree.

Changes from the previous version:

  • Includes everything added under src/ since then: posts, changelog entries, and the events, landing and vs images.
  • Five files already existed on the Nuxt side with different content. The four icons main had cleaned up in nuxt/assets/icons are kept. For industries/automotive/1-connect-systems.png the src copy wins, since it is the compressed one production serves.
  • New commit: the sitemap's lastmod follows exact file moves, so moved pages keep the date their content last changed instead of all taking this PR's merge date.
  • README: dropped a duplicate blueprints section that still described the retired live branch. The llms.txt note saying part of the site is on Eleventy is removed.

Checked locally: npm ci and npm test pass (274 tests). The full build could not be checked locally, because https://ff-integrations.flowfuse.cloud/api/nodes currently returns an empty catalogue and the build refuses to run without integration pages. That affects any build, not just this branch.

FlowFuse/github-actions-workflows#232 should merge before this.

@dimitrieh
dimitrieh changed the base branch from nuxt/eleventy-teardown-base to main September 25, 2026 19:02
@dimitrieh

Copy link
Copy Markdown
Contributor Author

Folded in #5796 (the codebase guide rewrite) as a third commit, since it only describes the tree this PR leaves behind and could not merge on its own. The description now covers it. This PR is the single remaining cleanup PR for #5777.

@netlify

netlify Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for flowfuse-website ready!

Name Link
🔨 Latest commit 1f6493f
🔍 Latest deploy log https://app.netlify.com/projects/flowfuse-website/deploys/6ab6f0600038cd00082ca704
😎 Deploy Preview https://deploy-preview-5795--flowfuse-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 44 (🟢 up 7 from production)
Accessibility: 95 (no change from production)
Best Practices: 92 (no change from production)
SEO: 92 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Every page is served by Nuxt, so the Eleventy build has nothing left to
generate. This removes it and moves what it still owned into the Nuxt app.

Moved, with no change to any URL:

- src/{blog,changelog,customer-stories,webinars}/**/*.md into nuxt/content/,
  so the four collections that still carried `cwd: '../src'` are sourced like
  every other collection.
- The images beside them into nuxt/public/ at the path they are served from
  (nuxt/public/blog/2024/07/images/...). @nuxt/content resolves a relative
  image in a post against the post's own directory, which is why these have to
  mirror the content tree rather than sit in one flat directory.
- src/images/** into nuxt/public/images/. 181 of those files were already
  byte-identical copies there, from earlier page ports; those are dropped
  rather than moved. One differed: industries/automotive/1-connect-systems.png,
  where the src copy is the compressed one production serves (the build copied
  11ty's output over nuxt/public), so it replaces the nuxt copy.
- src/{events,landing,vs}/images into nuxt/public/ at the same paths.
- src/public/* to the root of nuxt/public/ (favicons, CNAME, security.txt),
  which is where 11ty was copying them.
- src/_data/{site,chrome,blogTags,navHighlights,testimonials}.json,
  events.yaml and team/ and guests/ into nuxt/data/. These are imported
  directly by components and by nuxt.config; 11ty's `_data` convention was the
  only reason they lived where they did.
- src/_includes/components/icons/*.svg into nuxt/assets/icons/, the nav icons
  and the `ff:` icon collection. Four of them (arrows, pin, pulse, uns) already
  had a cleaned-up copy there that the `ff:` collection renders; those are kept.
- src/_includes/analytics into nuxt/server/assets/analytics, a Nitro server
  asset either way.
- src/css into nuxt/assets/css and src/js/cookieconsent-config.js into
  nuxt/assets/js: build inputs, not published files.
- src/js/{nav-tracking,signup-popup}.js into nuxt/public/js/, which is where
  app.head already loaded them from.

Removed: .eleventy.js and .eleventyignore, src/, lib/image-handler.js, the
Nunjucks includes and layouts, src/sitemap.njk (it built sitemap-legacy.xml,
which lists nothing now that no page is generated by 11ty, so robots.txt no
longer points at it), server/middleware/legacy.ts and the legacy-pages guard
that kept new .njk files out, style.eleventy.nav.css (no rule in it matches
anything Nuxt renders), the llms.txt note that part of the site is still on
Eleventy, and 15 dependencies.

nuxt/public is now a tracked asset tree rather than a build output directory,
so its .gitignore lists what a build writes into it instead of the reverse, and
clean:nuxt removes exactly those paths.

The dual build and dev scripts collapse into one of each: `npm run dev` starts
the Nuxt server with the CSS, docs and blueprint watchers beside it, and
`build:nuxt` no longer runs 11ty into nuxt/public first. netlify.toml's build
command and publish directory are unchanged, and `npm run blueprints` keeps its
name.

Two blog posts reference /img/ URLs from the retired image pipeline
(node-red-unified-namespace-architecture, images-in-node-red-dashboards). Both
already 404 in production; they are content fixes, not build ones, and are left
as they are.
The sitemap dates blog, changelog, customer-story, handbook, ebook and
whitepaper pages from the last commit that touched their file. That walk used
`git log --name-only`, which sees a moved file as new at its new path, so the
teardown's move of src/{blog,changelog,customer-stories,webinars} into
nuxt/content/ would have given every one of those pages the same lastmod: the
date of the move.

The walk now reads `--name-status -M100%` and follows exact moves back to the
old path, so a page keeps the date its content last changed. A move that also
edits the file still counts as a change, and deletions no longer date a path.
`-M100%` limits detection to exact moves, which git matches by blob id, so the
walk does not pay for content scoring on every commit.
.claude/CLAUDE.md still described the strangler-fig arrangement: two generators,
a migration-status table, `npm start` for the 11ty stack, a src/ directory
layout, Nunjucks layouts per content type, and a rule against adding a new .njk
page enforced by a test that no longer exists. All of that is gone.

What it says now: one Nuxt app, where each kind of content lives, and the two
collections synced in from other repositories. The Blueprint Library gets a
section of its own, since where it comes from and why it is gitignored here is
the least obvious thing in the tree: resolved at build time, with an
authenticated clone of the private library as the production path. The CTA
section keeps its detail but loses the Nunjucks half and points at
nuxt/lib/cta-destinations.ts, which has been the single source of that data
since before this migration finished. The attribution rule and the Icons
section are kept as they were, with the icon path moved to nuxt/assets/icons.

README's blueprint table named the override `BLUEPRINTS_LOCAL`; the variable
nuxt/lib/blueprints-sync.mjs reads is `FLOWFUSE_BLUEPRINTS_LOCAL`.
@dimitrieh
dimitrieh force-pushed the nuxt/eleventy-teardown branch from 063394d to cbe1c75 Compare September 25, 2026 19:06
@ZJvandeWeg
ZJvandeWeg marked this pull request as ready for review September 25, 2026 19:12
nuxt/assets/icons/ is the `ff` Nuxt Icon customCollection, and Nuxt Icon
parses every SVG in it at build time. Ten of the nav icons moved from
src/_includes/components/icons are bare <path> fragments, which NavIcon wraps in
its own <svg> but Nuxt Icon cannot parse, so `nuxt build` failed with "Cannot
read properties of undefined (reading 'attribs')".

The nav art now lives in nuxt/assets/nav-icons/, byte-identical to what 11ty
served, and nuxt/assets/icons/ is back to exactly the eight icons main has. That
also drops the special case where four icons existed in both places with
different markup: each set keeps its own copy.
11ty copied every images/ directory under src/ to its output, including the one
in its template tree, so sixteen industry illustrations were also served from
/_includes/images/industries/. The same files are at /images/industries/, so
the old path now redirects there instead of returning a 404.
The lastmod walk read `git log` in date order, which interleaves branch commits
with main's and lists no files for a merge. A branch cut before the teardown,
edited under the old src/ path after it and merged in, was walked first and
filed under the old name, so the page kept its pre-move date. `--first-parent
-m` walks main's own history and lists what each merge changed against main, so
the change is dated when it landed, under the path it has there.

The fixture for a renamed-and-edited file now matches what `-M100%` prints (an
add and a delete, not a partial rename), and a test builds a real repository
with a move and a branch merged after it. That test fails without the new flags.
Nothing reads src/ any more, and many open PRs still touch it. A branch that
adds a post in a new month directory merges cleanly into src/blog/ and the post
is never built, with nothing reporting it. retired-src.test.mjs fails while git
tracks anything under src/.

icon-collection.test.mjs checks that every file in the directory nuxt.config.ts
gives the `ff` icon collection has its own <svg> root. A bare <path> fragment
there fails the whole Nuxt build with an error that does not name the file,
which is how the nav icons first broke the build.
A checkout that ever ran the old build still holds its output: _site/, the
eleventy-fetch .cache/, and what 11ty wrote into nuxt/public/ (the eleventy-img
/img/ tree, sitemap-legacy.xml, the _includes/ image copies, two retired
scripts). nuxt/public/ is tracked now, so without these rules that output shows
up as untracked files and a local build copies it into nuxt/dist.
@dimitrieh

Copy link
Copy Markdown
Contributor Author

Verified and reviewed; fixes are pushed.

Verification:

  • Every file under src/ on main is moved byte-identical or intentionally removed; nothing unaccounted for.
  • A full production build (with the integrations guard relaxed locally while the API is empty) prerenders 2765 routes with no errors, and every URL in production's sitemap.xml is in it, apart from the integration and blueprint pages that need external data.

Fixed after review:

  • The nav icon art had landed in nuxt/assets/icons/, the ff Nuxt Icon collection, and its bare <path> fragments crashed nuxt build. It now lives in nuxt/assets/nav-icons/; a test checks the ff folder.
  • A test fails if anything is tracked under src/. Several open PRs still touch it, and a new post there would merge cleanly and never be built.
  • Sitemap lastmod follows main's history, so a change merged from an older branch is dated when it landed.
  • /_includes/images/industries/* redirects to /images/industries/*, the same files.
  • Stale comments, handbook instructions (changelog and blog image paths) and ignore rules for leftover 11ty output.

CI fails at integrations enumeration returned 0 nodes until https://ff-integrations.flowfuse.cloud/api/nodes returns data again; that affects every build, including main.

Merge order: FlowFuse/github-actions-workflows#232, then this, then #5869.

@dimitrieh

Copy link
Copy Markdown
Contributor Author

FYI: the failing build here isn't caused by this PR. Tracked in https://github.com/FlowFuse/engineering/issues/460. It's resolved now, re-running the checks.

Comments that gave Eleventy as the live reason for a choice, or told a
maintainer to keep something in sync with an 11ty template, now say what is
true: the CTA `external` rationale, NodeTile's plain <a>, the /ai prerender
entry (crawlLinks is off, so the entry is required), the chrome.json readers,
the shared stylesheet notes, nav-tracking.js. Pointers to files that moved now
name the new path. Historical "Ported from src/...njk" notes are left as they
are.

Handbook: changelog and blog screenshots go in nuxt/public/<section>/YYYY/MM/images/,
not beside the post, where they would not be served. The website page no longer
describes the 11ty keyword chain, the CTA split between renderers, or the
deleted .njk check. The codebase guide and README name both icon sets and both
Tailwind builds, say when future posts and analytics apply, and name
BLUEPRINTS_REF. .claude/launch.json loses its eleventy entry.
@dimitrieh
dimitrieh force-pushed the nuxt/eleventy-teardown branch from 6470fc4 to 1621c8d Compare September 25, 2026 20:07
@ZJvandeWeg
ZJvandeWeg merged commit 5b911bc into main Sep 25, 2026
9 checks passed
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.

Complete conversion to Nuxt

2 participants