Repository navigation
Commit aff7c4c
authored
perf: emit less chunk-loading runtime (#22094)
* perf: call the one chunk handler directly when a chunk carries one
`__webpack_require__.e` walked every key of the handler map to collect promises,
which is 78 minified bytes of dispatch for the single handler most chunks have.
Read the keys the chunk's other runtime modules emit and call that one directly.
The keys are read from what those modules generate rather than declared, so a
handler stays counted as their conditions change. One that reads the compilation
hash cannot be generated this early without caching it before the hash exists,
so a chunk carrying one keeps the walk.
* perf: emit less chunk-loading runtime
`__webpack_require__.O` carried a priority queue — an insertion sort, a lowest
seen priority and the gate reading it — for a priority only the prefetch startup
callback passes, so a build without one now keeps insertion order.
* perf: call the one chunk handler directly in every dispatch
The single-handler specialization read a sibling's code to learn which handlers a
chunk installs, and gave up whenever one was keyed on a hash. The module naming
chunk files is keyed on one and sits in every build that loads a chunk by
computed filename, so the specialization almost never fired there: 120 of the
259 single-handler assets still walked the map. Reading such a sibling through
`generate()` rather than `getGeneratedCode()` answers the same question without
pinning a placeholder into its cache.
The prefetch dispatch and the deferred-startup gate fan out over a handler map
the same way, so both now take the same direct call. A module that reads a map
rather than installing onto one is skipped, otherwise the three would generate
each other in a cycle.
* fix: escape every regexp metacharacter in the handler map name
The name was escaped for `$` and `.` alone, so one carrying a bracket or a
backslash would have been read as regexp syntax rather than matched literally.
The three globals it is called with are unaffected; CodeQL reports the gap.
* test: record the smaller entry chunk in the stats snapshots
`entryB.js` loses 18 bytes to the direct chunk handler call. These snapshots are
inline in a `*.test.js`, so only the integration matrix runs them.
* test: make the deferred priority case require the priority queue
The case passes a priority to `__webpack_require__.O` but never asked for
`hasChunkPriority`, so it was served the insertion-order queue and its assertion
held either way. It now requests the flag and defers a loaded odd priority behind
a blocked lower one, which insertion order runs instead.
* perf: read a chunk's handler keys once instead of once per dispatch
Each of the three dispatches scanned the chunk's runtime modules for its own map,
so the module naming chunk files — the one whose output grows with chunk count —
was generated once per dispatch. One pass now reads every map hanging off the
require global and caches it per chunk: on a 62-chunk build that is 1 generate
call rather than 3, and 9 KB scanned rather than 27 KB.
* perf: let a hash-keyed runtime module state the handlers it installs
Reading a module keyed on a hash means rendering it a second time, and the module
naming chunk files is read on every runtime chunk. The six such modules now state
which handlers they install, so none of them is rendered for the scan: a 20-entry
build drops from 20 generate calls to none. Saying nothing still means the code is
read, so a module that does not state its handlers keeps working.
* perf: let every chunk handler installer state what it installs
Replaces the per-module `_installedChunkHandlers` field with a
`getInstalledChunkHandlers()` method, and declares it on all fifteen runtime
modules that install onto a chunk handler map. `generate()` is no longer
reached: the modules keyed on a hash, which were the only ones a scan had to
render, now state their keys instead.
A module that states nothing is still read, because an undeclared installer
would otherwise be dropped from a specialized dispatch --- mini-css-extract-
plugin installs `__webpack_require__.f.miniCss` from its own runtime module,
and `configCases/custom-source-type/localization` does the same.
* test: cover the handler a legacy main template hook installs
`CompatRuntimeModule` emits whatever a plugin taps `requireExtensions` with, so
it states that it cannot name what it installs and the dispatch stays general.
Without that the case's handler is never called and the assertion on
`global.__legacyHandlerCalled` fails, which is how a third-party handler would
be dropped in a real build.
* perf: state chunk handlers on every runtime module instead of reading code
A dispatch can only be specialized when the whole key set is known, and that
knowledge has two possible sources: every contributing module states it, or
webpack reads what they emit. Nothing else answers it -- a runtime requirement
marker cannot speak for an installer that adds none, a registry cannot tell
"nobody installs" from "someone installs silently", and the dispatcher renders
before the installers because it emits the map they assign onto.
So "said nothing" now means unknown rather than none, which makes every runtime
module answer. `HelperRuntimeModule` answers for the seventeen helpers under it,
leaving thirty classes to state that they install nothing, and
`getOnlyHandlerKey` no longer renders or reads anything.
Across `configCases` this costs 29 gzip bytes in one case, whose fixture
installs a handler from a runtime module of its own and so keeps the general
dispatch -- which is what a third-party installer now gets too.
* fix: do not call the handler declaration on a module that lacks it
A runtime module built against an older webpack extends a base class from that
copy, so the instance has no `getInstalledChunkHandlers` and calling it threw
`module.getInstalledChunkHandlers is not a function` mid-build. Such a module is
read as unknown now, which keeps the general dispatch and its handler with it.
`Array.isArray` rather than a `null` check, so a module answering something else
is unknown as well. The check goes away in webpack 6, where every runtime module
answers.
* test: type the foreign runtime module case against the public entry
`tsc -p tsconfig.types.test.json` reads a test's webpack imports as the
generated types, so importing `RuntimeModule` from `lib/` made the instance
unassignable to `addRuntimeModule`. Shadowing the method on the instance rather
than defining it away on the prototype types cleanly too.1 parent e954b81 commit aff7c4c
71 files changed
Lines changed: 1006 additions & 94 deletions
File tree
- .changeset
- lib
- container
- css
- dependencies
- esm
- hmr
- node
- prefetch
- runtime
- sharing
- util
- wasm-async
- wasm-sync
- webworker
- web
- test
- configCases
- html
- inline-script-classic/__snapshots__
- script-src-classic/__snapshots__
- runtime
- foreign-runtime-module-dispatch
- legacy-compat-chunk-handler
- on-chunks-loaded-priority
- single-chunk-handler-dispatch
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
247 | 247 | | |
248 | 248 | | |
249 | 249 | | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
250 | 255 | | |
251 | 256 | | |
252 | 257 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
150 | 150 | | |
151 | 151 | | |
152 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
153 | 164 | | |
154 | 165 | | |
155 | 166 | | |
| |||
242 | 253 | | |
243 | 254 | | |
244 | 255 | | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
245 | 263 | | |
246 | 264 | | |
247 | 265 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
233 | 233 | | |
234 | 234 | | |
235 | 235 | | |
236 | | - | |
237 | 236 | | |
238 | 237 | | |
239 | 238 | | |
| |||
320 | 319 | | |
321 | 320 | | |
322 | 321 | | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
323 | 332 | | |
324 | 333 | | |
325 | 334 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
23 | 32 | | |
24 | 33 | | |
25 | 34 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
33 | 42 | | |
34 | 43 | | |
35 | 44 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
56 | 57 | | |
57 | 58 | | |
58 | 59 | | |
59 | | - | |
60 | | - | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
61 | 64 | | |
62 | | - | |
63 | | - | |
64 | | - | |
| 65 | + | |
65 | 66 | | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
| 67 | + | |
79 | 68 | | |
80 | 69 | | |
81 | 70 | | |
| |||
96 | 85 | | |
97 | 86 | | |
98 | 87 | | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
99 | 157 | | |
100 | 158 | | |
101 | 159 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
29 | 38 | | |
30 | 39 | | |
31 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
28 | 37 | | |
29 | 38 | | |
30 | 39 | | |
| |||
58 | 67 | | |
59 | 68 | | |
60 | 69 | | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
61 | 79 | | |
62 | 80 | | |
63 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
283 | 283 | | |
284 | 284 | | |
285 | 285 | | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
286 | 295 | | |
287 | 296 | | |
288 | 297 | | |
| |||
324 | 333 | | |
325 | 334 | | |
326 | 335 | | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
327 | 345 | | |
328 | 346 | | |
329 | 347 | | |
| |||
0 commit comments