fix(reactivity): proxy sealed and non-extensible targets (fix #14893)#14917
fix(reactivity): proxy sealed and non-extensible targets (fix #14893)#14917itsybitsybootsy wants to merge 2 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR adds a WeakSet-based fallback for markRaw to opt out non-extensible objects, exports isRawMarked, updates createReactiveObject to skip frozen or raw-marked targets, updates watch traversal to respect isRawMarked, and adds tests for sealed, frozen, and prevented-extension behaviors. ChangesrawSet-based raw target tracking for non-extensible objects
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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: 1
🤖 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/reactivity/src/reactive.ts`:
- Around line 26-27: The parity issue: non-extensible markRaw values stored in
rawSet are not being treated the same as objects flagged with ReactiveFlags.SKIP
during deep traversal/dependency collection (e.g., inside watch()). Fix by
updating the traversal / dependency-collection checks that currently test for
ReactiveFlags.SKIP to also check rawSet.has(target) (and where appropriate check
for non-extensible via Object.isExtensible) so markRaw non-extensible objects
are skipped the same way; update all places that gate behavior on
ReactiveFlags.SKIP (search for uses in watch() and traversal helpers) to include
a combined condition like “isSkipped = !!target[ReactiveFlags.SKIP] ||
rawSet.has(target)” so sealed/marked objects behave identically to skip-flagged
ones.
🪄 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: b31663a2-de15-42b8-89cb-1dda094358a6
📒 Files selected for processing (2)
packages/reactivity/__tests__/reactive.spec.tspackages/reactivity/src/reactive.ts
Summary
reactive(Object.seal({...}))returned the raw target instead of a proxy, so mutations on existing keys went untracked. The guard increateReactiveObjectskipped any non-extensible target, but seal andpreventExtensionsonly lock the structure, not the values. Narrowed toObject.isFrozen. The broader guard was the fix for #1784 / #1753, back whenreactivewrote a flag onto the target. That hasn't been true for a while.markRawcan't put the SKIP flag onto a non-extensible target, so after the guard change it falls back to a sideWeakSetfor those.Closes #14893.
Test Plan
pnpm vitest run packages/reactivity/reports 434 passed. The new test exercisesreactive,shallowReactive,readonly, andshallowReadonlyon sealed inputs with effect tracking, and a separate test pins themarkRawWeakSet path. The freeze case is preserved asshould not observe frozen objects.Summary by CodeRabbit
Tests
Bug Fixes