Skip to content

[6.x] Reduce publish container value cloning and emission overhead - #15261

Closed
jasonvarga wants to merge 2 commits into
6.xfrom
cp-visiblevalues-perf
Closed

[6.x] Reduce publish container value cloning and emission overhead#15261
jasonvarga wants to merge 2 commits into
6.xfrom
cp-visiblevalues-perf

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 24, 2026

Copy link
Copy Markdown
Member

Extracted from #15158

The publish container's visibleValues computed cloned the entire values tree — JSON.parse(JSON.stringify(...)) via Values — on every keystroke, and a separate deep watcher then re-traversed that derived tree in order to emit it. Neither is necessary in the common case.

Two independent changes, in separate commits:

Skip the clone when nothing is omitted. Field conditions only omit values when a field is hidden with omitValue. When nothing is omittable — the common case — visibleValues now returns the live tree instead of a copy. The cloning path is unchanged when there is actually something to strip out.

Emit without deep watching the derived tree.visibleValues is derived from values and hiddenFields, so it's now emitted alongside update:modelValue from the existing values watcher, and the separate deep watcher watches the much smaller hiddenFields object rather than re-traversing the whole values tree.

Emission behaviour is unchanged. I traced the emission sequence on 6.x and on this branch with the same instrumented test, and the count, order and payloads are identical for value edits, nested edits, wholesale replacement via setValues, and conditions toggling a field on or off.

Nothing here touches which fields get omitted.

One note for addon authors: on the non-omitting path visibleValues is now the live values tree rather than a copy, so it must be treated as read-only. Nothing in core mutates it, and nothing in core listens to update:visibleValues.

Adds resources/js/tests/components/ui/Publish/VisibleValues.test.js, covering the uncloned tree's equivalence to a clone (including identical serialization) and the emissions for each of the cases above.

The visibleValues computed cloned the entire values tree on every keystroke,
even when field conditions had nothing to omit, which is the common case.
Return the live tree by reference instead, and only clone when there is
actually something to strip out.
Deep watching the visibleValues computed traversed the entire derived tree on
every keystroke, on top of building it. visibleValues is derived from values
and hiddenFields, so emit it alongside update:modelValue from the values
watcher, and watch the much smaller hiddenFields object for the rest.
@jasonvarga

Copy link
Copy Markdown
MemberAuthor

Closing this one — it's a breaking change.

visibleValues is documented addon API. Returning the live values tree instead of a copy changes more than just "treat it as read-only":

  • mutations now leak into form state
  • visibleValues === values becomes true, so the two trees can't be told apart
  • structuredClone on it throws, which breaks worker/IndexedDB paths
  • a non-deep watch(visibleValues, cb) silently stops firing
  • retained references alias, so held snapshots rewrite themselves

The old clone was also normalizing via a JSON round trip, so Dates and undefined values now survive where they previously didn't.

Too much to put on a released line.

@jasonvarga
jasonvarga deleted the cp-visiblevalues-perf branch August 24, 2026 23:32
Sign up for freeto 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.

1 participant

@jasonvarga