Skip to content

Prepare the Nuxt app to move from nuxt/ to the repository root - #5871

Open
ZJvandeWeg wants to merge 9 commits into
mainfrom
prep-flatten-nuxt
Open

ZJvandeWeg wants to merge 9 commits into
mainfrom
prep-flatten-nuxt

Conversation

@ZJvandeWeg

Copy link
Copy Markdown
Member

Description

The Nuxt app lives in nuxt/ only because it had to share the repository with Eleventy. With Eleventy gone (#5795), the plan is to move it to the repository root. This PR does everything that can land before that move, so the move itself is a pure rename plus a mechanical prefix rewrite that is quick to review.

Nothing here changes what the site serves. Each commit stands on its own:

  • handbook changes: survive the move out of nuxt/: adds content/handbook/ as the newest handbook prefix, and skips a rename that only moves a page between prefixes. Without this, the move commit would list every handbook page as "Renamed" on Recent Changes.
  • repo root: find it instead of counting ../ from nuxt/: the two sync modules took the repo root to be dirname(nuxt.options.rootDir), and seven tests used a fixed '../..'. nuxt/lib/repo-root.mjs now finds the closest directory holding package-lock.json, which works on either side of the move and resolves a .claude/worktrees/* worktree to itself.
  • search index: move the helpers into nuxt/lib and switch the scripts to ESM: the root lib/ held one file and would collide with nuxt/lib/. index-algolia and watch_blueprints become .mjs.
  • css: keep the Tailwind config next to the stylesheet that loads it: tailwind.config.js moves into nuxt/, and postcss.config.js becomes .cjs because postcss-cli 9 require()s it.
  • package.json: fold the nuxt workspace into the root: one package.json with "type": "module", and no --workspace=nuxt. Script names are unchanged, because netlify.toml and FlowFuse/github-actions-workflows' build_website call them by name.
  • gitignore: merge nuxt/.gitignore into the root one.
  • guides sync test: build the expected edit URL from GUIDES_SOURCE: it was an escaped regex (nuxt\/content-guides) that a prefix rewrite can't see.
  • css: import the vendor stylesheets by package name: style.css reached node_modules through ../../../, which only holds at exactly that depth.
  • guides sync: date a guide by its last edit, not by a move: the updated timestamp came from git log -1 -- <path>, so moving content-guides/ would stamp all 149 guide pages with the move date. It now follows renames and skips a pure rename. A new test on a scratch git repository pins this. On a full clone of main, all 149 pages get the same date as before.

Verification

  • npm test: 287 pass (283 on main, plus the new tests).
  • Compiled style.css is byte-for-byte identical to main's.
  • build:nuxt:skip-images on this branch and on main, with the same docs and blueprints sources. Both produce the same 6,671 files. After normalising build IDs, timestamps, chunk hashes and the checkout path, every page, payload and sitemap entry matches except things that also vary between two builds of main: the shuffled customer-logo strips, random payload keys, and Shiki class names (token colours checked identical).
  • The Algolia indexer produces byte-identical records (14,094) from the same build with this branch's ESM helpers and with main's CommonJS ones.
  • Dependencies: every package resolves to the same version, except the markdown-it that nuxt/server/utils/integrations-enrich.ts imports, which goes from 14.3.0 to 14.3.2 (patch). The 15.0.0 copy that only satisfied the markdown-it plugins' open peer ranges is gone.
  • npm run dev:nuxt starts from the repo root. Request handling in my environment fails with spawn EBADF exactly as it does on main, so please load a page locally before merging.

The follow-up

The move itself: git mv every entry of nuxt/ to the root, drop the nuxt/ prefix, and make six small edits the prefix rewrite can't express (nuxt dev nuxt → nuxt dev, join(repoRoot, 'nuxt') → repoRoot in three scripts, Studio's rootDir: 'nuxt', two sentences in README/CLAUDE.md). I've done a trial run on top of this branch. It changes 4,611 files, all but 15 of them pure or near-pure renames. Tests pass, and the build matches this branch's except for the expected edit-link and Studio rootDir changes.

Before it can merge:

  1. FlowFuse/github-actions-workflows' build_website.yml names website/nuxt/ for the link check, dist/, and the og-image caches. It needs to resolve the app directory instead, like it already does for src/. That change is ready and waiting for approval to open.
  2. FlowFuse/flowfuse's docs workflow runs its own copy of the build with --sources website/src, which already breaks now that src/ is gone. Preview the website on documentation pull requests flowfuse#8070 replaces it with the shared workflow.
  3. Check the Netlify site settings for a base or publish directory set in the UI rather than in netlify.toml.

Out of scope here, for separate PRs: production still builds with SKIP_IMAGES, which turns Nuxt Image's Netlify provider off. The image-compression workflow's ignorePaths: 'nuxt/**' also covers every image, so it compresses nothing.

Related Issue(s)

Follows #5795.

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)

Add content/handbook/ as the newest handbook prefix and skip a rename that only
moves a page between two prefixes. Without this, the commit that moves the Nuxt
app to the repository root would list every handbook page as renamed in that
week's Recent Changes, and the history under nuxt/content/handbook would drop
out of the log's pathspec.
The Nuxt modules took the repository root to be the parent of the Nuxt root, and
seven tests reached it with a fixed '../..' from nuxt/lib/. Both stop being true
once the app moves to the repository root. nuxt/lib/repo-root.mjs finds the
closest directory holding package-lock.json instead, which is correct on either
side of the move and, for a worktree nested under .claude/worktrees/, resolves to
the worktree rather than the checkout around it.
…o ESM

lib/search-index.js is the only file in the root lib/, which would collide with
nuxt/lib/ once the app moves to the repository root, so it joins the other
plain-JS helpers there. It and the two CommonJS scripts, index-algolia and
watch_blueprints, become ES modules, since the merged package.json will declare
"type": "module" for the whole repository.
tailwind.config.js moves into nuxt/, beside nuxt/assets/css/style.css, the only
file that loads it, so its @config path stays the same when nuxt/ moves to the
repository root. It becomes an ES module and postcss.config.js becomes
postcss.config.cjs, ahead of the merged package.json's "type": "module":
postcss-cli 9 loads its config with require(). The compiled stylesheet is
byte-for-byte unchanged.
nuxt/package.json only existed so Nuxt and Eleventy could keep separate
dependencies. With Eleventy gone it splits one application's dependencies over
two files and routes every Nuxt command through --workspace=nuxt. Its
dependencies move into the root package.json, along with its "type": "module",
and the scripts call nuxt directly with nuxt/ as the root directory. Script
names are unchanged, since FlowFuse/github-actions-workflows' build_website
workflow and netlify.toml call them by name.

Every package resolves to the same version as before except markdown-it: the
copy nuxt/server/utils/integrations-enrich.ts imports goes from 14.3.0 to 14.3.2,
and the 15.0.0 copy that satisfied the markdown-it plugins' open peer ranges is
no longer installed.
A second .gitignore under nuxt/ would collide with the root one when the app
moves up. Its rules are now root rules under nuxt/, grouped with the matching
ones already there. The build-output rules are anchored at nuxt/ rather than
matching at any depth; nothing nested ever used them, and the set of ignored
files in a built checkout is otherwise identical.
It spelled the guides path out as an escaped regex, nuxt\/content-guides, which
a later rewrite of the nuxt/ prefix cannot match. Comparing against a string
built from GUIDES_SOURCE follows the constant wherever the guides live. A comment
in the sitemap route that named the nuxt/ workspace now says the same thing
without naming a layout.
style.css reached two packages' CSS through ../../../node_modules/, a path that
only holds while the stylesheet sits exactly three levels below the repository
root. Importing by package name lets Tailwind resolve node_modules itself, from
wherever the file is. Neither package declares exports, so the deep paths
resolve, and the compiled stylesheet is byte-for-byte unchanged.
A guide's updated timestamp came from the newest commit touching its path, so
moving the guides tree would stamp all 149 guide pages with the date of the move.
It now follows the file back through renames and skips a rename that left it
unchanged, the same rule nuxt/lib/git-lastmod.mjs applies to the sitemap. A move
that also edited the file still dates it. For a guide that never moved, the
result is the same commit as before.
@ZJvandeWeg
ZJvandeWeg requested review from a team and Yndira-E as code owners September 26, 2026 00:44
@netlify

netlify Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for flowfuse-website ready!

Name Link
🔨 Latest commit f6cb696
🔍 Latest deploy log https://app.netlify.com/projects/flowfuse-website/deploys/6ab7157bfcf30a0008c78c25
😎 Deploy Preview https://deploy-preview-5871--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: 49 (🟢 up 17 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.

This branch has not been deployed

No deployments
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