Skip to content

feat(vue): add @modular-vue/nuxt Nuxt 3 integration (PR-52) - #85

Merged
kibertoad merged 3 commits into
mainfrom
claude/nuxt-support-watk2h
Jul 17, 2026
Merged

feat(vue): add @modular-vue/nuxt Nuxt 3 integration (PR-52)#85
kibertoad merged 3 commits into
mainfrom
claude/nuxt-support-watk2h

Conversation

@kibertoad

@kibertoad kibertoad commented Jul 17, 2026

Copy link
Copy Markdown
Owner

What & why

Adds Nuxt 3 support for the @modular-vue family — the last remaining item in the Vue support initiative (docs/vue-support-tracker.md PR-52, and it resolves D6).

Nuxt owns the Vue app and the vue-router instance, so this is the router-owning path over @modular-vue/runtime (registry.resolve()), not framework mode: it grafts every module's createRoutes() subtree onto Nuxt's router via router.addRoute() and installs the modular contexts (shared deps, navigation, slots, modules) on the Nuxt Vue app.

New package packages/vue-nuxt@modular-vue/nuxt 0.1.0 (experimental), with two seams:

  • installModularApp(nuxtApp, registry, options?) — the runtime core. Takes the structural NuxtAppLike ({ vueApp, $router }, which a real NuxtApp satisfies), so the path needs no nuxt/@nuxt/schema runtime dependency and stays unit-testable against a live Vue app + vue-router. Calls registry.resolve({ router: nuxtApp.$router, ...options }), installs the manifest on nuxtApp.vueApp, and returns it. Forwards parentRouteName / authGuard / providers / slotFilter / onModuleExit.
  • A defineNuxtModule default export (configKey: "modularVue") — the zero-config path. Point modularVue.registry at a registry (or per-request factory) export; the module transpiles the package and injects a runtime plugin (addPluginTemplate) that calls installModularApp and exposes the manifest as $modular. The pure plugin-source builder (buildModularPluginContents) is unit-tested standalone.

Design notes:

  • resolve() not resolveManifest(): Nuxt creates the router, so there's no host createRouter({ routes }) to feed resolveManifest().routes into; resolve()'s runtime addRoute() is the exact fit. Under SSR the registry is built per request (fresh app + router per request; resolve() is single-use) — documented, and covered by a test asserting the single-use throw on a reused singleton.
  • First-paint routing: runtime addRoute serves client navigation immediately; a deep-linkable module subtree needs a Nuxt page to graft under (parentRouteName + a shell/catch-all page). Documented in the guide.
  • Build externals: @nuxt/kit and @nuxt/schema are external for both the JS bundle and the dts pass (the NuxtModule<ModuleOptions> annotation references @nuxt/schema).

Also lands: docs/framework-mode-nuxt.md, README package/guides/status entries, the Vue shell-patterns see-also link, the tracker update (PR-52 → done, D6 → resolved), and ci.yml / publish.yml plumbing for the new package. No example app or CI example-shell entry ships here (a Nuxt example would pull the full Nuxt toolchain into the examples workspace + CI matrix); the installer's real behavior is covered by the package suite.

