Skip to content

feat(vue): add @modular-vue/compositions provider, composables, plugin (PR-33) - #72

Merged
kibertoad merged 4 commits into
mainfrom
claude/vuejs-support-next-phase-mbjmkf
Jul 16, 2026
Merged

feat(vue): add @modular-vue/compositions provider, composables, plugin (PR-33)#72
kibertoad merged 4 commits into
mainfrom
claude/vuejs-support-next-phase-mbjmkf

Conversation

@kibertoad

@kibertoad kibertoad commented Jul 16, 2026

Copy link
Copy Markdown
Owner

What

Implements PR-33 of the Vue support initiative — part 1 of Phase 3's compositions work. New packages/vue-compositions (@modular-vue/compositions, 0.1.0), the Vue 3 compositions binding over @modular-frontend/compositions-engine.

React sources ported (named so reviewers can diff intent): packages/compositions/src/provider.tsx, hooks.ts, and plugin.tsx. The composition outlet (outlet.tsx) stays with PR-34.

Contents

  • provider.tsCompositionsProvider / useCompositionsContext / compositionsKey. Provides { runtime } by identity at setup (un-proxied, so identity checks against manifest.extensions.compositions hold); this also gives the React binding's memo-on-runtime fanout guarantee for free. Unlike <JourneyProvider>, it does not compose over <ModuleExitProvider> — composition panels emit via useCompositionEmit, not the global module-exit dispatcher.
  • hooks.ts — panel-side composables reading a per-mount compositionInstanceKey the outlet (PR-34) installs: useCompositionState (reactive), useCompositionDispatch, useCompositionEmit, useCompositionZone, the pre-typed createCompositionContext bundle, and CompositionContextValue.
  • use-composition.ts — host-side useComposition + useCompositionOptions + UseCompositionOptions, including the Symbol.for options brand ported verbatim. Mints once in setup and registers a no-op subscription torn down on scope dispose, so a held id disposes via the runtime's refcount gate even without an outlet.
  • plugin.tscompositionsPlugin() with extend / validate / onResolve and a providers() contributing a Vue <CompositionsProvider>; resolved-twice and register-after-resolve guards match the React source. No contributeNavigation (compositions contribute no nav).

Framework-forced deviations

  • useCompositionState returns a ShallowRef, not the selected value — the reactive-source convention from PR-10 (useStore) / PR-23 (useZones). Callers read .value.
  • No bespoke selector-result cache. React's caches results keyed on state identity to dodge its "getSnapshot should be cached" warning (React calls the selector every render). Vue's setup runs once and the store push is event-driven, so a small shallowRef + store.subscribe bridge (reimplemented locally, as journeys' instance-hooks.ts did) is the faithful analog.
  • useComposition mints once in setup with onScopeDispose instead of React's useRef lazy-init + useEffect (Vue's single setup removes the StrictMode double-invoke hazard).

Tests

30 tests across provider.test.ts (3), hooks.test.ts (9), use-composition.test.ts (5), plugin.test.ts (7), and hooks.test-d.ts (5) — porting the use-composition.test.tsx and selector-dispatch.test.tsx intent (outlet-dependent cases deferred to PR-34; engine-only cases already covered in the engine suite).

  • Full workspace typecheck (124 tasks) ✅
  • vite build (JS + dts) for the new package ✅
  • oxfmt / oxlint clean ✅
  • Externals (vue, @modular-frontend/core, @modular-frontend/compositions-engine, @modular-vue/vue) stay unbundled.

Tracker updated: PR-33 marked done on the status board with a full writeup.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QCgNTenPyTRTU6S8DgovNB


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added the Vue compositions package with provider and plugin support.
    • Added composables for composition state, dispatch, events, zones, and instance management.
    • Added typed composition context helpers and public composition APIs.
    • Added runtime validation and lifecycle handling for registered compositions.
  • Documentation

    • Documented Phase 3 completion and updated the support tracker.
  • Tests

    • Added comprehensive runtime and compile-time coverage for providers, plugins, composables, and lifecycle behavior.

…n (PR-33)

New packages/vue-compositions (@modular-vue/compositions, 0.1.0): the Vue 3
compositions binding, part 1 of Phase 3's compositions work. Ports the React
provider.tsx, hooks.ts, and plugin.tsx over @modular-frontend/compositions-engine;
the composition outlet stays with PR-34.

