Skip to content

fix: render options in linear time in the static HTML renderer - #664

Merged
ignsm merged 3 commits into
mainfrom
fix/static-html-option-render
Nov 2, 2026
Merged

ignsm merged 3 commits into
mainfrom
fix/static-html-option-render

Conversation

@ignsm

@ignsm ignsm commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

Rendering a field with N options was quadratic. A radio field with 10,000 options took about 1.4 s in goja.

Causes:

  • html() built its children string with += in a loop (markup.ts). goja copies the whole string on each append, so allocation grew with N squared.
  • firstOpen() rescanned the options for every option (choices.ts). With readOnly and no selection this is O(N^2) in Node too (6.5 s at 10,000).
  • Array values and defaultValue were checked with includes per option (choices.ts, warnings.ts).
  • The duplicate-option check used indexOf per option (definition-validation/fields.ts). This also speeds up checkDefinition().

Output is byte-identical to 1.12.0 on 570 renders (templates, fixtures, conformance scenarios, generated option-heavy fields).

Tests count array scan work at 200 and 800 options and assert near-linear growth (fails on main). No timing assertions.

Render time, goja / Node:

options before after
radio 100 4.1 ms / 0.7 ms 3.2 ms / 0.7 ms
radio 1000 35 ms / 3.8 ms 23 ms / 2.6 ms
radio 10000 835 ms (10 GB) / 88 ms 213 ms (349 MB) / 29 ms
select 10000 314 ms (2.2 GB) / 64 ms 96 ms (185 MB) / 10 ms
read-only radio 10000 n/a / 6460 ms n/a / 28 ms
10000 text fields 1299 ms (10.6 GB) / 61 ms 764 ms (1.3 GB) / 62 ms

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Bundle size

Gzipped size of the entry points on this pull request against its base. Growth over 512 B needs a ## Size section in the pull request description.

Entry Base Head Delta since @formhaus/core@1.12.0
core 33810 B 33830 B +20 B +20 B
core FormEngine 20471 B 20478 B +7 B +7 B
core + react FormRenderer 39189 B 39185 B -4 B -4 B
core + vue FormRenderer 42871 B 42876 B +5 B +5 B

@ignsm
ignsm merged commit 1ce8672 into main Nov 2, 2026
16 checks passed
@ignsm
ignsm deleted the fix/static-html-option-render branch November 2, 2026 19:49
Sign up for free to 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