Skip to content

blueprints: serve /blueprints/ from Nuxt - #5794

Merged
ZJvandeWeg merged 9 commits into
mainfrom
nuxt/blueprints
Sep 17, 2026
Merged

ZJvandeWeg merged 9 commits into
mainfrom
nuxt/blueprints

Conversation

@dimitrieh

@dimitrieh dimitrieh commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Description

Moves /blueprints/ to Nuxt: the paginated library, the detail pages and the submission page.

The blueprints come from the separate FlowFuse/blueprint-library repository, so the build step that pulls them in moves too. nuxt/lib/blueprints-sync.mjs writes the markdown into nuxt/content/blueprints/ and the screenshots into nuxt/public/blueprints/; a Nuxt module runs it during a build or dev start, the way the product docs already work. npm run blueprints keeps its name, so the Build Site workflow is unchanged apart from the path it commits.

The library is private, so the sync resolves its source in precedence order: FLOWFUSE_BLUEPRINTS_LOCAL, a sibling checkout, an authenticated sparse clone, then whatever is already on disk. Only a production deploy that resolves nothing is fatal.

Rebased onto #5694, which landed on 14 September and owns the authenticated clone path.

The listing is ordered by path, descending. Eleventy ordered by date and reversed, but no blueprint README carries a date, so they all fell back to their checkout timestamp and the tie broke on path. The one blueprint that does set a date sorted to the very end there and now sits with its category.

Related Issue(s)

Part of #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)

@netlify

netlify Bot commented Sep 11, 2026

Copy link
Copy Markdown

Deploy Preview for flowfuse-website ready!

Name Link
🔨 Latest commit cf97789
🔍 Latest deploy log https://app.netlify.com/projects/flowfuse-website/deploys/6aabbcf85e807000087b3de7
😎 Deploy Preview https://deploy-preview-5794--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: 47 (🟢 up 16 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.

@dimitrieh

Copy link
Copy Markdown
Contributor Author

Rebased on main, squashed to one commit: the branch's first commit carried leftover conflict markers in legacy.ts that its follow-up removed, and replaying that through a rebase reproduced them. The tree is unchanged from the branch head.

scripts/gen-site-art.py is now scripts/gen-site-art.mjs and nuxt/lib/rich-text.mjs is gone, per the review on #5784. The blueprint descriptions are still rendered with v-html, matching the | safe they had, but they come from READMEs in FlowFuse/blueprint-library rather than from this repo, so they are the one call site whose content is authored elsewhere. Raised on #5784 as well.

Four fixes from the review pass over the whole migration, all in the sync:

  • A library that resolves but holds no blueprints crashed with a raw ENOENT writing the manifest, after writeBlueprints had already deleted both published trees. Only the per-blueprint loop recreated contentDir, so the graceful "no blueprints" path in modules/blueprints-source.ts was unreachable. It now creates the directory after clearing it, with a test.
  • The sync deletes nuxt/content/blueprints and nuxt/public/blueprints before reading the source, and zero entries is the only fatal case. A partially-resolved library (a README renamed upstream, a restructured category) therefore unpublished live pages on a green build with nothing in the log, and the Build Site workflow commits and force-pushes whatever it leaves. It now reads the published set first and names anything being dropped, and names any directory skipped for a missing README. Two tests.
  • injectUpdated prepended updated: unconditionally, so a README that sets its own produced a duplicate YAML key, which fails the schema and drops the page silently.
  • stripLayout's /^layout:.*$/m ran over the whole file, so it could delete a body line beginning layout: when the frontmatter had no such key. It splits frontmatter first now, as rewriteFrontmatterImage does.

Also moved the stories collection comment back above stories: — inserting the blueprints collection had left it describing the wrong collection.

This still needs rebasing onto #5694 once that lands, per the note in #5777.

@dimitrieh

Copy link
Copy Markdown
Contributor Author

Rebased onto main. The conflicts in nuxt/server/middleware/legacy.ts and nuxt/nuxt.config.ts are resolved and CI is green.

Ports the Blueprint Library, the last route group still generated by 11ty.
src/blueprints.njk, src/blueprints/submit.njk and the templates they pulled in
are replaced by pages under nuxt/pages/blueprints/.

The blueprints themselves live in the separate FlowFuse/blueprint-library repo,
so this also moves the build step that brings them in. scripts/copy_blueprints.js
wrote a Nunjucks-shaped tree into src/blueprints/; nuxt/lib/blueprints-sync.mjs
writes the markdown into nuxt/content/blueprints/ and the screenshots and flow
exports into nuxt/public/blueprints/, and nuxt/modules/blueprints-source.ts runs
it during a Nuxt build or dev start the way docs-source does for the product
docs. scripts/sync_blueprints.mjs is the same sync for callers with no Nuxt yet,
which is what the Build Site workflow runs before committing to the `live`
branch Netlify deploys.

