Skip to content

feat(compiler): emit lazy getter for scoped slot props#14494

Open
Mini-ghost wants to merge 1 commit intovuejs:mainfrom
Mini-ghost:feat/compiler-lazy-scoped-slot-props
Open

feat(compiler): emit lazy getter for scoped slot props#14494
Mini-ghost wants to merge 1 commit intovuejs:mainfrom
Mini-ghost:feat/compiler-lazy-scoped-slot-props

Conversation

@Mini-ghost
Copy link
Contributor

@Mini-ghost Mini-ghost commented Feb 28, 2026

Close #4192

Summary by CodeRabbit

  • New Features

    • Added compiler support for computed refs in script setup, improving handling across v-model bindings, template refs, and slot outlet props.
    • Introduced lazy evaluation support for slot props backed by setup bindings.
  • Tests

    • Added comprehensive test coverage for computed binding scenarios in element transforms, expression handling, slot outlets, and v-model usage.

@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

📝 Walkthrough

Walkthrough

This pull request introduces support for SETUP_COMPUTED binding type to the Vue compiler, enabling computed refs to remain lazy when passed via slot props. The feature adds a new enum value, updates codegen to emit getter syntax for lazy evaluation, and modifies multiple compiler transforms to handle computed bindings distinctly from refs throughout the pipeline.

Changes

Cohort / File(s) Summary
Binding Type Definition
packages/compiler-core/src/options.ts, packages-private/template-explorer/src/options.ts
Adds new enum member SETUP_COMPUTED = 'setup-computed' to represent computed refs that are guaranteed to be refs, extending binding classification system.
AST and Codegen
packages/compiler-core/src/ast.ts, packages/compiler-core/src/codegen.ts
Introduces isGetter?: boolean flag to Property interface; updates genObjectExpression to emit getter syntax (get key() { return value }) for lazy evaluation and adjusts multiline formatting with newlines after commas.
Transform Implementations
packages/compiler-core/src/transforms/transformElement.ts, packages/compiler-core/src/transforms/transformExpression.ts, packages/compiler-core/src/transforms/vModel.ts
Adds SETUP_COMPUTED handling to setup binding resolution, dereferencing (.value access in inline mode), and v-model assignment logic for computed refs.
Slot Outlet Lazy Evaluation
packages/compiler-core/src/transforms/transformSlotOutlet.ts
Implements logic to identify setup-related lazy bindings (SETUP_COMPUTED, SETUP_MAYBE_REF, SETUP_LET) and mark corresponding slot prop properties as getters to defer evaluation.
Script Compilation
packages/compiler-sfc/src/compileScript.ts
Distinguishes computed() initializers to produce SETUP_COMPUTED binding instead of treating them as SETUP_REF, enabling proper classification of computed bindings.
Test Coverage
packages/compiler-core/__tests__/transforms/transformElement.spec.ts, packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts, packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts, packages/compiler-core/__tests__/transforms/vModel.spec.ts, packages/compiler-sfc/__tests__/compileScript.spec.ts, packages/compiler-sfc/__tests__/compileScript/defineProps.spec.ts
Comprehensive test additions covering SETUP_COMPUTED handling in element resolution, expression transforms, slot outlet getter emission, v-model behavior, and script compilation binding detection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • #14214: Modifies setup binding classification in vModel.ts for consistent handling of different binding types.

Suggested labels

scope: compiler, scope: slots, ready for review

Suggested reviewers

  • sxzz
  • baiwusanyu-c
  • KazariEX

Poem

