Skip to content

feat(vue): add @modular-vue/runtime registry (PR-21) - #63

Merged
kibertoad merged 3 commits into
mainfrom
feat/vue-router-runtime-registry-pr21
Jul 6, 2026
Merged

feat(vue): add @modular-vue/runtime registry (PR-21)#63
kibertoad merged 3 commits into
mainfrom
feat/vue-router-runtime-registry-pr21

Conversation

@kibertoad

@kibertoad kibertoad commented Jul 6, 2026

Copy link
Copy Markdown
Owner

What

First half of the vue-router runtime: @modular-vue/runtime (0.1.0). Ports registry.ts from @react-router-modules/runtime: createRegistry with register / registerLazy / use plugin machinery, and an idempotent resolveManifest() that assembles the navigation manifest, slots, module entries + descriptors, and plugin extensions.

React source: packages/react-router-runtime/src/registry.ts.

Implements PR-21 of the Vue support initiative.

Naming

This branch also consolidates the Vue router packages under the existing @modular-vue scope instead of a separate @vue-router-modules scope:

  • @vue-router-modules/core -> @modular-vue/core
  • @vue-router-modules/runtime -> @modular-vue/runtime

Vue has a single router (vue-router), so a router-named scope carries no disambiguating information the way it does on the React side, where @react-router-modules and @tanstack-react-modules distinguish two real router integrations. Folding into @modular-vue drops a namespace and sits these packages beside the existing @modular-vue/vue and @modular-vue/testing. Names are unprefixed (core/runtime, not router-core/router-runtime): the router-neutral core already lives at @modular-frontend/core, so there is no @modular-vue/core framework-alias to collide with. Decision D1 in the tracker records this. The rename spans the already-merged core package (PR-20) as well as this runtime package; both are unpublished, so there are no consumers to migrate.

Scope / boundary

Validation and the deps snapshot reuse the neutral @modular-frontend/core helpers directly (validateNoDuplicateIds, validateDependencies, validateEntryExitShape, buildDepsSnapshot). The idempotency contract (first call captures options + caches; later calls return the cache and reject options) and the onRegister-once / flip-before-throw guard match the React source.

Deferred to later PRs, by design:

  • PR-22: the router-owning resolve() entry, the Providers context component, the router.addRoute() route-builder, and the auth guard. The @modular-vue/vue context.ts note already anticipates this ("the runtime plugin (PR-22) provides it at the app root"). So resolveManifest() returns the resolved data surface (navigation, slots, modules, moduleDescriptors, extensions + the journeys alias, onModuleExit, recalculateSlots) but not Providers / routes. plugin.providers() (provider-stack contribution) is deferred with the stack.
  • PR-30 / PR-32: the real Vue journeys plugin. It doesn't exist yet, so the registry's plugin machinery is exercised here with a synthetic journeys-shaped plugin (registry-plugins.test.ts) covering extend / validate / contributeNavigation / onResolve, the .extensions bag, the .journeys alias, duplicate-name and method-collision guards, and launcher nav contribution.

RegistryConfig is re-exported from @modular-frontend/core (its Store<T> bucket already covers zustand and the core store), so the runtime doesn't redeclare a zustand-typed copy the way the React runtime does.

Tests

30 tests:

  • registry.test.ts (17): assembly, validation, onRegister-once, idempotency, recalculateSlots no-op vs live, onModuleExit forwarding, moduleDescriptors.
  • registry-plugins.test.ts (9): plugin machinery via the synthetic plugin.
  • registry.test-d.ts (4): plugin-extend intersection, base-surface exclusion, extensions typing, journeys-alias-never.

Full workspace typecheck and vite build (JS + dts) pass; externals (vue, vue-router, @modular-frontend/core, @modular-vue/vue, @modular-vue/core) stay unbundled. Tracker status board and PR-21 writeup updated in the same commit.

