Skip to content

Migrate website from 11ty to Nuxt 4#5091

Draft
dimitrieh wants to merge 90 commits into
mainfrom
4867-migrate-website-to-nuxt
Draft

Migrate website from 11ty to Nuxt 4#5091
dimitrieh wants to merge 90 commits into
mainfrom
4867-migrate-website-to-nuxt

Conversation

@dimitrieh
Copy link
Copy Markdown
Contributor

Description

Completes the 11ty to Nuxt 4 migration for the marketing website. Every existing URL is preserved (route-parity gate enforced), and the production build is now pure nuxt generate.

  • Marketing pages, handbook, docs, blog, integrations, node-red, events, and all other clusters migrated to native Nuxt 4 components and @nuxt/content collections.
  • 11ty fully removed: .eleventy.js, src/ 11ty templating, the legacy proxy middleware, and the 11ty build steps in package.json are gone.
  • Docs continue to source from FlowFuse/flowfuse via scripts/copy_docs.js (contract unchanged); a new scripts/copy_docs_nuxt.js step generates nuxt/content/docs/* at build time.
  • Build is now npm run build:nuxt (runs the copy scripts then nuxt generate). netlify.toml already points at nuxt/.output/public.
  • Route-parity baseline frozen at migration/routes-11ty.txt; migration/verify-routes.sh confirms Dropped: 0 (1186 routes, a superset of the 1178 baseline including upstream additions like the new blog categories and the NIS2 post).
  • Responsive sweep at 375/768/1280/1920 across docs, handbook, and a representative page per cluster: 0 horizontal overflow.
  • nuxt-link-checker: 0 of 1180 failing.

Full per-cluster notes, the verification harness, the route diff, and the long-form summary live under migration/ (see migration/PR_DESCRIPTION.md).

Related Issue(s)

Closes #4867

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 (static site: verification via the committed route-parity harness, link-checker, and responsive sweep instead)
  • Documentation has been updated
  • For blog PRs, an Art Request has been created (N/A)

@dimitrieh
Copy link
Copy Markdown
Contributor Author

dimitrieh commented May 29, 2026

Additional details

High-level changes

  • All sections rendered natively by Nuxt. Marketing pages are bespoke
    nuxt/pages/**/*.vue; markdown-driven sections (blog, changelog, handbook,
    docs, customer-stories, webinars/AMAs, ebooks) use @nuxt/content v3
    collections.
  • src/ is now a data source only. The build-time scripts/copy_*.js steps
    read the markdown and src/_data/* and generate the Nuxt content collections +
    route lists. There are no .njk templates or .eleventy.js anymore.
  • Eleventy removed: .eleventy.js, lib/, the dev proxy
    (nuxt/server/middleware/legacy.ts), src/_data/eleventyComputed.js, and all
    src/ .njk/_includes templating are deleted. The production build is a
    plain npm run buildbuild:nuxtnuxt generate.

    Note: @11ty/eleventy-fetch is intentionally retained — it is a generic HTTP
    caching-fetch library used by copy_node_red.js, copy_integrations.js, and
    a couple of src/_data/* scripts, not the 11ty build engine.

  • Straggler pages that the Nuxt prerenderer cannot reproduce (literal spaces
    in the URL, /404.html, /llms.txt) are served from committed HTML under
    nuxt/legacy-static/ (copied into public by copy_legacy_static.js) so their
    URLs are preserved.

Dev & build commands

npm install            # npm workspaces; nuxt/ is a workspace
npm run dev            # nuxt dev (3000) + postcss + docs + blueprints watchers
npm run build          # → build:nuxt → copy_* steps then `nuxt generate`
npm run build:nuxt:skip-images   # faster iteration (skips image processing)
  • Running nuxt dev behind a remote proxy? Allowlist your host without committing
    it: NUXT_DEV_ALLOWED_HOSTS=my-host.example.com npm run dev.
  • Optional QA helpers (require Playwright): npm run qa:responsive,
    npm run qa:smoke.

Verification gates

Gate Result
nuxt generate (npm run build:nuxt:skip-images) clean, no errors
Route parity (migration/verify-routes.sh vs frozen 1178-route 11ty baseline) Dropped: 0 — Nuxt build is a superset (see migration/route-diff.txt)
nuxt-link-checker (failOnError: true) 0 failing
Responsive sweep — npm run qa:responsive, viewports 375/768/1280/1920, docs + handbook + one page per cluster 60 captures, 0 horizontal overflow, all HTTP 200

The route-parity check is the proof for the "URLs never change" constraint: the
frozen migration/routes-11ty.txt (1178 routes) is diffed against the generated
Nuxt route set; the build fails if any legacy URL is dropped or renamed. The
committed migration/route-diff.txt is the evidence artifact.

CI

  • .github/workflows/test.yml already builds the site with
    npm run build:nuxt:skip-images and runs the hyperlink link-check against
    nuxt/.output/public.
  • .github/workflows/build.yml syncs docs + blueprints and pushes to the live
    branch (Netlify builds live via netlify.toml [build] = npm run build:nuxt).
  • netlify.toml [dev] was the one stale reference to the deleted 11ty engine;
    it now runs npm run dev on port 3000.

Known / deferred items (non-blocking)

  • Cosmetic hydration warnings on a few bespoke marketing pages (/pricing/,
    /node-red/, /platform/device-agent/): "Hydration completed but contains
    mismatches". Content/header/footer all render correctly; pinpointing the exact
    node reliably needs a dev-mode build. Deferred rather than guessed at.
  • @flowfuse/flow-renderer throws on flows containing group/junction/tab
    container nodes (same library + flow JSON 11ty used) — a pre-existing renderer
    limitation, wrapped in try/catch so the page degrades gracefully.
  • Generated-content tracking is intentionally split by cluster: blog,
    integrations, and node-red commit their generated nuxt/content/** +
    *.json (they pull from external/volatile sources, so snapshotting them in git
    gives reproducible builds and a working nuxt dev without a full rebuild),
    while handbook/docs/changelog/events/ebooks/customer-stories gitignore theirs
    and regenerate at build time. Each cluster is internally consistent; unifying
    the two strategies is left for a follow-up if the team prefers.
  • Sidebar nav ordering for docs/handbook is currently alphabetical from
    queryCollectionNavigation; the legacy navGroup/navOrder grouping is
    captured in the generated index JSON but not yet applied to the tree.
  • Site-wide integrations not re-wired: Algolia search box and HubSpot chat are
    global-script integrations documented as degraded (pre-existing gap).

See migration/STATUS.md for the full page-by-page migration record and
migration/README.md for the verification harness.

Copy link
Copy Markdown

@github-advanced-security github-advanced-security AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trivy found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@allthedoll
Copy link
Copy Markdown
Contributor

We need to find a way to break this down, no one can review 809 files. 😅

@netlify
Copy link
Copy Markdown

netlify Bot commented May 29, 2026

Deploy Preview for flowforge-website ready!

Name Link
🔨 Latest commit 3a5f626
🔍 Latest deploy log https://app.netlify.com/projects/flowforge-website/deploys/6a1aa9dfedff760008f31d9c
😎 Deploy Preview https://deploy-preview-5091--flowforge-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: 68 (🔴 down 8 from production)
Accessibility: 95 (🔴 down 1 from production)
Best Practices: 100 (no change from production)
SEO: 90 (🔴 down 1 from production)
PWA: -
View the detailed breakdown and full score reports

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

dimitrieh added 23 commits May 30, 2026 09:08
Adds tooling to prove the Nuxt build serves a superset of the legacy 11ty
routes (zero dropped URLs, trailing slashes preserved): route extractor,
diff checker, end-to-end verify script, and the committed 11ty route
baseline (1069 routes).
Separate one-time baseline capture (capture-baseline.sh) from per-build
verification (verify-routes.sh) so the diff keeps catching dropped URLs
even after a section is removed from the 11ty build.
Hybrid build (11ty copied into nuxt/public + Nuxt-native /terms,
/privacy-policy) produces a superset of the frozen 1069-route 11ty
baseline. Confirms the strangler-fig output drops no URLs.
Allowlist the sprite host so the Nuxt dev server works behind the
*.sprites.app proxy, and record migration progress, the route-parity
proof, and the remaining scope/blockers in migration/STATUS.md.
Render the handbook via @nuxt/content at its original /handbook/... URLs
(trailing slashes preserved) instead of 11ty:
- scripts/copy_handbook.js generates nuxt/content from src/handbook,
  rewriting relative .md links to absolute handbook URLs and relative
  images to /handbook-media (copied into public).
- handbook collection + pages/handbook/[...slug].vue with sidebar nav
  (HandbookNavTree) and TOC; routes prerendered from handbook.routes.json.
- legacy proxy yields /handbook* to Nuxt in dev.
- The one .njk-templated and one space-named handbook page stay on 11ty.
- Skip link-checker best-practice STYLE inspections (not broken links)
  that legacy prose violates; failOnError stays on.

Verified: nuxt generate green, link-checker 0 errors/0 warnings,
route diff 0 dropped URLs (Nuxt superset of the 1069-route baseline).
11ty now ignores the handbook pages Nuxt owns (via generated
nuxt/handbook.migrated-sources.json manifest); only the 3 bespoke
straggler pages (2 .njk + 1 space-named .md) still build on 11ty.
Verified: build green, link-checker 0/0, route diff 0 dropped.
Render the changelog at its original URLs via Nuxt instead of 11ty:
- scripts/copy_changelog.js generates nuxt/content/changelog from
  src/changelog (relative links/images rewritten) and a combined,
  date-desc card index (170 entries + 9 blog posts tagged 'changelog')
  matching 11ty's collection so pagination yields the identical pages.
- pages/changelog/[...slug].vue serves entries, the paginated index
  (/changelog/ + /changelog/1..9/, 19/page), with author/date/issues
  from the generated index (single source of truth shared with the feed).
- server/routes/changelog/index.xml.get.ts reproduces the Atom feed.
- .eleventy.js ignores the 170 entries + index.njk + feed-changelog.njk;
  legacy proxy yields /changelog* to Nuxt.

Verified: nuxt generate green, link-checker 0/0, route diff 0 dropped
(Nuxt superset of the 1069-route baseline).
scripts/copy_customer_stories.js generates nuxt/content/customer-stories
+ a metadata index (brand/quote/challenge/solution/logo) since @nuxt/content
doesn't surface nested frontmatter. pages/customer-stories/[...slug].vue
serves the index grid + story pages (hero, quote, Challenge/Solution
sidebar) at identical URLs; legacy proxy yields /customer-stories* to Nuxt.

11ty keeps building these (Nuxt prerender overwrites in the merged output)
because collections.stories is consumed by other pages that remain on 11ty
(node-red/index, landing/tulip, thank-you/contact, llms).

Verified: build green, link-checker 0/0, route diff 0 dropped.
Reproduces the legacy 11ty renderFlow shortcode: renders a Node-RED flow
client-side via the bundled @flowfuse/flow-renderer (window.FlowRenderer,
loaded through a runtime module script). Flow JSON is passed base64-encoded
to survive MDC parsing. Verified in a real browser: renders nodes, wires,
labels and zoom controls. Unblocks faithful migration of the 188 renderFlow
embeds across node-red and blog.
Render /webinars/ (index + 39 detail pages) and /ask-me-anything/ (3 pages)
natively via @nuxt/content, preserving every URL incl. trailing slashes.

- scripts/copy_events.js generates webinars + ama collections from
  src/webinars and src/ask-me-anything, resolving hosts (team+guests) and
  per-page metadata (date/time/duration/video/hubspot) into events.index.json,
  and emits events.routes.json for prerendering.
- Shared EventDetail + HubSpotForm components; webinars [...slug] handles the
  index and detail, ask-me-anything [...slug] reuses EventDetail.
- The one webinar whose filename contains a literal space is left on 11ty
  (Nuxt prerenderer cannot resolve unsafe-char routes); 11ty still emits it so
  route parity holds. Dir-index (index.md) maps to the directory URL.
- Removed /webinars + /ask-me-anything from the legacy proxy.

Verified: build green, prerender 0 errors, route diff 0 dropped (superset),
pages confirmed Nuxt-rendered.
Render /ebooks/<slug>/ natively via @nuxt/content, reusing the HubSpotForm
component for the gated download. copy_ebooks.js generates the ebooks
collection + metadata index (title/cover/contentTable/hubspot) from src/ebooks;
images resolved to absolute /images URLs. Removed /ebooks from the legacy proxy.

Verified: build green, prerender 0 errors, route diff 0 dropped, page
Nuxt-rendered with working download form.
…tes)

Convert three bespoke 11ty solution pages to native Vue pages, reproducing the
hand-crafted marketing markup (hero, feature grids, advantage grid, CTA, UNS
learn cards). Icons inlined as SVG; sign-up shortcode resolved to the app URL;
lite-youtube replaced with a responsive iframe. Added each exact route to the
legacy proxy NUXT_ROUTES and to nitro.prerender.routes.

Verified: build green, prerender 0 errors, link-checker 0/0, route diff 0
dropped, all three confirmed Nuxt-rendered.
Add the remaining three bespoke solution pages (data-integration, mes,
it-ot-middleware) as native Vue, reproducing the hand-crafted marketing markup:
feature grids, ffIconLg icons inlined as SVG, architecture/pictogram sections,
resources (case-study + whitepaper cards), deployment options, and a reusable
FaqAccordion component. With all six migrated, /solutions is now a Nuxt-owned
prefix in the legacy proxy (individual route entries removed).

Verified: build green, prerender 0 errors, link-checker 0/0, route diff 0
dropped, all six confirmed Nuxt-rendered.
Convert the two comparison landing pages to native Vue, reproducing the
data-driven hero, feature grids, comparison tables, switch steps, and CTA.
Add a reusable SocialProof.vue (homeLogos carousel) shared by both. Icons
inlined as SVG, sign-up shortcode resolved, lite-youtube -> responsive iframe.
/vs is now a Nuxt-owned proxy prefix.

Verified: build green, prerender 0 errors, link-checker 0/0, route diff 0
dropped, both pages Nuxt-rendered (kepware visually confirmed).
dimitrieh added 29 commits May 30, 2026 09:09
scripts/visual-check.js drives a headless Chrome over a representative URL
per migrated cluster, capturing page errors, first-party 404s and render
signals (screenshots to /tmp/smoke). Document the final verification results
and the two known non-blocking items (hydration warnings on a few bespoke
pages; flow-renderer limitation on flows with group/junction nodes) in
migration/STATUS.md.
Ports the rotating hero background images, indigo full-bleed hero, screenshot
bridge, and updated metrics (red styling) from src/index.njk into the native
Nuxt homepage; 11ty source remains deleted.
…dbus categories

- Render the TL;DR / first-answer block on blog posts (tldr frontmatter now
  captured in blog.index.json) and show author job titles + 'Updated' date label,
  matching the upstream post layout.
- Add plc/mqtt/opcua/modbus to the blog category map so /blog/<cat>/ routes
  generate natively (the new upstream category landing pages), and wire the
  'See All PLC Articles' button on the PLC landing page.
- Docs/handbook: sidebar is now a collapsible disclosure below lg and the
  two-column layout shifts from md to lg, so tablet (768px) no longer overflows
  and mobile no longer dumps the full nav tree above the content.
- Cap all <img> to their container width (ported pages hardcoded
  style=max-width:NNNpx without width:100%, overflowing narrow viewports);
  also fixed the it-ot-middleware architecture diagram.
- Normalise blog card/hero image paths to absolute in copy_blog.js so relative
  frontmatter image refs stop 404ing on index/category pages.
- Make code fences and wide tables scroll within prose instead of forcing the
  page wider on mobile/tablet (no max-width was set, so long lines overflowed).
- Restore the docs landing-page tile grids (offering + product-feature): the
  11ty CSS for these classes was lost in migration, leaving inert grid-cols
  utilities and unstyled stacked text; re-add a responsive card grid.
…ile/tablet

The native docs/handbook pages lay out their own 3 columns on an inner wrapper,
but the outer div still carried the legacy .handbook class whose flex/grid
container (built for the old 11ty direct-child DOM) sized its flex item to
content min-width — forcing ~920px and overflowing narrow viewports (545px at
375px). Scope a .handbook-shell override to render those wrappers as plain
blocks; node-red and the legacy-static pages keep .handbook unchanged.
Blank lines inside the ff-*-tiles HTML containers (left by multi-line inline
SVGs) terminated the markdown HTML block, so the indented continuation rendered
as <pre> blocks of raw HTML on the docs landing page. Strip blank lines within
those containers during content generation so they render as the card grid.
Picks up the new upstream blog posts/tags (incl. NIS2), the new category routes,
TL;DR + absolute card-image paths from copy_blog, and the upstream mqtt-in docs
update; reconciles package-lock.json after the rebase.
…ication

scripts/responsive-check.js: scripted 4-viewport Playwright sweep (no MCP) with
overflow detection. Updates the committed route-diff evidence (Dropped: 0) and
documents this session in migration/STATUS.md.
The [dev] command still launched 'npx @11ty/eleventy --watch', whose engine
was deleted in the 11ty teardown, so 'netlify dev' would fail. Point it at the
Nuxt dev server ('npm run dev', port 3000) and drop the stale Eleventy labels
on the image cache paths (the paths themselves are still valid).
- nuxt.config.ts: drop the hardcoded '<sprite>.sprites.app' Vite allowedHosts
  entry. Replace with a $development-only allowlist sourced from the
  NUXT_DEV_ALLOWED_HOSTS env var, so nothing host-specific ships in the repo
  while devs behind a proxy can still allowlist their host.
- scripts/responsive-check.js, scripts/visual-check.js: resolve Playwright via
  a normal require('playwright') (with an install hint) instead of hardcoded
  /home/sprite npx-cache paths; make the Chrome executable opt-in via CHROME_PATH
  rather than a hardcoded /usr/bin path. Add qa:responsive / qa:smoke npm
  aliases so they are discoverable dev-QA tools.
- README.md: rewrite the repo-structure, dev-server, and build sections to
  describe the single Nuxt 4 static build (src/ is now a data source only).
  Remove the Strangler-Fig / 11ty-proxy / port-8080 / 'legacy-only mode' text
  and the Nuxt 3 references.
- .claude/CLAUDE.md: replace the deleted layouts/*.njk references (per content
  type + the Layouts table) with the Nuxt pages/components that render each
  section; drop the removed eleventyComputed.js data row.
- migration/README.md: note the frozen baseline is 1178 routes; 'hybrid' -> static.
- migration/PR_DESCRIPTION.md: new — what changed, why, dev/build commands,
  verification gates, and deferred items.
- VERIFICATION.md: rewrite as the final-state record (1178->1186 routes, Dropped 0;
  link-checker 0 of 1180 failing; responsive sweep 60 captures, 0 overflow) instead
  of the stale 1069-route handbook-increment snapshot.
- STATUS.md: add a 'FINAL STATE (PR-ready)' summary at the top with the current
  numbers, and flag the running log below as historical so the older interim
  counts don't read as current.
Vues default transformAssetUrls rewrites <img src="/foo.png"> into a Rollup
import. Under SKIP_IMAGES (which test.yml runs via build:nuxt:skip-images),
copy_assets skips populating nuxt/public, so the imports cannot resolve and
the production build errors out. Setting vite.vue.template.transformAssetUrls
.includeAbsolute=false leaves root-relative URLs as plain runtime paths served
from public/. Production deploys (no SKIP_IMAGES) and the prior local builds
were unaffected; this only matters when the assets directory is empty at
build time.
11tys addPassthroughCopy ran unconditionally regardless of SKIP_IMAGES;
the flag only disabled the @11ty/eleventy-img optimization step. The
post-migration copy_assets.js conflated the two, gating the raw copy on
SKIP_IMAGES and producing a build output with no images at all in test
mode. This broke CIs static link checker (4788 missing image refs).

Drop the SKIP_IMAGES gate so raw originals always copy. The flag becomes
a no-op here, reserved as a placeholder for any future image-optimization
pipeline (e.g. @nuxt/image) where it would once again mean disable
optimization, not skip copying.
The Netlify _redirects body extraction stripped frontmatter with a \n-only
delimiter; allow an optional \r so CRLF-checked-out source still produces a
clean _redirects file.
@nuxt/content (via MDC) slugs heading ids with github-slugger, which strips
'?', ':', '(', ')', '&', periods and emoji. The legacy 11ty build used
markdown-it-anchor's default slugify, which keeps them, and the prose anchors
throughout the docs/handbook/blog were written against that form (e.g.
'#what-is-udp?', '#ideal-customer-profile-(icp)', '#🔁-iterative-improvement').

Add an mdc.config.ts that injects a rehype plugin (before MDC's compileHast, so
the id flows to both the heading and the generated TOC) re-deriving each heading
id with the markdown-it-anchor algorithm in raw, non-percent-encoded form so it
is byte-identical to the raw href fragments authors wrote.
…ernal links)

Reproduce 11ty's internal-link rewriting (*/abc.md#x -> */abc/#x, */README#x ->
*/#x) for the absolute links that the per-collection copy scripts don't touch —
chiefly the externally-synced docs and handbook, including raw-HTML <a> tags
that the markdown-only copy regexes never matched. Done as a rehype plugin so
it covers every collection and both markdown- and HTML-authored links in one
place, adding the directory trailing slash the routes expect (while leaving
real file extensions like .zip/.pdf alone).
… links)