The library is private, so unlike the docs there is no clone fallback. Source
precedence is FLOWFUSE_BLUEPRINTS_LOCAL, then a sibling checkout, then the tree
already committed by that workflow. A production build that resolves nothing
fails rather than publishing an empty library.
@@ -0,0 +1,10 @@
<script setup lang="ts">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I thought we already had a CTA component?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We do, but they are all buttons through cta/CtaButton.vue. This one is the one-line text band with an inline link, ported from contact-us-cta-line.njk, so there is no button to share. Renamed it to CtaContactUsLine.vue so it sits with the rest of the family.

The wider point stands though: the teardown branch ends up with thirteen CTA-ish components. Consolidating them touches pages across five of the open migration PRs, so better as its own PR once 5777 is done.

…istry

Keeps the URL in the one place the other Cta* components read it from. The band
stays its own component because it is prose with an inline link rather than a
button through cta/CtaButton.vue, and it stays untracked because the .njk it
ports was.
@dimitrieh

Copy link
Copy Markdown
Contributor Author

There is CtaContactUs, but it is a button: it goes through cta/CtaButton.vue, takes a variant and a position, and fires a tracked event. This one is the band from contact-us-cta-line.njk, an inline link inside a sentence, so it stays separate.

Pushed a change so it at least reads its href from CTA_DESTINATIONS like the other Cta* components. It stays untracked because the .njk it ports was untracked too, so adding an event here would be a behaviour change rather than a port. #5749 is the right place for that if we want it.

The /blueprints registration is in #5815.

Without the prefix the dev middleware keeps proxying to 11ty, so npm run dev
shows the old page. The middleware returns early unless NODE_ENV is development,
which is why CI and the deploy preview both looked correct.
@dimitrieh

Copy link
Copy Markdown
Contributor Author

Correction to my earlier comment: #5815 is closed, the registration belongs in each migration PR instead. Pushed here.

Both glyphs are stock Heroicons, byte-identical to the files SiteArt inlined, so
they go through <UIcon> and the component, its generated util and its generator
script come out. Each call site carries the size the source SVG had.
@dimitrieh

Copy link
Copy Markdown
Contributor Author

Cross-PR pass over the four patterns. Two applied:

  • Custom icon files. chevron-left and rocket-launch are byte-identical to the Heroicons outline glyphs, so they are <UIcon> now and SiteArt.vue, siteArt.ts and gen-site-art.mjs are gone. Each call site keeps the size its source SVG had (w-5 h-5 and size-6), since the mask span has no intrinsic ratio.
  • legacy.ts. /blueprints registered.

This also closes out the open thread on #5792, which asked for gen-site-art not to be python3. It became .mjs there, and on this branch the script is gone entirely.

No useScrollToAnchor here, and no layouts this PR makes dead relative to main.

@dimitrieh dimitrieh mentioned this pull request Sep 16, 2026
5 tasks
@dimitrieh

Copy link
Copy Markdown
Contributor Author

Separate finding from the preview, not from the icon change and not a blocker.

/blueprints/other/mobile-alerting/ logs Hydration completed but contains mismatches. Traced it by diffing the SSR tree against the hydrated DOM: it is the ## Start now heading, whose markdown is a link.

@nuxt/content's prose heading wraps the heading text in its own <a href="#start-now"> anchor. When the heading is itself a link, that nests an <a> inside an <a>, which HTML cannot represent, so the parser splits them when it reads the SSR response while Vue's client render builds the nested structure it intended. The two trees disagree:

  • SSR: <a href="#start-now"></a> then <a href="https://app.flowfuse.com/deploy/blueprint?...">Start now</a>
  • Client: <a href="#start-now">Start now</a> then the deploy link

11ty never did this, so it only shows up now that these render through ContentRenderer.

Sampled the 12 blueprints linked from the index and 1 is affected, so it is narrow: only blueprints whose markdown uses a linked heading. The fix belongs in the blueprint content rather than here (heading and link as separate lines), since the markdown is synced from blueprint-library at build time and is not in this repo.

Flagging rather than fixing, as it is pre-existing to my commits and outside this PR.

@dimitrieh

Copy link
Copy Markdown
Contributor Author

Fix for the hydration mismatch is up: https://github.com/FlowFuse/blueprint-library/pull/182

It was the only linked heading across all 19 blueprints, and the link was dead anyway (blueprintId= with no value) while the page already renders its own Deploy button from the frontmatter. Once that merges and the next build syncs, this page stops logging the mismatch. Nothing needed in this PR.

# Conflicts:
#	nuxt/server/middleware/legacy.ts
@dimitrieh

Copy link
Copy Markdown
Contributor Author

Conflicts resolved, main is merged in. Same shape as the other migration PRs: the registry files take the union, so NUXT_PREFIXES and the prerender list keep both sides and this PR's own route drops out of the "still on 11ty" comment.

# Conflicts:
#	nuxt/server/middleware/legacy.ts
# Conflicts:
#	nuxt/server/middleware/legacy.ts
@ZJvandeWeg
ZJvandeWeg merged commit 98a36e5 into main Sep 17, 2026
7 checks passed
@ZJvandeWeg
ZJvandeWeg deleted the nuxt/blueprints branch September 17, 2026 17:48
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.

2 participants