Version: 2.0.0-rc.8 (@solidjs/web), packages/web/src/client.ts ~809 (// TODO: make this better)
spread(node, props, skipChildren) currently sets up (a) a render effect assigning props, (b) a separate one for children when not skipped, and (c) the props-collection memo, on top of a prevProps object per element. Every element rendered through Dynamic, dynamic(), or any component that forwards {...props} to an intrinsic pays this; the compiler only avoids it for statically-known attributes.
Measured
ryansolid/yak-bench, Chromium 4× throttle, @yak/solid PR head on rc.8. btn-variant and compose-1 render the same <button> × 1000; the only difference is dynamic $props (so a memo + spread) versus a static class baked into the template:
|
hydrate |
mount |
SSR inst/s |
| compose-1 (static) |
15.7 ms |
9.3 ms |
10.0M |
| btn-variant (spread) |
30.4 ms |
22.6 ms |
2.7M |
The styled(Component) cases (tabs, multifile-composition) that go createComponent → omit → {...rest} spread → element are the only ones still slower than React on hydrate (0.45×) and mount (0.63×). Full tables in the perf tracker, #3389.
Proposal
- One render effect per element that owns the diff: iterate the (already collected) prop keys, compare against
prevProps, assign changed ones; children handled inside the same effect via insert when present.
- Static fast path when the accessor is a plain object without
$PROXY (rc.8 4e730a9 already does the collection half of this): assign once, no effect at all unless a getter is present.
- Keep
prevProps off the element when there's nothing reactive to diff against.
Acceptance: a yak-runtime variant that forwards to spread lands within noise of yak's hand-rolled createElementRenderer on btn-variant and tabs in the harness; no change to the hydratable fixtures' output.
Version: 2.0.0-rc.8 (
@solidjs/web),packages/web/src/client.ts~809 (// TODO: make this better)spread(node, props, skipChildren)currently sets up (a) a render effect assigning props, (b) a separate one for children when not skipped, and (c) the props-collection memo, on top of aprevPropsobject per element. Every element rendered throughDynamic,dynamic(), or any component that forwards{...props}to an intrinsic pays this; the compiler only avoids it for statically-known attributes.Measured
ryansolid/yak-bench, Chromium 4× throttle,
@yak/solidPR head on rc.8.btn-variantandcompose-1render the same<button>× 1000; the only difference is dynamic$props(so a memo +spread) versus a static class baked into the template:The
styled(Component)cases (tabs,multifile-composition) that gocreateComponent→omit→{...rest}spread → element are the only ones still slower than React on hydrate (0.45×) and mount (0.63×). Full tables in the perf tracker, #3389.Proposal
prevProps, assign changed ones; children handled inside the same effect viainsertwhen present.$PROXY(rc.8 4e730a9 already does the collection half of this): assign once, no effect at all unless a getter is present.prevPropsoff the element when there's nothing reactive to diff against.Acceptance: a yak-runtime variant that forwards to
spreadlands within noise of yak's hand-rolledcreateElementRendereronbtn-variantandtabsin the harness; no change to the hydratable fixtures' output.