How it was verified

  • pnpm lint passes — 147 typecheck tasks (incl. @modular-vue/nuxt#typecheck), oxfmt --check clean, oxlint reports only pre-existing warnings in other packages (none in vue-nuxt).
  • pnpm test — 19 new tests pass: install.test.ts (8; route grafting, context injection, parentRouteName nesting, auth guard, provider/onModuleExit forwarding, static slots, single-use throw), module.test.ts (8; plugin-source emission incl. factory-unwrap + JSON-escaping, module meta/defaults, setup transpile + addPluginTemplate), index.test.ts (2; barrel), install.test-d.ts (2).
  • vite build produces a clean dist (JS + dts); @nuxt/kit / @nuxt/schema stay unbundled. Full-workspace pnpm build passes.

Checklist

  • pnpm lint passes (typecheck + oxfmt + oxlint).
  • Tests cover the change and pass (pnpm test).
  • Docs / READMEs / tracker updated in the same PR where relevant.
  • Vue impact stated. This is a Vue-only PR (a new @modular-vue/* package); it touches no @modular-frontend/* package and adds no React-binding capability, so no cross-family follow-up is needed.

Release label: this PR pre-sets the new package version (@modular-vue/nuxt@0.1.0), so release-same-version is the appropriate label per the README release-labels table.

🤖 Generated with Claude Code

https://claude.ai/code/session_012nc4TqY91FV1GGJAncBYX6


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added experimental Nuxt 3 integration via @modular-vue/nuxt.
    • Supports automatic route integration, SSR-friendly registry setup, authentication guards, dynamic slots, and custom installation options.
    • Exposes the resolved modular application manifest through Nuxt.
  • Documentation
    • Added Nuxt framework-mode setup guidance, configuration examples, SSR considerations, and troubleshooting notes.
    • Updated project status, package listings, and related documentation links.
  • Tests
    • Added coverage for routing, SSR behavior, installation options, authentication guards, generated plugins, and TypeScript typings.

Add a Nuxt 3 integration for the @modular-vue family. Nuxt owns the Vue
app and the vue-router instance, so this is the router-owning path over
@modular-vue/runtime (registry.resolve()): it grafts every module's
createRoutes() subtree onto Nuxt's router via router.addRoute() and
installs the modular contexts on the Nuxt Vue app.

Two seams:
- installModularApp(nuxtApp, registry, options?) — the runtime core.
  Structural NuxtAppLike ({ vueApp, $router }) so the path takes no
  nuxt/@nuxt/schema runtime dependency and stays unit-testable against a
  real Vue app + vue-router. Forwards parentRouteName / authGuard /
  providers / slotFilter / onModuleExit to resolve().
- A defineNuxtModule default export (configKey "modularVue") — the
  zero-config path. Points modularVue.registry at a registry (or
  factory) export and injects a runtime plugin (addPluginTemplate) that
  calls installModularApp and exposes the manifest as $modular. The pure
  plugin-source builder is unit-tested standalone.

Ships packages/vue-nuxt (@modular-vue/nuxt 0.1.0, experimental) with the
repo's standard build/test skeleton, 19 tests, a framework-mode-nuxt.md
guide, README package/guides/status entries, the shell-patterns see-also
link, and ci.yml / publish.yml plumbing. Resolves D6 and closes PR-52 in
the Vue support tracker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012nc4TqY91FV1GGJAncBYX6
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kibertoad, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1e5b6508-4694-44e3-bc05-87407c30dabe

📥 Commits

Reviewing files that changed from the base of the PR and between 13837a5 and 4fb0998.

📒 Files selected for processing (9)
  • docs/framework-mode-nuxt.md
  • packages/vue-nuxt/README.md
  • packages/vue-nuxt/package.json
  • packages/vue-nuxt/src/index.ts
  • packages/vue-nuxt/src/install.test.ts
  • packages/vue-nuxt/src/install.ts
  • packages/vue-nuxt/src/module.test.ts
  • packages/vue-nuxt/src/module.ts
  • packages/vue-nuxt/vite.config.ts
📝 Walkthrough

Walkthrough

Adds the experimental @modular-vue/nuxt package with a Nuxt module, runtime installer, route grafting, SSR guidance, tests, documentation, and CI/publish integration.

Changes

Nuxt package foundation

Layer / File(s) Summary
Package foundation and exports
packages/vue-nuxt/package.json, packages/vue-nuxt/src/index.ts, packages/vue-nuxt/*config.*
Defines package metadata, public exports, build configuration, test configuration, dependencies, and type-checking setup.
Runtime installer
packages/vue-nuxt/src/install.ts, packages/vue-nuxt/src/install.test.ts, packages/vue-nuxt/src/install.test-d.ts
Adds installModularApp, forwarding route, guard, provider, slot, and exit options into registry.resolve(), installing the manifest into the Vue app, and validating runtime and type behavior.
Nuxt module generation
packages/vue-nuxt/src/module.ts, packages/vue-nuxt/src/module.test.ts
Adds serializable Nuxt configuration, generated plugin contents, registry factory support, transpilation setup, and module registration tests.
Integration documentation
packages/vue-nuxt/README.md, docs/framework-mode-nuxt.md, docs/shell-patterns-vue-router.md
Documents Nuxt setup, router ownership, SSR registry requirements, route grafting, installer options, and related guides.

Release wiring

Layer / File(s) Summary
Package discovery and project status
.github/workflows/*, README.md, docs/vue-support-tracker.md
Adds the Nuxt package to changed-package detection, publishing matrices, project package listings, framework guides, and support tracking.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Nuxt
  participant ModularNuxtModule
  participant installModularApp
  participant Registry
  participant VueRouter
  Nuxt->>ModularNuxtModule: load modularVue configuration
  ModularNuxtModule->>installModularApp: invoke generated plugin
  installModularApp->>Registry: resolve with Nuxt router
  Registry->>VueRouter: add module routes
  installModularApp-->>Nuxt: provide modular manifest
Loading

Possibly related PRs

Suggested labels: minor

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding the new @modular-vue/nuxt Nuxt 3 integration package.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/nuxt-support-watk2h

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/vue-nuxt/src/install.ts (2)

108-115: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a runtime check for $router presence.

In Nuxt 3, the $router property is only injected if the pages/ directory exists or if Vue Router is explicitly configured. If a user installs this module without configuring Nuxt for routing, nuxtApp.$router will be undefined, causing registry.resolve to throw a cryptic error when it attempts to call addRoute.

Adding a fail-fast check improves the developer experience.

🛡️ Proposed fix to validate router
+  if (!nuxtApp.$router) {
+    throw new Error(
+      "installModularApp requires a Nuxt app with vue-router (e.g., a pages/ directory must exist)."
+    );
+  }
+
   const manifest = registry.resolve({
     router: nuxtApp.$router,
     parentRouteName: options?.parentRouteName,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/vue-nuxt/src/install.ts` around lines 108 - 115, In the install flow
before calling registry.resolve, validate that nuxtApp.$router exists and fail
fast with a clear configuration error when it is absent. Preserve the existing
resolve options and behavior when the router is available.

108-115: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a runtime fail-fast check for $router.

In Nuxt 3, the $router property is only injected if the pages/ directory exists or if Vue Router is explicitly configured. If a user installs this module without configuring Nuxt for routing, nuxtApp.$router will be undefined, causing registry.resolve to throw a cryptic error when it attempts to invoke addRoute.

Adding an explicit runtime check helps developers quickly identify the misconfiguration.

🛡️ Proposed fix to validate router presence
+  if (!nuxtApp.$router) {
+    throw new Error(
+      "installModularApp requires a Nuxt app with vue-router (e.g., a pages/ directory must exist)."
+    );
+  }
+
   const manifest = registry.resolve({
     router: nuxtApp.$router,
     parentRouteName: options?.parentRouteName,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/vue-nuxt/src/install.ts` around lines 108 - 115, Before calling
registry.resolve in the install flow, validate that nuxtApp.$router is present
and fail fast with a clear configuration error when it is undefined. Keep
passing the existing router value to registry.resolve for configured
applications, and leave the remaining resolve options unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/vue-nuxt/src/install.ts`:
- Around line 108-115: In the install flow before calling registry.resolve,
validate that nuxtApp.$router exists and fail fast with a clear configuration
error when it is absent. Preserve the existing resolve options and behavior when
the router is available.
- Around line 108-115: Before calling registry.resolve in the install flow,
validate that nuxtApp.$router is present and fail fast with a clear
configuration error when it is undefined. Keep passing the existing router value
to registry.resolve for configured applications, and leave the remaining resolve
options unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6f7645f8-7b88-4827-bae7-65b2d2dec193

📥 Commits

Reviewing files that changed from the base of the PR and between ccebed4 and 13837a5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • .github/workflows/ci.yml
  • .github/workflows/publish.yml
  • README.md
  • docs/framework-mode-nuxt.md
  • docs/shell-patterns-vue-router.md
  • docs/vue-support-tracker.md
  • packages/vue-nuxt/README.md
  • packages/vue-nuxt/package.json
  • packages/vue-nuxt/src/index.test.ts
  • packages/vue-nuxt/src/index.ts
  • packages/vue-nuxt/src/install.test-d.ts
  • packages/vue-nuxt/src/install.test.ts
  • packages/vue-nuxt/src/install.ts
  • packages/vue-nuxt/src/module.test.ts
  • packages/vue-nuxt/src/module.ts
  • packages/vue-nuxt/tsconfig.json
  • packages/vue-nuxt/vite.config.ts
  • packages/vue-nuxt/vitest.config.ts

…registry path

Address review findings on the @modular-vue/nuxt integration:

- Add a runtime-only `./runtime` export (built from `src/install.ts`) and point
  the injected Nuxt plugin — and the own-plugin docs/JSDoc examples — at
  `@modular-vue/nuxt/runtime` instead of the package barrel. The barrel
  re-exports the `defineNuxtModule` default, which eagerly imports `@nuxt/kit`
  (a build-time toolkit); importing the installer from it dragged `@nuxt/kit`
  into the app's client/SSR runtime bundle. The runtime bundle is now
  @nuxt/kit-free.
- Fix the module's default `registry` option from `~/modular.registry` to
  `~/modular/registry`, matching the documented convention everywhere else.

Tests and typecheck updated accordingly; vite emits dist/index.js (barrel) and
dist/runtime.js (installer only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SDNhgjLDRjem9pyJsuoeDU
…etup

Raise docstring coverage over the pre-merge threshold: document the
`install.test.ts` helpers (`newRegistry`, `page`, `routedModule`, `nuxtAppFor`)
as JSDoc and add a docstring to the Nuxt module's `setup` hook. Comments only —
no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SDNhgjLDRjem9pyJsuoeDU

Copy link
Copy Markdown
Owner Author

Pushed follow-ups addressing the review and CI:

Review findings

  • Keep @nuxt/kit out of the app runtime bundle. The injected plugin (and the own-plugin docs/JSDoc examples) imported installModularApp from the package barrel, which re-exports the defineNuxtModule default and eagerly pulls in @nuxt/kit (a build-time toolkit) — dragging it into the client/SSR runtime bundle. Added a runtime-only ./runtime export (built from src/install.ts) and pointed the generated plugin + docs at @modular-vue/nuxt/runtime. Verified: dist/runtime.js has zero @nuxt/kit references; dist/index.js keeps it.
  • Default registry path typo. ~/modular.registry~/modular/registry, matching the documented convention everywhere else (and the test that pinned it).

CI

  • Added the release-same-version label (per the release-labels table this PR notes) — the Ensure PR has proper labeling check is now green. Full suite (build/test on 22.x + 24.x, lint, E2E, examples, catalog) passes.
  • Raised docstring coverage above the pre-merge threshold by documenting the installer test helpers and the module setup hook.

Note: CodeRabbit's review was rate-limited and posted no line findings this run, so there were no review threads to resolve.


Generated by Claude Code

@kibertoad
kibertoad merged commit 04e3d6c into main Jul 17, 2026
18 checks passed
@kibertoad
kibertoad deleted the claude/nuxt-support-watk2h branch July 17, 2026 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants