feat(bench): add the Attaform (Zod 4) adapter and order the comparison by performance#406
Merged
Merged
Conversation
…lation Add a second Attaform row to the cohort, built on `attaform/zod-v4`, so the bench measures both first-class zod adapters side by side. It mirrors the existing Attaform adapter exactly (same shared Field / ArrayRow bindings, same handle), differing only in the validator it feeds: `useForm` / `useWizard` from `attaform/zod-v4` over zod v4 schemas. New `*Zod4` scenario builders (dispatched by `zodV4SchemaFor`) mirror the v3 shapes, and `schemaLib` gains a `zod4` value. Dual-zod isolation is the load-bearing piece. Attaform's published zod-v4 adapter imports bare `zod`, expecting zod@^4 (its zod-v3 adapter imports the `zod-v3` alias instead). The arena pins zod@3 for the whole v3 cohort, so without isolation the v4 adapter resolves zod v3 and runs v3's discriminatedUnion over a v4 schema, which throws "discriminator could not be extracted" and breaks the DU scenario. A small `enforce: 'pre'` vite resolver redirects ONLY the Attaform dist's bare `zod` import to an aliased `zod-v4` package (npm:zod@^4); every other bare `zod` import (the v3 validators, the v3 schema builders) is left untouched, so the v3 cohort's numbers cannot move. This is the general shape for hosting mixed zod majors in one bundle, and the same approach will host a future vee-validate v4. Validated locally: the zod-v4 row is green across all seven scenarios including discriminated-union, and every v3-cohort DU cell passes unchanged (116 passed, 0 failed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le selector The runtime tables rendered fixed registry order, so a reader could not see who was fastest at a glance. Order the rows by performance instead, best at the top, ranked by the value at the largest (at-scale) param where the cost gaps read truest. A did-not-finish or unsupported cell sorts last, never ahead of a real measurement. Add a "Sort by" selector that re-ranks the rows at any other field count, so a reader can watch the order shift as a form grows from a handful of fields to thousands. It shows only when a dimension has more than one param; single-param scenarios (discriminated-union, wizard) still sort, with no selector. The bundle table already orders smallest-first, and the capability / scorecard tables stay in registry order since they are not performance axes. Also label the new `zod4` schema value as "Zod 4" in the capability matrix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a second Attaform row to the cross-library benchmark, Attaform (Zod 4), so the arena measures
both adapters Attaform ships, and reorders the documentation comparison so the fastest library sits at
the top.
Two commits:
feat(bench-arena): the Attaform (Zod 4) adapter plus the dual-zod isolation that lets one benchhost both zod majors safely.
feat(site): the comparison tables now rank by performance (best first), with a field-countselector that re-ranks at each scale.
Why
Attaform treats its zod-v3 and zod-v4 adapters as first-class peers, so the benchmark should hold both
to the same cohort. Separately, the comparison page rendered libraries in fixed registry order, so a
reader could not see at a glance who leads a given dimension.
The dual-zod isolation (the load-bearing piece)
Attaform's published zod-v4 adapter imports bare
zod(on a zod 4.x install, barezodresolves tov4). The bench pins zod 3.x for the rest of the cohort, where bare
zodis v3, so without isolationthe v4 adapter would resolve v3 and a v4-built schema would fail to parse.
The fix is a small vite resolver (
enforce: 'pre') that redirects only the Attaform dist's barezodimport to an aliasedzod-v4package (npm:zod@^4), leaving every other library'szoduntouched. The v3 cohort is provably unaffected (see the validation run below). This is the general
pattern for hosting two zod majors in one app, and it carries directly to any future adapter that needs
a different zod major than its neighbours.
One new bench-only devDependency:
zod-v4(an alias ofzod@^4).Local parity check (throwaway, not committed)
A local head-to-head smoke run (attaform vs attaform-zod4 across all 68 comparable cells) puts the
median ratio at exactly 1.00:
+3%), validate often faster on v4, rerender identical, array ops within noise.
massivescenario(hundreds of distinct keys plus deep nesting) shows mount +43% and retained heap +83% on v4. This is
zod v4's heavier in-memory schema representation, faithfully reflected by the adapter. It does not
appear in arrays/grid at scale (where one small row shape is reused N times), and it is a one-time
mount/heap cost, not a steady-state hot-path cost.
Absolute numbers are host-specific; CI will re-measure. No DNFs, no failures.
Docs comparison ordering
The runtime (timed plus memory) tables now sort by the selected scale's measurement, best first, with a
field-count selector that re-ranks at other scales (hidden for single-param dimensions). The bundle
table sorts smallest-first. Capability and supply-chain tables keep registry order (they are not
performance axes). The sort works on the current committed cohort immediately.
Sequencing
This PR's sort UI works on the current
results.jsonnow. After merge, a CI bench refresh (the monthlysharded workflow) repopulates
results.jsonwith the ninth row so the published tables includeAttaform (Zod 4).
Test plan
--grep 'attaform-zod4|DU'): 116 passed, 0 failed; attaform-zod4 DU green,every v3-cohort DU cell unchanged.
--grep attaform): 136 passed, 4 skipped (the L5000 budget skips), 0 failed.🤖 Generated with Claude Code