- provider.ts: CompositionsProvider / useCompositionsContext / compositionsKey.
  Provides { runtime } by identity at setup (un-proxied, so identity checks
  against manifest.extensions.compositions hold), which also gives the React
  binding's memo-on-runtime fanout guarantee for free. Unlike JourneyProvider it
  does not compose over ModuleExitProvider.
- hooks.ts: panel-side composables reading a per-mount compositionInstanceKey the
  outlet (PR-34) installs — useCompositionState (reactive ShallowRef),
  useCompositionDispatch, useCompositionEmit, useCompositionZone, the pre-typed
  createCompositionContext bundle, and CompositionContextValue.
- use-composition.ts: host-side useComposition + useCompositionOptions, with the
  Symbol.for options brand ported verbatim. Mints once in setup and registers a
  no-op subscription torn down on scope dispose, so a held id disposes via the
  runtime's refcount gate without an outlet.
- plugin.ts: compositionsPlugin() with extend/validate/onResolve and a providers()
  contributing a Vue CompositionsProvider; resolved-twice + register-after-resolve
  guards match the React source.

Framework-forced deviations: useCompositionState returns a ShallowRef (reactive-
source convention, PR-10/PR-23) instead of the selected value, and drops React's
getSnapshot-cache since Vue's setup runs once and the store push is event-driven.

Tests: 30 across provider/hooks/use-composition/plugin suites + a hooks.test-d.ts,
porting the use-composition.test.tsx and selector-dispatch.test.tsx intent (outlet-
dependent and engine-only cases deferred/already covered). Full workspace typecheck
(124 tasks) and vite build (JS + dts) pass. Tracker updated: PR-33 marked done.

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

coderabbitai Bot commented Jul 16, 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: 40 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: 70efeaca-3456-4628-9e95-9952ff795f10

📥 Commits

Reviewing files that changed from the base of the PR and between a519d38 and 51105a2.

📒 Files selected for processing (4)
  • docs/vue-support-tracker.md
  • packages/vue-compositions/src/index.ts
  • packages/vue-compositions/src/use-composition.test.ts
  • packages/vue-compositions/src/use-composition.ts
📝 Walkthrough

Walkthrough

Introduces @modular-vue/compositions with Vue runtime providers, registry integration, host and panel composables, typed hooks, package tooling, tests, and updated Phase 3 documentation.

Changes

Vue compositions package

Layer / File(s) Summary
Package setup and public exports
packages/vue-compositions/package.json, packages/vue-compositions/tsconfig.json, packages/vue-compositions/vite.config.ts, packages/vue-compositions/vitest.config.ts, packages/vue-compositions/src/index.ts
Adds package metadata, build and test configuration, and public re-exports for engine, provider, plugin, hook, and host composable APIs.
Runtime provider and registry plugin
packages/vue-compositions/src/provider.ts, packages/vue-compositions/src/plugin.ts, packages/vue-compositions/src/provider.test.ts, packages/vue-compositions/src/plugin.test.ts
Provides stable runtime injection and plugin lifecycle handling for registration, validation, resolution, and Vue provider wiring.
Host composition lifecycle
packages/vue-compositions/src/use-composition.ts, packages/vue-compositions/src/use-composition.test.ts
Adds branded options, runtime resolution, mount-stable instance creation, subscription retention, and scope-based disposal.
Panel hooks and typed context
packages/vue-compositions/src/hooks.ts, packages/vue-compositions/src/hooks.test.ts, packages/vue-compositions/src/hooks.test-d.ts
Adds scoped state, dispatch, emit, zone, and typed context hooks with runtime and compile-time coverage.
Support tracker documentation
docs/vue-support-tracker.md
Documents the completed Vue compositions work and marks PR-33 as done.

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

Sequence Diagram(s)

sequenceDiagram
  participant VueComponent
  participant useComposition
  participant CompositionsProvider
  participant CompositionRuntime
  VueComponent->>CompositionsProvider: resolve runtime context
  VueComponent->>useComposition: bind composition handle and input
  useComposition->>CompositionRuntime: start instance
  CompositionRuntime-->>useComposition: return instance id
  VueComponent->>CompositionRuntime: subscribe for component lifetime
  VueComponent->>CompositionRuntime: unsubscribe on scope disposal
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 50.00% 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 Vue compositions provider, composables, and plugin.
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/vuejs-support-next-phase-mbjmkf

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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/vue-compositions/tsconfig.json (1)

8-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Ensure .test-d.ts files are excluded from the declaration build.

