Skip to content

fix(reactivity): prevent orphan effect when created in a stopped scope#14778

Merged
edison1105 merged 2 commits intovuejs:mainfrom
Mini-ghost:fix/reactivity-orphan-effect-stopped-scope
May 6, 2026
Merged

fix(reactivity): prevent orphan effect when created in a stopped scope#14778
edison1105 merged 2 commits intovuejs:mainfrom
Mini-ghost:fix/reactivity-orphan-effect-stopped-scope

Conversation

@Mini-ghost
Copy link
Copy Markdown
Contributor

@Mini-ghost Mini-ghost commented May 4, 2026

close #14777

Summary by CodeRabbit

  • Bug Fixes

    • Prevented effects from remaining active after scope shutdown during async setup (e.g., Suspense with top-level await) and reduced spurious development-time warnings for inactive scopes.
  • Tests

    • Added tests covering async component setup with top-level await in Suspense, including branch replacement and unmount scenarios.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 382bdafd-2728-495c-a2d1-2344636324d7

📥 Commits

Reviewing files that changed from the base of the PR and between 69aff7c and 313fd93.

📒 Files selected for processing (2)
  • packages/reactivity/src/effectScope.ts
  • packages/runtime-core/__tests__/components/Suspense.spec.ts

📝 Walkthrough

Walkthrough

ReactiveEffect and EffectScope constructors are tightened to avoid attaching effects to inactive scopes: effects created when a parent scope is inactive are marked inactive. EffectScope also suppresses run-time warnings for scopes created under inactive parents. Tests for Suspense async setup with top-level await were added.

Changes

Effect Scope Lifecycle and Async Setup Bug Fix

Layer / File(s) Summary
Scope ctor attachment
packages/reactivity/src/effectScope.ts
EffectScope now has a private _warnOnRun flag and only attaches a new scope to the current activeEffectScope if that parent is active; otherwise the new scope is marked inactive and run warnings are disabled.
Effect ctor handling
packages/reactivity/src/effect.ts
ReactiveEffect constructor: when an activeEffectScope exists but is inactive, the effect's EffectFlags.ACTIVE is cleared so it won't become an orphan and continue subscribing/triggering after scope shutdown.
Run warning gating
packages/reactivity/src/effectScope.ts
run() warning logic now checks _warnOnRun in addition to __DEV__ so only appropriate scopes emit dev warnings when run while inactive.
Tests / Verification
packages/runtime-core/__tests__/components/Suspense.spec.ts
Adds getCurrentInstance and withAsyncContext imports and a describe('async setup with top-level await') block with three tests validating top-level-await async setup under <Suspense> (pending branch replacement, boundary unmount, repeated branch replacement) to ensure abandoned async setups do not produce lingering watcher updates.

Sequence Diagram(s)

(Skipped)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • vuejs/core#14734: Addresses related effect-scope lifecycle management to avoid stale/inactive scopes being reactivated.
  • vuejs/core#14776: Related changes around EffectScope propagation for component/teleport children.
  • vuejs/core#14359: Prior modifications to EffectScope internals; relevant at the class level.

Suggested reviewers

  • edison1105

Poem

🐰 A scope once stayed, though its parent was gone,
Flags cleared at creation, so misfires are none.
Async setups finish or quietly yield,
No orphaned watchers will roam the field. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: preventing orphan effects created in stopped scopes, which directly addresses the core issue of reactive effects leaking when components are abandoned.
Linked Issues check ✅ Passed The PR fully addresses issue #14777 by preventing reactive effects from becoming orphaned when created in stopped scopes, with changes to ReactiveEffect and EffectScope to handle inactive parent scopes properly.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing orphaned effects: effect.ts prevents inactive scope effects, effectScope.ts manages inactive scope initialization, and Suspense tests validate top-level-await behavior under this fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 106 kB (+83 B) 40 kB (+28 B) 35.9 kB (+26 B)
vue.global.prod.js 164 kB (+83 B) 60 kB (+26 B) 53.4 kB (+42 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 48.7 kB (+83 B) 18.9 kB (+24 B) 17.3 kB (+22 B)
createApp 56.8 kB (+83 B) 22 kB (+26 B) 20.1 kB (+33 B)
createSSRApp 61.1 kB (+83 B) 23.7 kB (+28 B) 21.6 kB (+24 B)
defineCustomElement 63 kB (+83 B) 23.9 kB (+27 B) 21.8 kB (+32 B)
overall 71.5 kB (+83 B) 27.4 kB (+22 B) 25 kB (+81 B)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 4, 2026

Open in StackBlitz

@vue/compiler-core

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

@vue/compiler-dom

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

@vue/compiler-sfc

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

@vue/compiler-ssr

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

@vue/reactivity

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

@vue/runtime-core

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

@vue/runtime-dom

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

@vue/server-renderer

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

@vue/shared

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

vue

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

@vue/compat

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

commit: 313fd93

@edison1105 edison1105 added scope: reactivity 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. labels May 4, 2026
@edison1105 edison1105 added the ready to merge The PR is ready to be merged. label May 6, 2026
@edison1105
Copy link
Copy Markdown
Member

/ecosystem-ci run

@vue-bot
Copy link
Copy Markdown
Contributor

vue-bot commented May 6, 2026

📝 Ran ecosystem CI: Open

suite result latest scheduled
quasar success success
pinia success success
router success success
language-tools success success
primevue success success
vue-i18n success success
radix-vue success success
vitepress success success
vue-simple-compiler success success
vant success success
nuxt success failure
vueuse success success
vuetify success success
vite-plugin-vue success success
vue-macros success success
test-utils success success

@edison1105 edison1105 merged commit c8e2d4a into vuejs:main May 6, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. ready to merge The PR is ready to be merged. scope: reactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Top-level await in <script setup> leaks reactive effects when the component is abandoned before the await resolves

3 participants