Skip to content

v3.2.5: perf: build only the data arrays that are actually emitted (#133)

Choose a tag to compare

@github-actions github-actions released this 08 Aug 19:56
· 2 commits to main since this release
a540c0e
* perf: build only the data arrays that are actually emitted

genDataArrays built both the gzip and the plain array text and then let
sw() discard one. Each array text is roughly 4x the payload size, so the
default --gzip=always path allocated megabytes of string per run purely
to throw it away. Only the 'compiler' mode ever emits both.

Branch explicitly instead of routing through sw(), whose cases object
forces both arms to be evaluated, and drop the precomputed bytes/bytesGzip
fields from transformSourceToTemplateData so the byte strings are built
inside the arm that is actually taken. Those fields had exactly four
readers, all of them data-array emission.

Also stop re-reducing the file totals in getCppCode: runPipeline already
accumulates them while compressing, and they are provably equal because
createSourceEntry aliases contentGzip to content when gzip is unused.

Every generated header variant is byte-identical to before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: O(n^2) compressed-file scan and Math.max spread overflow

shouldSkipFile did an Array#includes over the full file list for every
file, which is quadratic exactly when it matters: compression plugins
emit a .gz beside every asset, so the compressed-extension branch is hit
n times over an n-element list. Build the lookup set once.

Math.max(...rows.map(...)) spreads an unbounded array into a call and
throws RangeError past V8's argument limit, which a large dist directory
can reach. Replace the four sites with a maxLength reduce, which also
drops the intermediate map allocations.

Fold the three separate traversals of the file map before the compression
loop into one, and reuse its datanames there so toDataName runs once per
file instead of twice.

Every generated header variant is byte-identical to before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: generate espidf header via the shared cppCode helpers

cppCodeEspIdf.ts hand-rolled inline copies of five of the six helpers the
other three engines import from cppCode.ts. The genEtagArrays copy was
byte-identical and the #warning ladder was a character-for-character
duplicate. CLAUDE.md already warns that four engine copies drifting apart
is how the 304 lost its headers once; espidf was exempt from that
consolidation for four of six blocks, which is the same setup.

Parameterize the shared helpers along the axes that actually vary:
genCommonHeader takes a UriHandlerMode ('loadBearing' for espidf, whose
httpd_config_t really consumes the counts, vs 'informational' for psychic,
which overwrites them in start()), genDataArrays takes the element type
and PROGMEM, genManifest takes a C-style typedef flag, genHook an
extern "C" flag.

Add gateGzip alongside the existing gateEtag and use it for the six
handler-body #ifdef ladders that were built by hand. It omits the #else
when the plain body is empty, which is what the Content-Encoding blocks
need, and emits nothing when both bodies are empty. genDataArrays keeps
its explicit branching: routing it through gateGzip would reintroduce the
eager evaluation of the discarded arm removed in the previous commit.

The duplicated RFC 7232 comment above each 304 block is left alone: it is
a source comment with engine-specific trailing lines, and the four 304
bodies themselves are genuinely different code with different failure
modes.

Every generated header variant is byte-identical to before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: deduplicate RC config parsing and validation

Six copy-pasted boolean checks and three copy-pasted cachetime checks in
validateRcConfig become two key lists and two small validators, with the
error messages and the validation order preserved exactly.

The list of fields that may contain $npm_package_ variables was
maintained in three places - the detection, the "variables found in
fields" error and the interpolation - so adding an interpolatable option
needed three coordinated edits. One INTERPOLATABLE_KEYS list now drives
all three; its order is the one the error message already used.

Collapse the two 22-line ICopyFilesArguments literals in vitePlugin.ts
into one builder. The RC file and the plugin options use the same key
names and differ only in whether booleans arrive as strings, which
coerceBool already handles for both.

validateEngine now throws instead of calling process.exit. It runs inside
validateRcConfig, which the Vite plugin also reaches, so a typo'd engine
in an RC file would have hard-exited the Vite build instead of surfacing
a plugin error. parseArguments catches it at the CLI boundary and still
prints the enhanced message and exits 1, so the CLI behaviour is
unchanged.

Also drop findIdentifierCollisions and toDataName from pipeline.ts's
export list: nothing outside that file referenced them.

Every generated header variant is byte-identical to before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: record that all four engines share the cppCode helpers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: 3.3.0 changelog, README what's new, CLAUDE.md invariants

Adds the 3.3.0 CHANGELOG entry (unreleased — npm latest is 3.2.4) and a
matching README "What's New" line, which the release notes rule keeps to
minor and major versions.

Also records two invariants this release introduced, so they are not
undone later: validators in commandLine.ts must throw rather than exit,
because validateRcConfig runs inside the Vite plugin, and all four
engines build their header from the shared cppCode.ts helpers. Refreshes
the stale coverage figures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore: release 3.2.5 instead of 3.3.0

No features and no public API change, so this is a patch. The one
behaviour change - validateEngine throwing rather than exiting - is a bug
fix confined to the Vite plugin path.

Drops the README "What's New" entry accordingly: that list carries minor
and major versions only. Adds the CHANGELOG compare link that the earlier
entry was missing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>