Summary by CodeRabbit

  • New Features

    • Added a new Vue router runtime package with registry-based module registration, manifest resolution, plugin support, and navigation/slot handling.
    • Introduced type-safe runtime APIs and test coverage for the new package.
  • Documentation

    • Updated Vue and router docs to use the new @modular-vue/* package naming.
    • Added documentation for the new runtime package and refreshed Vue initiative planning/tracking notes.
  • Chores

    • Renamed published package references from the old namespace to @modular-vue/*.

Port registry.ts from @react-router-modules/runtime as the first half of the
vue-router runtime: createRegistry with register/registerLazy/use plugin
machinery and an idempotent resolveManifest that assembles navigation, slots,
module descriptors, and plugin extensions. Validation and the deps snapshot
reuse the neutral @modular-frontend/core helpers directly.

The router-owning resolve() entry, the Providers context component, and the
router.addRoute() route-builder are deferred to PR-22, matching the boundary
the @modular-vue/vue context.ts note already anticipates. The real Vue journeys
plugin lands in PR-30/PR-32, so plugin machinery is covered here with a
synthetic journeys-shaped plugin (registry-plugins.test.ts).

React source: packages/react-router-runtime/src/registry.ts

30 tests (registry.test.ts, registry-plugins.test.ts, registry.test-d.ts);
workspace typecheck (120 tasks) and vite build (JS + dts) pass. Updates the
Vue support tracker status board and PR-21 writeup.
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Renames the vue-router package family from @vue-router-modules/* to @modular-vue/* across docs and the vue-router-core package, and adds a new @modular-vue/runtime package implementing a plugin-extensible module registry with typed manifest resolution, navigation/slot assembly, and accompanying tests, README, and build configuration.

Changes

Package Rename

Layer / File(s) Summary
Documentation and package naming
docs/vue-port-analysis.md, docs/vue-support-tracker.md, packages/vue-router-core/README.md, packages/vue-router-core/package.json, packages/vue-router-core/src/index.test.ts, packages/vue-router-core/src/route-meta.ts, packages/vue/README.md
All @vue-router-modules/* references, including package name, imports, install commands, and test descriptions, are renamed to @modular-vue/* across docs and vue-router-core.

New @modular-vue/runtime Package

Layer / File(s) Summary
Runtime type contracts
packages/vue-router-runtime/src/types.ts
Defines ModuleExitEvent, ResolveManifestOptions, ResolvedManifest, and re-exports shared registry/navigation types from @modular-frontend/core.
Module registry implementation
packages/vue-router-runtime/src/registry.ts
Implements createRegistry() with ModuleRegistry interface: eager/lazy module registration, plugin attachment via use(), assembly validation, lifecycle hooks, navigation/slot building, and idempotent resolveManifest().
Barrel exports
packages/vue-router-runtime/src/index.ts
Re-exports createRegistry, registry types, shared core helpers, and Vue slot-signal utilities.
Registry and plugin tests
packages/vue-router-runtime/src/registry.test.ts, packages/vue-router-runtime/src/registry.test-d.ts, packages/vue-router-runtime/src/registry-plugins.test.ts
Adds Vitest and type-level tests covering module registration, dependency validation, manifest idempotency, slot recalculation, plugin extend/navigation contribution, and error aggregation.
Package metadata and build config
packages/vue-router-runtime/package.json, packages/vue-router-runtime/tsconfig.json, packages/vue-router-runtime/vite.config.ts, packages/vue-router-runtime/vitest.config.ts, packages/vue-router-runtime/README.md
Adds package manifest, TypeScript config, Vite library build config, Vitest typecheck config, and README documenting the new package.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • kibertoad/modular-react#57: Updates the same docs/vue-support-tracker.md and packages/vue/README.md files to realign package naming to @modular-vue/*.
  • kibertoad/modular-react#61: Updates the same packages/vue-router-core artifacts (package.json, README.md, index.test.ts, route-meta.ts) renaming @vue-router-modules/core to @modular-vue/core.

Suggested reviewers: casamitjana

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding the @modular-vue/runtime registry for Vue.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vue-router-runtime-registry-pr21

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.

- use() collision guard: check Object.hasOwn(registry, key) instead of
  `key in registry`, so a plugin contributing a method named after an
  Object.prototype key (toString, hasOwnProperty, valueOf, ...) is no
  longer falsely rejected. Adds a covering test.
- registerLazy: warn (dev only) when lazy modules are registered, since
  route grafting is deferred to PR-22 and they otherwise contribute
  nothing to the resolved manifest with no diagnostic. Adds a covering
  test asserting the modules are absent but the warning fires.
- CommonAssembly doc comment now lists every field carried inert for
  PR-22 (stores/services/reactiveServices as well as slotsSignal/
  dynamicSlotFactories/slotFilter), so they no longer read as accidental
  dead code.
@kibertoad kibertoad changed the title feat(vue): add @vue-router-modules/runtime registry (PR-21) feat(vue): add @modular-vue/router-runtime registry (PR-21) Jul 6, 2026
@kibertoad kibertoad changed the title feat(vue): add @modular-vue/router-runtime registry (PR-21) feat(vue): add @modular-vue/runtime registry (PR-21) Jul 6, 2026
Rename @vue-router-modules/{core,runtime} to @modular-vue/{core,runtime}.
Vue has a single router (vue-router), so a router-named scope carries no
disambiguating information the way @react-router-modules vs
@tanstack-react-modules does on the React side. Folding into @modular-vue
drops a namespace and sits these packages beside @modular-vue/vue and
@modular-vue/testing.

Names stay unprefixed (core/runtime, not router-core/router-runtime): the
router-neutral core already lives at @modular-frontend/core, so there is no
@modular-vue/core framework-alias to collide with.

Updates package names and deps, source imports and error prefixes, both
package READMEs, packages/vue/README.md, the tracker (D1 decision + package
map) and port-analysis, and regenerates the lockfile. Both packages are
unpublished, so there are no consumers to migrate.
@kibertoad
kibertoad merged commit e394b25 into main Jul 6, 2026
12 of 13 checks passed
@kibertoad
kibertoad deleted the feat/vue-router-runtime-registry-pr21 branch July 6, 2026 14:32

@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.

Actionable comments posted: 4

🤖 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.

Inline comments:
In `@docs/vue-port-analysis.md`:
- Line 41: The package name row in the Vue port analysis uses invented
router-prefixed names, which conflicts with the standardized naming used
elsewhere in the PR. Update the text in this section to use the actual package
names referenced by the rest of the document—@modular-vue/core,
`@modular-vue/runtime`, `@modular-vue/testing`, and `@modular-vue/cli`—so the naming
stays consistent and searchable.

In `@docs/vue-support-tracker.md`:
- Around line 28-36: The support-tracker table currently mixes released and
deferred Vue APIs, so update the map in the docs to separate what has already
shipped from what is still planned. Adjust the entries for `@modular-vue/testing`
and `@modular-vue/runtime` so deferred items like renderJourney, route-builder,
app/providers plugin, and zones are either moved into a later-phase section or
clearly marked as end-state only. Keep the same package names and mirrors, but
make the phase boundaries explicit so the tracker reflects actual delivery
status.

In `@packages/vue-router-runtime/README.md`:
- Around line 22-31: Update the Registry documentation in README to explicitly
state the current limitation of registry.registerLazy(descriptor) and
Registry.resolveManifest(options?): lazy registrations are validated but do not
yet contribute to the resolved manifest (navigation, moduleDescriptors, or other
outputs) until the router-building work lands. Keep the existing references to
registry.register, registry.registerLazy, registry.use, and resolveManifest, but
add a clear caveat that lazy entries currently contribute nothing in
packages/vue-router-runtime/src/registry.ts so readers do not assume they are
included today.
- Around line 12-16: The installation section in README should make it clear
that installing `@modular-vue/runtime` alone is not sufficient because vue,
vue-router, `@modular-frontend/core`, `@modular-vue/core`, and `@modular-vue/vue` are
peer dependencies. Update the install guidance in the README so it either shows
the full installation command including those peer packages or explicitly states
that they must already be installed before using the runtime package. Use the
package.json peerDependencies list and the Installation section as the locations
to update.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3b95a3e5-180a-4554-8db0-70dd4771314d

📥 Commits

Reviewing files that changed from the base of the PR and between c876cc3 and a031588.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • docs/vue-port-analysis.md
  • docs/vue-support-tracker.md
  • packages/vue-router-core/README.md
  • packages/vue-router-core/package.json
  • packages/vue-router-core/src/index.test.ts
  • packages/vue-router-core/src/route-meta.ts
  • packages/vue-router-runtime/README.md
  • packages/vue-router-runtime/package.json
  • packages/vue-router-runtime/src/index.ts
  • packages/vue-router-runtime/src/registry-plugins.test.ts
  • packages/vue-router-runtime/src/registry.test-d.ts
  • packages/vue-router-runtime/src/registry.test.ts
  • packages/vue-router-runtime/src/registry.ts
  • packages/vue-router-runtime/src/types.ts
  • packages/vue-router-runtime/tsconfig.json
  • packages/vue-router-runtime/vite.config.ts
  • packages/vue-router-runtime/vitest.config.ts
  • packages/vue/README.md

Comment thread docs/vue-port-analysis.md
- The class-based error boundary → a small wrapper component using `onErrorCaptured`.
- Zone/slot rendering → `<component :is>` over the contribution lists.
3. `@vue-router-modules/{core,runtime,testing,cli}` (~2.5-3k LOC): the router bridge. This is where Vue is actively easier than either existing family:
3. `@modular-vue/{router-core,router-runtime,testing,router-cli}` (~2.5-3k LOC): the router bridge. This is where Vue is actively easier than either existing family:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the actual package names here.

This row still invents router-* package names, but the rest of the PR standardizes on @modular-vue/core / runtime / testing / cli. Keeping one naming scheme avoids search and migration confusion.

🤖 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 `@docs/vue-port-analysis.md` at line 41, The package name row in the Vue port
analysis uses invented router-prefixed names, which conflicts with the
standardized naming used elsewhere in the PR. Update the text in this section to
use the actual package names referenced by the rest of the
document—@modular-vue/core, `@modular-vue/runtime`, `@modular-vue/testing`, and
`@modular-vue/cli`—so the naming stays consistent and searchable.

Comment on lines +28 to +36
| New package | Mirrors | Contents |
| --------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@modular-vue/vue` | `@modular-react/react` | Injection keys and providers (modules, navigation, slots), store composables, scoped-store composable, error-capture wrapper, entry resolution via `defineAsyncComponent`, module-exit |
| `@modular-vue/journeys` | React parts of `@modular-react/journeys` | Journey provider, instance composables, outlet, module-tab, wait-for-exit |
| `@modular-vue/compositions` | React parts of `@modular-react/compositions` | Composition provider, composables, outlet |
| `@modular-vue/testing` | `@modular-react/testing` + `@react-router-modules/testing` | `resolveModule`, `createMockStore`, `preloadEntries`, `renderModule`, `renderJourney`, mock store (Vue folds both React testing packages into one) |
| `@modular-vue/core` | `@react-router-modules/core` | `defineModule` (with `createRoutes(): RouteRecordRaw[]`), `defineSlots`, shared composable context, scoped store, types |
| `@modular-vue/runtime` | `@react-router-modules/runtime` | Registry, route-builder, app/providers as a Vue plugin, zones, active-zones, route-data |
| `@modular-vue/cli` | `@react-router-modules/cli` | `cli-core` preset + SFC templates |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Split the target map by phase.

This table now mixes shipped and deferred APIs: @modular-vue/testing lists renderJourney, but PR-24 below says it lands with PR-32, and the runtime row includes route-builder / app-shell / zones that PR-22/23 still defer. Split the row or rename this as an eventual end-state map so the tracker doesn't read like those APIs already shipped.

🤖 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 `@docs/vue-support-tracker.md` around lines 28 - 36, The support-tracker table
currently mixes released and deferred Vue APIs, so update the map in the docs to
separate what has already shipped from what is still planned. Adjust the entries
for `@modular-vue/testing` and `@modular-vue/runtime` so deferred items like
renderJourney, route-builder, app/providers plugin, and zones are either moved
into a later-phase section or clearly marked as end-state only. Keep the same
package names and mirrors, but make the phase boundaries explicit so the tracker
reflects actual delivery status.

Comment on lines +12 to +16
## Installation

```bash
npm install @modular-vue/runtime
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

List the peer deps in the install step.

package.json declares vue, vue-router, @modular-frontend/core, @modular-vue/core, and @modular-vue/vue as peers, so npm install @modular-vue/runtime`` by itself is not a complete setup for a fresh app. Please either show the full install command or call out that those packages must already be present. Based on packages/vue-router-runtime/package.json, these packages are peers.

🤖 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-router-runtime/README.md` around lines 12 - 16, The installation
section in README should make it clear that installing `@modular-vue/runtime`
alone is not sufficient because vue, vue-router, `@modular-frontend/core`,
`@modular-vue/core`, and `@modular-vue/vue` are peer dependencies. Update the
install guidance in the README so it either shows the full installation command
including those peer packages or explicitly states that they must already be
installed before using the runtime package. Use the package.json
peerDependencies list and the Installation section as the locations to update.

Comment on lines +22 to +31
- **`registry.register(module)`** / **`registry.registerLazy(descriptor)`** —
register eager and lazily-loaded modules.
- **`registry.use(plugin)`** — attach a plugin; its `extend` surface is
intersected onto the returned registry reference, so contributed methods
(e.g. a future `registerJourney`) are typed on the same object.
- **`registry.resolveManifest(options?)`** — resolve all modules into a
`ResolvedManifest`: `navigation`, `slots`, `modules`, `moduleDescriptors`,
plugin `extensions` (+ the `journeys` alias), `onModuleExit`, and
`recalculateSlots`. Idempotent — the first call does the work and caches the
result; later calls return it and must pass no options.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify the lazy-module limitation.

registerLazy() is currently validated but intentionally omitted from resolveManifest() until the router-building PR lands, so this wording reads as if lazy registrations already contribute to navigation / moduleDescriptors. Please note the current caveat explicitly. Based on packages/vue-router-runtime/src/registry.ts, lazy registrations currently contribute nothing to the resolved manifest until PR-22.

🤖 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-router-runtime/README.md` around lines 22 - 31, Update the
Registry documentation in README to explicitly state the current limitation of
registry.registerLazy(descriptor) and Registry.resolveManifest(options?): lazy
registrations are validated but do not yet contribute to the resolved manifest
(navigation, moduleDescriptors, or other outputs) until the router-building work
lands. Keep the existing references to registry.register, registry.registerLazy,
registry.use, and resolveManifest, but add a clear caveat that lazy entries
currently contribute nothing in packages/vue-router-runtime/src/registry.ts so
readers do not assume they are included today.

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.

1 participant