Skip to content

refactor(runtime-vapor): simplify slot fallback model#14899

Draft
edison1105 wants to merge 12 commits into
minorfrom
edison/slot-simplify-model
Draft

refactor(runtime-vapor): simplify slot fallback model#14899
edison1105 wants to merge 12 commits into
minorfrom
edison/slot-simplify-model

Conversation

@edison1105
Copy link
Copy Markdown
Member

@edison1105 edison1105 commented Jun 1, 2026

Remove the carrier/fallback outlet model and make slot fallback switching rely on
slot boundary state directly. Gate fallback rechecks behind compiler-emitted
slot-root flags, including forwarded Vapor slots, so inactive branches detach
cleanly while only root slot branches notify parent boundaries.

Summary by CodeRabbit

Release Notes

  • Refactor
    • Improved slot fallback handling and root detection for conditional and loop content in slots.
    • Refactored dynamic component configuration to use a unified flags-based API.
    • Enhanced slot fragment management with explicit state tracking for fallback lifecycle.

Remove the carrier/fallback outlet model and make slot fallback switching rely on
the slot boundary state directly. Gate slot dirty tracking behind compiler-emitted
slot-root flags so only root v-if/v-for/slot/dynamic component branches register
fallback rechecks.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 38e6a6eb-2420-4e52-93c7-838e59886153

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.04% 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
Title check ✅ Passed The PR title "refactor(runtime-vapor): simplify slot fallback model" clearly and concisely describes the main change: simplifying slot fallback handling by removing the carrier/outlet model.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch edison/slot-simplify-model

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

Size Report

Bundles

File Size Gzip Brotli
compiler-dom.global.prod.js 86.5 kB 30.3 kB 26.6 kB
runtime-dom.global.prod.js 113 kB 42.6 kB 38.2 kB
vue.global.prod.js 172 kB 62.4 kB 55.6 kB

Usages

Name Size Gzip Brotli
createApp (CAPI only) 51.6 kB 20.1 kB 18.3 kB
createApp 60.6 kB 23.5 kB 21.3 kB
createApp + vaporInteropPlugin 105 kB (-715 B) 37.9 kB (-204 B) 34.2 kB (-246 B)
createVaporApp 29.2 kB (+52 B) 11.2 kB (-2 B) 10.3 kB (+22 B)
createSSRApp 65.1 kB 25.3 kB 22.9 kB
createVaporSSRApp 35.5 kB (+51 B) 13.4 kB (+7 B) 12.3 kB (+16 B)
defineCustomElement 67.2 kB 25.5 kB 23.1 kB
defineVaporCustomElement 40.5 kB (-761 B) 14.4 kB (-300 B) 13.3 kB (-279 B)
overall 75.9 kB 28.9 kB 26.2 kB

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 1, 2026

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@14899
npm i https://pkg.pr.new/@vue/compiler-core@14899
yarn add https://pkg.pr.new/@vue/compiler-core@14899.tgz

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@14899
npm i https://pkg.pr.new/@vue/compiler-dom@14899
yarn add https://pkg.pr.new/@vue/compiler-dom@14899.tgz

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@14899
npm i https://pkg.pr.new/@vue/compiler-sfc@14899
yarn add https://pkg.pr.new/@vue/compiler-sfc@14899.tgz

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@14899
npm i https://pkg.pr.new/@vue/compiler-ssr@14899
yarn add https://pkg.pr.new/@vue/compiler-ssr@14899.tgz

@vue/compiler-vapor

pnpm add https://pkg.pr.new/@vue/compiler-vapor@14899
npm i https://pkg.pr.new/@vue/compiler-vapor@14899
yarn add https://pkg.pr.new/@vue/compiler-vapor@14899.tgz

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@14899
npm i https://pkg.pr.new/@vue/reactivity@14899
yarn add https://pkg.pr.new/@vue/reactivity@14899.tgz

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@14899
npm i https://pkg.pr.new/@vue/runtime-core@14899
yarn add https://pkg.pr.new/@vue/runtime-core@14899.tgz

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@14899
npm i https://pkg.pr.new/@vue/runtime-dom@14899
yarn add https://pkg.pr.new/@vue/runtime-dom@14899.tgz

@vue/runtime-vapor

