feat(vue): add @modular-vue/compositions provider, composables, plugin (PR-33) - #72
Conversation
…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
|
Warning Review limit reached
Next review available in: 40 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughIntroduces ChangesVue compositions package
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
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/vue-compositions/tsconfig.json (1)
8-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winEnsure
.test-d.tsfiles are excluded from the declaration build.The glob
src/**/*.test.*matches files likehooks.test.ts, but it does not matchhooks.test-d.tsbecause the segment before the final extension istest-d, nottest. Sincerolldown-plugin-dtsuses thistsconfig.jsonto generate the.d.tsoutputs fordist/, 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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (15)
docs/vue-support-tracker.mdpackages/vue-compositions/package.jsonpackages/vue-compositions/src/hooks.test-d.tspackages/vue-compositions/src/hooks.test.tspackages/vue-compositions/src/hooks.tspackages/vue-compositions/src/index.tspackages/vue-compositions/src/plugin.test.tspackages/vue-compositions/src/plugin.tspackages/vue-compositions/src/provider.test.tspackages/vue-compositions/src/provider.tspackages/vue-compositions/src/use-composition.test.tspackages/vue-compositions/src/use-composition.tspackages/vue-compositions/tsconfig.jsonpackages/vue-compositions/vite.config.tspackages/vue-compositions/vitest.config.ts
…next-phase-mbjmkf
…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
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, andplugin.tsx. The composition outlet (outlet.tsx) stays with PR-34.Contents
provider.ts—CompositionsProvider/useCompositionsContext/compositionsKey. Provides{ runtime }by identity at setup (un-proxied, so identity checks againstmanifest.extensions.compositionshold); this also gives the React binding's memo-on-runtimefanout guarantee for free. Unlike<JourneyProvider>, it does not compose over<ModuleExitProvider>— composition panels emit viauseCompositionEmit, not the global module-exit dispatcher.hooks.ts— panel-side composables reading a per-mountcompositionInstanceKeythe outlet (PR-34) installs:useCompositionState(reactive),useCompositionDispatch,useCompositionEmit,useCompositionZone, the pre-typedcreateCompositionContextbundle, andCompositionContextValue.use-composition.ts— host-sideuseComposition+useCompositionOptions+UseCompositionOptions, including theSymbol.foroptions brand ported verbatim. Mints once insetupand 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.ts—compositionsPlugin()withextend/validate/onResolveand aproviders()contributing a Vue<CompositionsProvider>; resolved-twice and register-after-resolve guards match the React source. NocontributeNavigation(compositions contribute no nav).Framework-forced deviations
useCompositionStatereturns aShallowRef, not the selected value — the reactive-source convention from PR-10 (useStore) / PR-23 (useZones). Callers read.value.setupruns once and the store push is event-driven, so a smallshallowRef+store.subscribebridge (reimplemented locally, as journeys'instance-hooks.tsdid) is the faithful analog.useCompositionmints once insetupwithonScopeDisposeinstead of React'suseReflazy-init +useEffect(Vue's singlesetupremoves 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), andhooks.test-d.ts(5) — porting theuse-composition.test.tsxandselector-dispatch.test.tsxintent (outlet-dependent cases deferred to PR-34; engine-only cases already covered in the engine suite).typecheck(124 tasks) ✅vite build(JS + dts) for the new package ✅oxfmt/oxlintclean ✅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
Documentation
Tests