11ty left blog relative links untouched and let the browser resolve them
against the page URL; @nuxt/content resolves them against the page path treated
as a file, dropping a segment, so '../../04/foo' in a /blog/2022/05/<post>/ page
became '/blog/04/foo' (year lost) instead of '/blog/2022/04/foo'. Resolve
relative link targets in copy_blog.js against the post's rendered URL (a
directory) before the content is handed to @nuxt/content, matching 11ty.
Port 11ty's fuzzy anchor-repair: rewrite broken in-page '#fragment' links to the
real heading id they were meant to reach. Generalises 11ty's period-only match
to a normalised (lower-cased, alphanumerics-only) match so it also bridges the
residue MDC's id post-processing introduces that the slugger plugin can't
pre-empt (collapsed consecutive dashes, leading-digit '_' prefix). Cross-page
aware and only ever touches already-broken links. Wired into both build chains
between 'prod:nuxt' and 'sitemap'.
…headings

The mdc.config.ts file-discovery produced an empty #mdc-configs template in this
setup, so the slugger/link plugins never ran. Register them instead through
content.build.markdown.rehypePlugins as in-process `instance` functions (which
@nuxt/content resolves directly), and drop the dead mdc.config.ts. Also honor an
explicit trailing {#custom-id} on a heading (11ty's markdown-it-attrs), using it
as the id and stripping it from the visible text.
@nuxt/content resolves relative links against the page path treated as a file,
dropping a path segment (e.g. ./mcp-tool from .../mcp/index -> /node-red/flowfuse/
mcp-tool instead of .../mcp/mcp-tool). 11ty resolved them relative to the source
file (its rewriteHandbookLinks ../-prepend made that equivalent). Resolve every
relative internal link (with or without .md, README/index -> directory) against
the source dir at copy time, for markdown and raw-HTML <a> links alike, so
@nuxt/content never sees a relative link to mis-resolve.
The blog relative-link resolver treated a malformed `lhttps:` typo URL as a
relative path (new URL parsed the scheme), turning an externally-ignored link
into a broken internal one. Skip any target carrying a URI scheme. Regenerated
blog content reflects the dimension-3 relative-link resolution.
A webinar linked a sibling .zip via a relative path; it was neither resolved
nor published. Resolve relative downloadable assets at copy time and serve them
from /events-media/, alongside the existing image handling.
Cross-page anchor links arrive percent-encoded (e.g. ':' -> '%3A'); decode the
fragment before matching so it can be reconciled with the literal heading id.
The first/last-page Prev/Next links were only hidden with opacity, leaving a
broken href (e.g. /blog/20, /changelog/10) in the DOM for the link checker to
flag. Render them with v-if so the hidden link is not emitted at all.
Completes the registration the prior commit intended: nuxt.config.ts registers
the anchor-slugs + strip-internal-md rehype plugins via
content.build.markdown.rehypePlugins (instance functions), and anchor-slugs.mjs
honors explicit {#custom-id} headings. (These were inadvertently left unstaged
when the mdc.config.ts removal was committed.)
After the renderer-alignment work changed copy_node_red.js/copy_blog.js and
related rehype plugins, regenerated content now matches the upstream source
files in src/node-red and src/blog. The dropped mqtt Dynamic-Control-Operations
sections never existed in src/node-red/flowfuse/mqtt/mqtt-{in,out}.md (verified
absent on origin/main too), so the regeneration corrects hallucinated content
from an earlier interim copy run. integrations.index.json reflects fresh npm
download counts.
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.

Migrate website from 11ty to Nuxt

3 participants