pnpm add https://pkg.pr.new/@vue/runtime-vapor@14899
npm i https://pkg.pr.new/@vue/runtime-vapor@14899
yarn add https://pkg.pr.new/@vue/runtime-vapor@14899.tgz

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@14899
npm i https://pkg.pr.new/@vue/server-renderer@14899
yarn add https://pkg.pr.new/@vue/server-renderer@14899.tgz

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@14899
npm i https://pkg.pr.new/@vue/shared@14899
yarn add https://pkg.pr.new/@vue/shared@14899.tgz

vue

pnpm add https://pkg.pr.new/vue@14899
npm i https://pkg.pr.new/vue@14899
yarn add https://pkg.pr.new/vue@14899.tgz

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@14899
npm i https://pkg.pr.new/@vue/compat@14899
yarn add https://pkg.pr.new/@vue/compat@14899.tgz

commit: d739b9e

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/runtime-vapor/src/fragment.ts (1)

979-1051: 💤 Low value

Complex recheck logic with multiple branching paths.

The recheckSlotFallback function handles many state combinations. The logic appears correct, but the deep nesting and multiple conditional paths make it difficult to follow. Consider adding inline comments explaining each major branch for future maintainability.

The current implementation correctly handles:

  • Early return when rendering fallback
  • Content validity transitions
  • Fallback insertion/detachment based on validity changes
  • Recursive recheck after pending updates
🤖 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/runtime-vapor/src/fragment.ts` around lines 979 - 1051, The
recheckSlotFallback function contains multiple complex branches (referencing
state.isRenderingFallback, state.activeFallback, isValidBlock,
state.isContentValid, clearSlotFallback, insertActiveSlotFallback,
renderSlotFallbackState, commitSlotFallback, state.pendingRecheck,
state.syncNodes, and state.notifyFallbackValidityChange); add concise inline
comments at each major decision point to explain intent and key transitions
(early return when isRenderingFallback, the content-valid fast-path that syncs
nodes, the contentValid vs fallback branches that detach or insert fallback
blocks, the force/render path that calls renderSlotFallbackState and possibly
recurses when pendingRecheck, and the final sync + notify step) so future
readers can quickly understand why each branch exists and what state changes it
performs.
🤖 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/runtime-vapor/src/fragment.ts`:
- Around line 979-1051: The recheckSlotFallback function contains multiple
complex branches (referencing state.isRenderingFallback, state.activeFallback,
isValidBlock, state.isContentValid, clearSlotFallback, insertActiveSlotFallback,
renderSlotFallbackState, commitSlotFallback, state.pendingRecheck,
state.syncNodes, and state.notifyFallbackValidityChange); add concise inline
comments at each major decision point to explain intent and key transitions
(early return when isRenderingFallback, the content-valid fast-path that syncs
nodes, the contentValid vs fallback branches that detach or insert fallback
blocks, the force/render path that calls renderSlotFallbackState and possibly
recurses when pendingRecheck, and the final sync + notify step) so future
readers can quickly understand why each branch exists and what state changes it
performs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 245f1ef3-0135-4911-b6f4-37adf66082a9

📥 Commits

Reviewing files that changed from the base of the PR and between 9691bc5 and 086caa3.