🐰 A computed hop, now lazy and bright,
Through slot props it dances, deferred with delight,
With getters so clever, the dance stays on time,
No eager evaluations—just pure paradigm chime! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% 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 'feat(compiler): emit lazy getter for scoped slot props' directly describes the main feature being implemented - adding lazy getter emission for slot props, which aligns with the core changes throughout the codebase.
Linked Issues check ✅ Passed The PR implements the compiler changes needed to keep computed values lazy when passed through slot props [#4192]. Changes include: adding SETUP_COMPUTED binding type, marking properties as getters for lazy evaluation, handling computed refs in v-model and expression transforms, and updating binding detection in SFC compilation.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing lazy getter support for scoped slot props. The modifications span binding type recognition, code generation for getters, slot outlet transforms, and comprehensive test coverage for the new feature.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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

@github-actions
Copy link

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 104 kB 39.3 kB 35.4 kB
vue.global.prod.js 163 kB (+608 B) 59.5 kB (+195 B) 53 kB (+158 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 47.8 kB 18.6 kB 17.1 kB
createApp 56 kB 21.7 kB 19.8 kB
createSSRApp 60.2 kB 23.4 kB 21.4 kB
defineCustomElement 61.6 kB 23.4 kB 21.4 kB
overall 70.4 kB 27 kB 24.6 kB

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 28, 2026

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@14494
npm i https://pkg.pr.new/@vue/compiler-core@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@14494
npm i https://pkg.pr.new/@vue/compiler-dom@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@14494
npm i https://pkg.pr.new/@vue/compiler-sfc@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@14494
npm i https://pkg.pr.new/@vue/compiler-ssr@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@14494
npm i https://pkg.pr.new/@vue/reactivity@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@14494
npm i https://pkg.pr.new/@vue/runtime-core@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@14494
npm i https://pkg.pr.new/@vue/runtime-dom@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@14494
npm i https://pkg.pr.new/@vue/server-renderer@14494
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@14494
npm i https://pkg.pr.new/@vue/shared@14494
yarn add https://pkg.pr.new/@vue/[email protected]

vue

pnpm add https://pkg.pr.new/vue@14494
npm i https://pkg.pr.new/vue@14494
yarn add https://pkg.pr.new/[email protected]

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@14494
npm i https://pkg.pr.new/@vue/compat@14494
yarn add https://pkg.pr.new/@vue/[email protected]

commit: e801fd3

Copy link

@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 (3)
packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts (1)

519-522: Minor inconsistency: Use toBeUndefined() for consistency.

Line 521 uses .toBe(undefined) while other similar assertions in this file use .toBeUndefined().

🔧 Consistency fix
-      expect(props.properties[0].isGetter).toBe(undefined)
+      expect(props.properties[0].isGetter).toBeUndefined()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts`
around lines 519 - 522, Replace the inconsistent Jest assertion in the test that
checks the slot outlet props: change the assertion on
props.properties[0].isGetter from expect(...).toBe(undefined) to
expect(...).toBeUndefined() so it matches the other assertions in
transformSlotOutlet.spec.ts; locate the assertion using the props variable
(derived from (ast.children[0] as ElementNode).codegenNode.arguments[2]) and
update the expect call accordingly.
packages/compiler-core/src/transforms/transformSlotOutlet.ts (1)

142-171: Object identity check may fail for transformed expressions in edge cases.

The lazy evaluation marking relies on lazyEvalExps.has(prop.value) which uses object identity. While this works for simple identifiers (filtered at line 119), if buildProps transforms the expression node (e.g., via processExpression creating a new compound expression), the identity check will fail silently.

The current implementation is protected by the isSimpleIdentifier filter, but consider adding a comment explaining this constraint for future maintainers.

📝 Suggested documentation
     if (lazyEvalExps.size > 0 && slotProps) {
+      // Note: lazyEvalExps contains original expression node references.
+      // This identity check works because we only track simple identifiers
+      // (see isSimpleIdentifier filter above), which are not transformed
+      // into new compound expression nodes by buildProps.
       const propsObjects: ObjectExpression[] = []
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-core/src/transforms/transformSlotOutlet.ts` around lines
142 - 171, Add a short inline comment above the block that checks lazyEvalExps
against prop.value in transformSlotOutlet.ts explaining that lazyEvalExps uses
object identity (lazyEvalExps.has(prop.value)) and thus depends on nodes not
being replaced by transformations (e.g., buildProps/processExpression may create
new compound expression nodes), and note that this is why the earlier
isSimpleIdentifier filter is required; also advise future maintainers to ensure
any transformation preserves the original node identity or to update this logic
to match transformed nodes if they change the AST flow.
packages/compiler-core/__tests__/transforms/vModel.spec.ts (1)

616-636: Consider more precise assertion for generated handler structure.

The test uses loose expect.stringContaining matchers which could miss subtle regressions. Consider matching the full structure similar to existing tests in this file.

🔧 More precise assertion
-      expect(props[1]).toMatchObject({
-        key: { content: 'onUpdate:modelValue', isStatic: true },
-        value: {
-          children: expect.arrayContaining([
-            expect.stringContaining('=> (('),
-            expect.stringContaining(').value = $event)'),
-          ]),
-        },
-      })
+      expect(props[1]).toMatchObject({
+        key: { content: 'onUpdate:modelValue', isStatic: true },
+        value: {
+          children: [
+            '$event => ((',
+            { content: 'title.value' },
+            ') = $event)',
+          ],
+        },
+      })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-core/__tests__/transforms/vModel.spec.ts` around lines 616
- 636, Update the test "generates .value assignment in event handler" to assert
the handler shape more precisely instead of using loose expect.stringContaining
checks: locate the parseWithVModel call and the computed node extraction (root
-> node -> (node.codegenNode as VNodeCall).props as
ObjectExpression).properties, then replace the two stringContaining matchers
with a stricter match that mirrors existing tests (e.g., assert the exact
generated handler source string or full children array structure for
props[1].value.children) so the assertion verifies the exact arrow function
wrapper and the final ").value = $event" fragment rather than any substring;
keep references to the same symbols (parseWithVModel, VNodeCall, props) when
updating the expectation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts`:
- Around line 519-522: Replace the inconsistent Jest assertion in the test that
checks the slot outlet props: change the assertion on
props.properties[0].isGetter from expect(...).toBe(undefined) to
expect(...).toBeUndefined() so it matches the other assertions in
transformSlotOutlet.spec.ts; locate the assertion using the props variable
(derived from (ast.children[0] as ElementNode).codegenNode.arguments[2]) and
update the expect call accordingly.

In `@packages/compiler-core/__tests__/transforms/vModel.spec.ts`:
- Around line 616-636: Update the test "generates .value assignment in event
handler" to assert the handler shape more precisely instead of using loose
expect.stringContaining checks: locate the parseWithVModel call and the computed
node extraction (root -> node -> (node.codegenNode as VNodeCall).props as
ObjectExpression).properties, then replace the two stringContaining matchers
with a stricter match that mirrors existing tests (e.g., assert the exact
generated handler source string or full children array structure for
props[1].value.children) so the assertion verifies the exact arrow function
wrapper and the final ").value = $event" fragment rather than any substring;
keep references to the same symbols (parseWithVModel, VNodeCall, props) when
updating the expectation.

In `@packages/compiler-core/src/transforms/transformSlotOutlet.ts`:
- Around line 142-171: Add a short inline comment above the block that checks
lazyEvalExps against prop.value in transformSlotOutlet.ts explaining that
lazyEvalExps uses object identity (lazyEvalExps.has(prop.value)) and thus
depends on nodes not being replaced by transformations (e.g.,
buildProps/processExpression may create new compound expression nodes), and note
that this is why the earlier isSimpleIdentifier filter is required; also advise
future maintainers to ensure any transformation preserves the original node
identity or to update this logic to match transformed nodes if they change the
AST flow.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea24576 and 02171cd.

⛔ Files ignored due to path filters (1)
  • packages/compiler-core/__tests__/transforms/__snapshots__/transformExpressions.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (15)
  • packages-private/template-explorer/src/options.ts
  • packages/compiler-core/__tests__/transforms/transformElement.spec.ts
  • packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts
  • packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts
  • packages/compiler-core/__tests__/transforms/vModel.spec.ts
  • packages/compiler-core/src/ast.ts
  • packages/compiler-core/src/codegen.ts
  • packages/compiler-core/src/options.ts
  • packages/compiler-core/src/transforms/transformElement.ts
  • packages/compiler-core/src/transforms/transformExpression.ts
  • packages/compiler-core/src/transforms/transformSlotOutlet.ts
  • packages/compiler-core/src/transforms/vModel.ts
  • packages/compiler-sfc/__tests__/compileScript.spec.ts
  • packages/compiler-sfc/__tests__/compileScript/defineProps.spec.ts
  • packages/compiler-sfc/src/compileScript.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keep computeds lazy when passed via slot props

1 participant