Skip to content

perf(webpack-cli): allocate Levenshtein buffer lazily#4765

Merged
alexander-akait merged 7 commits into
mainfrom
claude/performance-memory-optimization-bn84r
May 27, 2026
Merged

perf(webpack-cli): allocate Levenshtein buffer lazily#4765
alexander-akait merged 7 commits into
mainfrom
claude/performance-memory-optimization-bn84r

Conversation

@alexander-akait
Copy link
Copy Markdown
Member

The 256 KB peq Uint32Array was allocated at module load, so every CLI
invocation paid that cost even though distance() only runs on error
paths ("did you mean" suggestions). Defer the allocation to the first
distance() call.

https://claude.ai/code/session_01TKJqMqs6zkot18iBUae52n

claude added 4 commits May 27, 2026 14:07
The 256 KB peq Uint32Array was allocated at module load, so every CLI
invocation paid that cost even though distance() only runs on error
paths ("did you mean" suggestions). Defer the allocation to the first
distance() call.

https://claude.ai/code/session_01TKJqMqs6zkot18iBUae52n
Profiling `webpack build` showed CLI-owned code is a tiny fraction of
startup; the cost is module loading. Two reductions there:

- Default-config discovery now imports `interpret` only when no
  common-extension config (.js/.mjs/.cjs/.ts/.cts/.mts) is found, so the
  common `webpack.config.js` build never loads it.
- The Levenshtein "did you mean" helper is inlined into webpack-cli as a
  private method, removing the separate module/import. The 256 KB buffer
  stays lazily allocated (error paths only).

https://claude.ai/code/session_01TKJqMqs6zkot18iBUae52n
Migrate the previously removed test/api/levenshtein.test.js to exercise the
inlined implementation. The helper is now a `private static distance` method
(TypeScript `private` is erased at runtime), so the unit tests call it directly
without re-introducing a separate module or import.

https://claude.ai/code/session_01TKJqMqs6zkot18iBUae52n
…ssed

A plain `webpack build` (no option flags) previously still ran webpack's
~28ms `getArguments` schema walk and built the full ~864-entry option list,
then registered nothing. Now:

- makeCommand skips building/registering options entirely when argv has no
  option flags (nothing to register, and no unknown-option suggestions are
  possible without flags).
- loadConfig computes the argument metadata lazily, skipping it when only
  internal keys (webpack/argv/isWatchingLikeCommand) are present.

Net: a plain build makes 0 getArguments calls (was 1), ~14-18ms faster
startup and ~2.5MB less heap. Builds with flags or entry operands are
unchanged (getArguments still runs once, as before).

https://claude.ai/code/session_01TKJqMqs6zkot18iBUae52n
Copilot AI review requested due to automatic review settings May 27, 2026 15:19
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 27, 2026

🦋 Changeset detected

Latest commit: 7c20d69

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
webpack-cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented May 27, 2026

CLA Not Signed

@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.89%. Comparing base (1b40b72) to head (7c20d69).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4765      +/-   ##
==========================================
+ Coverage   92.82%   92.89%   +0.06%     
==========================================
  Files          15       14       -1     
  Lines        5076     5124      +48     
  Branches      752      756       +4     
==========================================
+ Hits         4712     4760      +48     
  Misses        362      362              
  Partials        2        2              
Files with missing lines Coverage Δ
packages/webpack-cli/src/webpack-cli.ts 96.43% <100.00%> (+0.24%) ⬆️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1b40b72...7c20d69. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces webpack-cli startup overhead by deferring or skipping work that’s only needed on error paths or when certain flags/config patterns are present.

Changes:

  • Lazily allocate the 256 KB Levenshtein lookup buffer and inline the distance implementation to avoid a module-load allocation/import on typical runs.
  • Skip building the full command option list (and related “did you mean” candidate list) when no option flags are present in argv.
  • Defer importing interpret until common config extensions are not found during default config resolution, and make getArguments() computation lazy when only internal option keys are present.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/api/levenshtein.test.js Updates the unit test to call the inlined Levenshtein implementation via WebpackCLI.distance.
packages/webpack-cli/src/webpack-cli.ts Inlines and lazily allocates Levenshtein buffer; skips option registration work when no flags; defers interpret import; lazily computes getArguments() and filters internal keys.
packages/webpack-cli/src/levenshtein.ts Removes the standalone Levenshtein module after inlining into webpack-cli.ts.
.changeset/skip-getarguments-no-flags.md Adds release note for skipping schema-to-arguments work on no-flag invocations.
.changeset/lazy-levenshtein-buffer.md Adds release note for lazy Levenshtein buffer allocation.
.changeset/defer-interpret-inline-levenshtein.md Adds release note for deferring interpret import and inlining Levenshtein helper.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +5
---
"webpack-cli": patch
---

Skip the webpack schema-to-arguments walk on a plain `webpack build` (and other no-flag invocations). When no option flags are present, the CLI no longer builds the full option list or calls `getArguments`, reducing startup time and peak memory for the most common invocation.
claude added 2 commits May 27, 2026 15:34
bin/cli.js required both `import-local` and the full CLI implementation
up front. Reorder so:

- a run delegated to a local install returns without loading the outer
  installation's CLI lib (+commander), and
- WEBPACK_CLI_SKIP_IMPORT_LOCAL short-circuits before requiring
  `import-local` at all (10 fewer modules loaded on that path).

The typical local invocation is unchanged. Behavior is preserved
(import-local still runs by default).

https://claude.ai/code/session_01TKJqMqs6zkot18iBUae52n
Copilot AI review requested due to automatic review settings May 27, 2026 15:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated no new comments.

Replace the TypeScript `private static distance` with a `#distance` private
method that delegates to a module-scoped `distance` function. The function is
exported so the unit tests can exercise the algorithm directly.

https://claude.ai/code/session_01TKJqMqs6zkot18iBUae52n
@alexander-akait alexander-akait merged commit 00347ed into main May 27, 2026
18 of 19 checks passed
@alexander-akait alexander-akait deleted the claude/performance-memory-optimization-bn84r branch May 27, 2026 16:32
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.

3 participants