The glob src/**/*.test.* matches files like hooks.test.ts, but it does not match hooks.test-d.ts because the segment before the final extension is test-d, not test. Since rolldown-plugin-dts uses this tsconfig.json to generate the .d.ts outputs for dist/, test definition files could leak into the built package.

♻️ Proposed fix to explicitly exclude both
-  "exclude": ["src/**/*.test.*"]
+  "exclude": ["src/**/*.test.ts", "src/**/*.test-d.ts"]
🤖 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-compositions/tsconfig.json` at line 8, Update the tsconfig
exclude patterns to explicitly exclude both regular test files and TypeScript
declaration test files ending in .test-d.ts, ensuring rolldown-plugin-dts does
not emit them into dist while preserving the existing test-file exclusion.
🤖 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-support-tracker.md`:
- Line 287: Correct the test-count summary in the Vue support tracker entry: the
listed suites total 29 tests, so update the aggregate total or adjust the
per-suite counts to match the verified tests. Keep the suite names and other
acceptance details unchanged.
- Line 376: Update the PR-33 row in the Vue support tracker so its completed
“done” entry includes a link to PR-33, using the repository’s existing PR-link
format.

In `@packages/vue-compositions/src/use-composition.ts`:
- Around line 82-92: Update the public useComposition overloads to require the
branded options type produced by useCompositionOptions(), matching the runtime
checks in the implementation around lines 102-109. Apply this to both the
handle-based and compositionId-based signatures so plain option objects cannot
be mistaken for input; preserve the existing optional-input behavior and
runtime-start flow.

---

Nitpick comments:
In `@packages/vue-compositions/tsconfig.json`:
- Line 8: Update the tsconfig exclude patterns to explicitly exclude both
regular test files and TypeScript declaration test files ending in .test-d.ts,
ensuring rolldown-plugin-dts does not emit them into dist while preserving the
existing test-file exclusion.
🪄 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: bc3a536f-5e47-44e3-bb8d-1675a3e97bad

📥 Commits

Reviewing files that changed from the base of the PR and between 80697e2 and a519d38.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • docs/vue-support-tracker.md
  • packages/vue-compositions/package.json
  • packages/vue-compositions/src/hooks.test-d.ts
  • packages/vue-compositions/src/hooks.test.ts
  • packages/vue-compositions/src/hooks.ts
  • packages/vue-compositions/src/index.ts
  • packages/vue-compositions/src/plugin.test.ts
  • packages/vue-compositions/src/plugin.ts
  • packages/vue-compositions/src/provider.test.ts
  • packages/vue-compositions/src/provider.ts
  • packages/vue-compositions/src/use-composition.test.ts
  • packages/vue-compositions/src/use-composition.ts
  • packages/vue-compositions/tsconfig.json
  • packages/vue-compositions/vite.config.ts
  • packages/vue-compositions/vitest.config.ts

Comment thread docs/vue-support-tracker.md Outdated
Comment thread docs/vue-support-tracker.md Outdated
Comment thread packages/vue-compositions/src/use-composition.ts
@kibertoad kibertoad added the skip-release label Jul 16, 2026 — with Claude
claude added 3 commits July 16, 2026 20:22
…tion

Adds two useComposition cases that exercise the Symbol.for options brand,
which no prior test touched:
- an input shaped like `{ runtime }` (unbranded) is treated as input, not
  options — minting still uses the context runtime, and a decoy runtime on
  the input is never consulted
- a branded `useCompositionOptions({ runtime })` is detected as options
  while the preceding argument is still forwarded to `runtime.start` as input

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

- useComposition overloads now accept only BrandedCompositionOptions (the
  useCompositionOptions() output) instead of a bare UseCompositionOptions.
  A plain positional `{ runtime }` was type-valid but, being unbranded, was
  silently consumed as `input` while the supplied runtime was ignored — the
  type now enforces the same brand the runtime check requires. Exported the
  BrandedCompositionOptions type.
- docs/vue-support-tracker.md: correct the PR-33 test tally (32 across the
  suites: plugin is 8, use-composition is 7) and link the PR (#72) in the
  status board row per the "done (link the PR)" convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S5ZzHx6WVWzuoBk8n1UEJv
@kibertoad
kibertoad merged commit 993f882 into main Jul 16, 2026
13 checks passed
@kibertoad
kibertoad deleted the claude/vuejs-support-next-phase-mbjmkf branch July 16, 2026 20:42
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