⛔ Files ignored due to path filters (11)
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/TransformTransition.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/logicalIndex.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/transformKey.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/transformSlotOutlet.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/vIf.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap is excluded by !**/*.snap
  • packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (25)
  • packages/compiler-vapor/__tests__/transforms/transformSlotOutlet.spec.ts
  • packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts
  • packages/compiler-vapor/src/generators/block.ts
  • packages/compiler-vapor/src/generators/component.ts
  • packages/compiler-vapor/src/generators/for.ts
  • packages/compiler-vapor/src/generators/if.ts
  • packages/compiler-vapor/src/generators/slotOutlet.ts
  • packages/compiler-vapor/src/ir/index.ts
  • packages/runtime-core/src/apiCreateApp.ts
  • packages/runtime-vapor/__tests__/apiCreateDynamicComponent.spec.ts
  • packages/runtime-vapor/__tests__/componentAttrs.spec.ts
  • packages/runtime-vapor/__tests__/componentSlots.spec.ts
  • packages/runtime-vapor/__tests__/dom/prop.spec.ts
  • packages/runtime-vapor/__tests__/hydration.spec.ts
  • packages/runtime-vapor/__tests__/scopeId.spec.ts
  • packages/runtime-vapor/__tests__/vdomInterop.spec.ts
  • packages/runtime-vapor/src/apiCreateDynamicComponent.ts
  • packages/runtime-vapor/src/apiCreateFor.ts
  • packages/runtime-vapor/src/apiCreateIf.ts
  • packages/runtime-vapor/src/apiDefineAsyncComponent.ts
  • packages/runtime-vapor/src/block.ts
  • packages/runtime-vapor/src/componentSlots.ts
  • packages/runtime-vapor/src/fragment.ts
  • packages/runtime-vapor/src/vdomInterop.ts
  • packages/shared/src/vaporFlags.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/runtime-vapor/src/vdomInterop.ts (1)

1490-1505: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't move the content branch when fallback is active.

On reinsert, this always moves contentState.rendered and then inserts activeFallback. If recheckSlotFallback() already detached the content branch, internals.m()/insert() will reattach that inactive branch during a move or KeepAlive activation.

Suggested fix
     } else {
-      if (isVNode(contentState.rendered)) {
+      if (fallbackState.activeFallback) {
+        insertActiveSlotFallback(fallbackState)
+      } else if (isVNode(contentState.rendered)) {
         // move vdom content
         internals.m(
           contentState.rendered,
           parentNode,
           anchor,
@@
       } else if (contentState.rendered) {
         // move vapor content
         insert(contentState.rendered, parentNode, anchor)
       }
-
-      insertActiveSlotFallback(fallbackState)
     }
🤖 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/runtime-vapor/src/vdomInterop.ts` around lines 1490 - 1505, The
current reinsert always moves/attaches contentState.rendered via internals.m or
insert then calls insertActiveSlotFallback; change it to skip moving/reattaching
the content branch when the slot fallback is active or when
recheckSlotFallback() indicates the content was detached: before calling
internals.m(contentState.rendered, ...) or insert(contentState.rendered, ...),
call or check recheckSlotFallback(fallbackState) / fallbackState active flag and
only perform the move/insert when that check shows the content branch is still
active; leave insertActiveSlotFallback(fallbackState) as-is so the fallback is
inserted when appropriate.
🤖 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 `@packages/runtime-vapor/src/vdomInterop.ts`:
- Around line 1582-1590: The refreshSlotVNode callback only updates frag.nodes,
leaving fallbackState and frag validity stale; update refreshSlotVNode (the
function passed to trackSlotVNodeUpdatesWithRefresh for hydratedContent) to also
recompute and sync the content validity and block validity: call whatever
updates compute the slot's contentState.valid and fallbackState (so
fallbackState.isContentValid() reflects the new content), and update
frag.isBlockValid() (or recompute frag validity) after
resolveVNodeNodes(hydratedContent) runs; ensure this runs in the same callback
used for trackSlotVNodeUpdatesWithRefresh (and still invokes frag.onUpdated) so
a hydrated slot-root branch that flips valid/invalid on first client update
won't retain the old fallback state.

---

Outside diff comments:
In `@packages/runtime-vapor/src/vdomInterop.ts`:
- Around line 1490-1505: The current reinsert always moves/attaches
contentState.rendered via internals.m or insert then calls
insertActiveSlotFallback; change it to skip moving/reattaching the content
branch when the slot fallback is active or when recheckSlotFallback() indicates
the content was detached: before calling internals.m(contentState.rendered, ...)
or insert(contentState.rendered, ...), call or check
recheckSlotFallback(fallbackState) / fallbackState active flag and only perform
the move/insert when that check shows the content branch is still active; leave
insertActiveSlotFallback(fallbackState) as-is so the fallback is inserted when
appropriate.
🪄 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: 77997f1b-f3b5-4401-bdf6-4831e738e615

📥 Commits

Reviewing files that changed from the base of the PR and between 3ab2a88 and 1729029.

📒 Files selected for processing (8)
  • packages/runtime-vapor/__tests__/componentSlots.spec.ts
  • packages/runtime-vapor/__tests__/vdomInterop.spec.ts
  • packages/runtime-vapor/src/component.ts
  • packages/runtime-vapor/src/componentSlots.ts
  • packages/runtime-vapor/src/components/Transition.ts
  • packages/runtime-vapor/src/components/TransitionGroup.ts
  • packages/runtime-vapor/src/fragment.ts
  • packages/runtime-vapor/src/vdomInterop.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/runtime-vapor/src/fragment.ts

Comment thread packages/runtime-vapor/src/vdomInterop.ts
@edison1105 edison1105 added the scope: vapor related to vapor mode label Jun 1, 2026
@edison1105 edison1105 force-pushed the edison/slot-simplify-model branch from bdc52d2 to d739b9e Compare June 1, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: vapor related to vapor mode

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant