Conversation
…eiver A prop's getter is defined only for a read through its own object. The plain-object merge() path already binds a copied getter to its source; omit()'s no-Proxy path forwarded the descriptor as-is, so a getter that keeps state on the instance (the compiler's server props, #3511) would throw on the first read of the copy. Both copy paths now follow the same rule, the rule is written down on merge(), and isStatic()'s note about server/client parity says what is actually equal: the descriptors. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
🦋 Changeset detectedLatest commit: 756b1b3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Coverage Report for CI Build 35385554074Coverage remained the same at 71.366%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Merging this PR will improve performance by 69.47%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | omit |
50.8 µs | 30 µs | +69.47% |
Tip
Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.
Comparing fix/omit-fallback-read-through (756b1b3) with next (ead76f4)
Footnotes
-
3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
Summary
omit()'s no-Proxy copy path forwarded accessor descriptors as-is onto the copy.merge()'s copy path, three functions above it, already binds a copied getter to its source. Both now follow the same rule: a prop's getter is defined only for a read through its own object.This is groundwork for #3511 (finding 2). The server-side props emission under evaluation there builds each component's props with a per-site constructor whose getters are shared across instances and read their state off
this— the thing that gets the object out of V8 dictionary mode (15–48% SSR CPU on the component-heavy yak-bench cases). A descriptor forwarded from such an object and read on another throws. Nothing in core reads props that way except this one fallback branch, which cannot execute on a server runtime anyway; it is fixed here so the rule holds everywhere.Changes
omit()no-Proxy path: accessors are re-homed (get/setbound to the source,configurable: true), matchingmerge(). Data descriptors are unchanged.merge()'s doc block.isStatic()'s note on server/client parity now says what is actually equal — the own descriptors — rather than "the compiled shape".utilities-no-proxy.test.ts): a props object in the receiver-dependent shape (plain prototype, shared getter readingthis[$m]); the forwarded descriptor throws,omit/mergecopies read live through the source and keep accessor kind. Fails onomitwithout the fix.Not changed
Stores (
createStoresource clone,storePathmerge) also copy descriptors, deliberately: a store getter is re-homed so it computes against the store proxy. That is the store's own contract, and a compiled props object is not a store source. Left as is; noted so it is a decision rather than an omission.Ecosystem
Surveyed for descriptor forwarding of props: Kobalte
solid2, corvu, ark (solid), solid-ui, solid-primitivessolid2— none (solid-primitives'mutablealready binds).@yak/solid'scopyPropsdoes forward; its fix is a getter that reads throughprops, and the note goes to them with the compiler PR.Made with Cursor