perf: precompile AliasPlugin options to speed up huge alias lists#528
Conversation
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #528 +/- ##
==========================================
+ Coverage 96.51% 96.52% +0.01%
==========================================
Files 50 50
Lines 2640 2651 +11
Branches 806 808 +2
==========================================
+ Hits 2548 2559 +11
Misses 77 77
Partials 15 15
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Merging this PR will improve performance by 22.23%
Performance Changes
Comparing |
fd5157f to
6ca4c6f
Compare
Hoists per-option strings (nameWithSlash, absolutePath, wildcardPrefix/Suffix)
out of the hot AliasPlugin scan into AliasUtils#compileAliasOptions, invoked
once per resolver in AliasPlugin#apply (and in TsconfigPathsPlugin when a
paths map is built). The per-resolve loop then runs with no string concat,
no name.split("*"), and no resolver.join per unmatched entry - the cost that
dominated projects with hundreds of webpack aliases (see #438).
Adds two benchmark cases covering the monorepo-scale scenario:
- huge-alias-list: 300 non-matching + 8 matching aliases, match near end
- huge-alias-miss: 300 aliases + requests that never match any
Local wall-clock numbers (Node 22, tinybench):
before after delta
huge-alias-list 225 ops 405 ops +80%
huge-alias-miss 453 ops 893 ops +97%
large-alias-list 653 ops 856 ops +31%
https://claude.ai/code/session_01ERSdt7j3dKwd9MxNbuuXnm
Short-circuits aliasResolveHandler before computing innerRequest / entering forEachBail when options is empty, and returns a shared empty array from compileAliasOptions so both AliasPlugin instances the factory registers for resolvers without aliases do zero per-resolve work. Also drops the hoisted hasRequest variable — reading request.request inline is cheaper than closing over it, and matches the original code shape to keep no-alias / single-alias cases (array-alias, fully-specified) on a hot path identical to main. https://claude.ai/code/session_01ERSdt7j3dKwd9MxNbuuXnm
6ca4c6f to
78744d1
Compare
Hoists per-option strings (nameWithSlash, absolutePath, wildcardPrefix/Suffix)
out of the hot AliasPlugin scan into AliasUtils#compileAliasOptions, invoked
once per resolver in AliasPlugin#apply (and in TsconfigPathsPlugin when a
paths map is built). The per-resolve loop then runs with no string concat,
no name.split("*"), and no resolver.join per unmatched entry - the cost that
dominated projects with hundreds of webpack aliases (see #438).
Adds two benchmark cases covering the monorepo-scale scenario:
Local wall-clock numbers (Node 22, tinybench):
before after delta
huge-alias-list 225 ops 405 ops +80%
huge-alias-miss 453 ops 893 ops +97%
large-alias-list 653 ops 856 ops +31%
https://claude.ai/code/session_01ERSdt7j3dKwd9MxNbuuXnm