webpack 5.107.1 → 5.107.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Compiler.js +27 -3
- package/lib/ContextModuleFactory.js +45 -38
- package/lib/MultiCompiler.js +14 -0
- package/lib/NormalModule.js +459 -41
- package/lib/ProgressPlugin.js +1 -1
- package/lib/SourceMapDevToolPlugin.js +102 -25
- package/lib/buildChunkGraph.js +24 -2
- package/lib/cache/getLazyHashedEtag.js +9 -2
- package/lib/dependencies/HarmonyExportInitFragment.js +8 -9
- package/lib/dependencies/HtmlInlineScriptDependency.js +3 -14
- package/lib/dependencies/HtmlInlineStyleDependency.js +17 -0
- package/lib/dependencies/HtmlScriptSrcDependency.js +6 -45
- package/lib/dependencies/HtmlSourceDependency.js +18 -0
- package/lib/dependencies/WorkerPlugin.js +18 -4
- package/lib/hmr/LazyCompilationPlugin.js +104 -0
- package/lib/html/HtmlGenerator.js +81 -33
- package/lib/html/HtmlModulesPlugin.js +86 -23
- package/lib/javascript/JavascriptParser.js +1 -1
- package/lib/library/ModuleLibraryPlugin.js +30 -24
- package/lib/node/NodeWatchFileSystem.js +37 -22
- package/lib/optimize/ConcatenatedModule.js +3 -2
- package/lib/util/fs.js +6 -1
- package/package.json +3 -3
- package/types.d.ts +117 -5
|
@@ -17,6 +17,8 @@ const CssUrlDependency = require("../dependencies/CssUrlDependency");
|
|
|
17
17
|
|
|
18
18
|
/** @typedef {import("webpack-sources").Source} Source */
|
|
19
19
|
/** @typedef {import("../../declarations/WebpackOptions").HtmlGeneratorOptions} HtmlGeneratorOptions */
|
|
20
|
+
/** @typedef {import("../Chunk")} Chunk */
|
|
21
|
+
/** @typedef {import("../Compilation")} Compilation */
|
|
20
22
|
/** @typedef {import("../Compilation").DependencyConstructor} DependencyConstructor */
|
|
21
23
|
/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
|
|
22
24
|
/** @typedef {import("../Dependency")} Dependency */
|
|
@@ -39,7 +41,76 @@ const CssUrlDependency = require("../dependencies/CssUrlDependency");
|
|
|
39
41
|
*/
|
|
40
42
|
const JAVASCRIPT_AND_HTML_TYPES = new Set([JAVASCRIPT_TYPE, HTML_TYPE]);
|
|
41
43
|
|
|
44
|
+
/** @type {WeakMap<Compilation, Map<string, Chunk>>} */
|
|
45
|
+
const chunksByIdCache = new WeakMap();
|
|
46
|
+
|
|
42
47
|
class HtmlGenerator extends Generator {
|
|
48
|
+
/**
|
|
49
|
+
* Emit a sentinel for a chunk URL that can't be resolved at code-gen time
|
|
50
|
+
* (chunk hashes aren't computed yet); `resolveChunkUrlSentinels` swaps it
|
|
51
|
+
* for `${PUBLIC_PATH_AUTO}<chunkFilename>` once they are.
|
|
52
|
+
* @param {Chunk} chunk chunk
|
|
53
|
+
* @param {"javascript" | "css"} contentHashType which chunk content hash slot the resolved URL should reference
|
|
54
|
+
* @returns {string} sentinel
|
|
55
|
+
*/
|
|
56
|
+
static makeChunkUrlSentinel(chunk, contentHashType) {
|
|
57
|
+
const hexId = Buffer.from(String(chunk.id), "utf8").toString("hex");
|
|
58
|
+
return `__WEBPACK_HTML_CHUNK_URL__${hexId}__${contentHashType}__END__`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Replace every `makeChunkUrlSentinel` sentinel in `content` with
|
|
63
|
+
* `${PUBLIC_PATH_AUTO}<chunkFilename>`. Must run after
|
|
64
|
+
* `Compilation#createHash()` so `[contenthash]` resolves.
|
|
65
|
+
* @param {string} content content
|
|
66
|
+
* @param {Compilation} compilation compilation
|
|
67
|
+
* @returns {string} resolved content
|
|
68
|
+
*/
|
|
69
|
+
static resolveChunkUrlSentinels(content, compilation) {
|
|
70
|
+
if (!content.includes("__WEBPACK_HTML_CHUNK_URL__")) return content;
|
|
71
|
+
const outputOptions = compilation.outputOptions;
|
|
72
|
+
let chunksById = chunksByIdCache.get(compilation);
|
|
73
|
+
if (chunksById === undefined) {
|
|
74
|
+
chunksById = new Map();
|
|
75
|
+
for (const chunk of compilation.chunks) {
|
|
76
|
+
chunksById.set(String(chunk.id), chunk);
|
|
77
|
+
}
|
|
78
|
+
chunksByIdCache.set(compilation, chunksById);
|
|
79
|
+
}
|
|
80
|
+
return content.replace(
|
|
81
|
+
/__WEBPACK_HTML_CHUNK_URL__([0-9a-f]+)__([a-z]+)__END__/g,
|
|
82
|
+
(_, hexId, contentHashType) => {
|
|
83
|
+
const chunkId = Buffer.from(hexId, "hex").toString("utf8");
|
|
84
|
+
const chunk = chunksById.get(chunkId);
|
|
85
|
+
if (!chunk) return "data:,";
|
|
86
|
+
let filenameTemplate;
|
|
87
|
+
if (contentHashType === "css") {
|
|
88
|
+
const CssModulesPlugin = require("../css/CssModulesPlugin");
|
|
89
|
+
|
|
90
|
+
filenameTemplate = CssModulesPlugin.getChunkFilenameTemplate(
|
|
91
|
+
chunk,
|
|
92
|
+
outputOptions
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
filenameTemplate =
|
|
96
|
+
chunk.filenameTemplate ||
|
|
97
|
+
(chunk.canBeInitial()
|
|
98
|
+
? outputOptions.filename
|
|
99
|
+
: outputOptions.chunkFilename);
|
|
100
|
+
}
|
|
101
|
+
const filename = compilation.getPath(
|
|
102
|
+
/** @type {import("../TemplatedPathPlugin").TemplatePath} */
|
|
103
|
+
(filenameTemplate),
|
|
104
|
+
{
|
|
105
|
+
chunk,
|
|
106
|
+
contentHashType
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
return `${CssUrlDependency.PUBLIC_PATH_AUTO}${filename}`;
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
43
114
|
/**
|
|
44
115
|
* Creates an instance of HtmlGenerator.
|
|
45
116
|
* @param {HtmlGeneratorOptions=} options generator options
|
|
@@ -268,28 +339,15 @@ class HtmlGenerator extends Generator {
|
|
|
268
339
|
this.sourceModule(module, initFragments, source, generateContext);
|
|
269
340
|
|
|
270
341
|
if (undoPath === undefined) {
|
|
342
|
+
// HTML output — leave sentinels and `[webpack/auto]` for renderManifest.
|
|
271
343
|
return /** @type {string} */ (source.source());
|
|
272
344
|
}
|
|
273
345
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
for (
|
|
280
|
-
let idx = moduleSourceContent.indexOf(autoPlaceholder);
|
|
281
|
-
idx !== -1;
|
|
282
|
-
idx = moduleSourceContent.indexOf(
|
|
283
|
-
autoPlaceholder,
|
|
284
|
-
idx + autoPlaceholderLen
|
|
285
|
-
)
|
|
286
|
-
) {
|
|
287
|
-
generatedSource.replace(idx, idx + autoPlaceholderLen - 1, undoPath);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// TODO handle `[fullhash]`
|
|
291
|
-
|
|
292
|
-
return /** @type {string} */ (generatedSource.source());
|
|
346
|
+
// JS-export path — resolve `[webpack/auto]` inline; chunk-URL sentinels
|
|
347
|
+
// stay for `HtmlModulesPlugin`'s `JavascriptModulesPlugin.render` tap.
|
|
348
|
+
let content = /** @type {string} */ (source.source());
|
|
349
|
+
content = content.split(CssUrlDependency.PUBLIC_PATH_AUTO).join(undoPath);
|
|
350
|
+
return content;
|
|
293
351
|
}
|
|
294
352
|
|
|
295
353
|
/**
|
|
@@ -306,16 +364,13 @@ class HtmlGenerator extends Generator {
|
|
|
306
364
|
}
|
|
307
365
|
|
|
308
366
|
if (generateContext.type === HTML_TYPE) {
|
|
309
|
-
// Preserve `[webpack/auto]
|
|
310
|
-
// `renderManifest` hook knows the final `.html` filename and
|
|
311
|
-
// resolves them to an undo path relative to that location.
|
|
367
|
+
// Preserve `[webpack/auto]`; renderManifest resolves it once `.html` filename is known.
|
|
312
368
|
return new RawSource(
|
|
313
369
|
this._renderHtml(module, generateContext, undefined)
|
|
314
370
|
);
|
|
315
371
|
}
|
|
316
372
|
|
|
317
|
-
// JS export:
|
|
318
|
-
// runtime, so resolve placeholders to root-relative URLs.
|
|
373
|
+
// JS export: resolve `[webpack/auto]` to root-relative URLs.
|
|
319
374
|
const generated = this._renderHtml(module, generateContext, "");
|
|
320
375
|
|
|
321
376
|
/** @type {string} */
|
|
@@ -346,10 +401,7 @@ class HtmlGenerator extends Generator {
|
|
|
346
401
|
*/
|
|
347
402
|
generateError(error, module, generateContext) {
|
|
348
403
|
if (generateContext.type === HTML_TYPE) {
|
|
349
|
-
//
|
|
350
|
-
// input, dep request strings). Strip `<`, `>`, and `--` runs so a
|
|
351
|
-
// crafted message can't close the comment with `-->` (or open a
|
|
352
|
-
// fake nested comment) and inject HTML into the extracted page.
|
|
404
|
+
// Strip `<`, `>`, `--` runs from `error.message` so it can't escape the comment.
|
|
353
405
|
const safe = String(error.message)
|
|
354
406
|
.replace(/[<>]/g, "")
|
|
355
407
|
.replace(/-{2,}/g, (m) => `${"-".repeat(m.length - 1)} `);
|
|
@@ -365,11 +417,7 @@ class HtmlGenerator extends Generator {
|
|
|
365
417
|
*/
|
|
366
418
|
updateHash(hash, updateHashContext) {
|
|
367
419
|
hash.update("html");
|
|
368
|
-
// Hash
|
|
369
|
-
// so the module hash flips when a module becomes (or stops being)
|
|
370
|
-
// a compilation entry under the `extract: undefined` default — the
|
|
371
|
-
// generator's source-type set changes with it, so any cached
|
|
372
|
-
// HTML-type codegen result must be invalidated.
|
|
420
|
+
// Hash effective extraction state — source-type set changes when this flips.
|
|
373
421
|
if (this._shouldExtract(updateHashContext.module)) {
|
|
374
422
|
hash.update("extract");
|
|
375
423
|
}
|
|
@@ -45,12 +45,43 @@ const generatorValidationOptions = {
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
class HtmlModulesPlugin {
|
|
48
|
+
/**
|
|
49
|
+
* `output.hashFunction`/`hashSalt`/`hashDigest`/`hashDigestLength`
|
|
50
|
+
* digest of `content`, with `nonNumericOnlyHash` applied — webpack's
|
|
51
|
+
* standard `[contenthash]` recipe.
|
|
52
|
+
* @param {string | Buffer} content content to hash
|
|
53
|
+
* @param {import("../../declarations/WebpackOptions").Output} outputOptions output options
|
|
54
|
+
* @returns {string} content hash
|
|
55
|
+
*/
|
|
56
|
+
static computeContentHash(content, outputOptions) {
|
|
57
|
+
const createHash = require("../util/createHash");
|
|
58
|
+
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
|
|
59
|
+
|
|
60
|
+
const hash = createHash(
|
|
61
|
+
/** @type {import("../../declarations/WebpackOptions").HashFunction} */
|
|
62
|
+
(outputOptions.hashFunction)
|
|
63
|
+
);
|
|
64
|
+
if (outputOptions.hashSalt) hash.update(outputOptions.hashSalt);
|
|
65
|
+
hash.update(content);
|
|
66
|
+
return nonNumericOnlyHash(
|
|
67
|
+
/** @type {string} */ (
|
|
68
|
+
hash.digest(/** @type {string} */ (outputOptions.hashDigest))
|
|
69
|
+
),
|
|
70
|
+
/** @type {number} */ (outputOptions.hashDigestLength)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
48
74
|
/**
|
|
49
75
|
* Applies the plugin by registering its hooks on the compiler.
|
|
50
76
|
* @param {Compiler} compiler the compiler instance
|
|
51
77
|
* @returns {void}
|
|
52
78
|
*/
|
|
53
79
|
apply(compiler) {
|
|
80
|
+
// Per-chunk `RawSource` reused across builds when bytes are unchanged:
|
|
81
|
+
// keeping identity stable avoids invalidating `RealContentHashPlugin|analyse`.
|
|
82
|
+
/** @type {Map<string, { content: string, source: import("webpack-sources").RawSource }>} */
|
|
83
|
+
const sentinelResolvedSourceCache = new Map();
|
|
84
|
+
|
|
54
85
|
// `<script src>` and `<link rel="modulepreload">` references collected
|
|
55
86
|
// by HtmlParser become real compilation entries here. The classic
|
|
56
87
|
// and esm-script groups are chained via a leader-only dependOn so
|
|
@@ -296,8 +327,6 @@ class HtmlModulesPlugin {
|
|
|
296
327
|
getUndoPath,
|
|
297
328
|
makePathsRelative
|
|
298
329
|
} = require("../util/identifier");
|
|
299
|
-
const createHash = require("../util/createHash");
|
|
300
|
-
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
|
|
301
330
|
const CssUrlDependency = require("../dependencies/CssUrlDependency");
|
|
302
331
|
|
|
303
332
|
const autoPlaceholder = CssUrlDependency.PUBLIC_PATH_AUTO;
|
|
@@ -342,17 +371,15 @@ class HtmlModulesPlugin {
|
|
|
342
371
|
const placeholderContent = /** @type {string} */ (
|
|
343
372
|
placeholderSource.source()
|
|
344
373
|
);
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const fullContentHash = /** @type {string} */ (
|
|
351
|
-
hashInput.digest(outputOptions.hashDigest)
|
|
374
|
+
// Resolve sentinels *before* hashing so the HTML's `[contenthash]`
|
|
375
|
+
// invalidates with the referenced chunks' filenames.
|
|
376
|
+
const resolvedContent = HtmlGenerator.resolveChunkUrlSentinels(
|
|
377
|
+
placeholderContent,
|
|
378
|
+
compilation
|
|
352
379
|
);
|
|
353
|
-
const contentHash =
|
|
354
|
-
|
|
355
|
-
outputOptions
|
|
380
|
+
const contentHash = HtmlModulesPlugin.computeContentHash(
|
|
381
|
+
resolvedContent,
|
|
382
|
+
outputOptions
|
|
356
383
|
);
|
|
357
384
|
|
|
358
385
|
const { path: filename, info } = compilation.getPathWithInfo(
|
|
@@ -382,7 +409,7 @@ class HtmlModulesPlugin {
|
|
|
382
409
|
/** @type {string} */ (outputOptions.path),
|
|
383
410
|
false
|
|
384
411
|
);
|
|
385
|
-
const finalContent =
|
|
412
|
+
const finalContent = resolvedContent
|
|
386
413
|
.split(autoPlaceholder)
|
|
387
414
|
.join(undoPath);
|
|
388
415
|
const finalSource = new RawSource(finalContent);
|
|
@@ -395,16 +422,9 @@ class HtmlModulesPlugin {
|
|
|
395
422
|
// the post-undo-path content in the hash, so the
|
|
396
423
|
// asset cache can't reuse one variant's bytes at
|
|
397
424
|
// another variant's URL.
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
finalHash.update(finalContent);
|
|
403
|
-
const finalContentHash = nonNumericOnlyHash(
|
|
404
|
-
/** @type {string} */ (
|
|
405
|
-
finalHash.digest(outputOptions.hashDigest)
|
|
406
|
-
),
|
|
407
|
-
outputOptions.hashDigestLength
|
|
425
|
+
const finalContentHash = HtmlModulesPlugin.computeContentHash(
|
|
426
|
+
finalContent,
|
|
427
|
+
outputOptions
|
|
408
428
|
);
|
|
409
429
|
|
|
410
430
|
result.push({
|
|
@@ -421,6 +441,49 @@ class HtmlModulesPlugin {
|
|
|
421
441
|
return result;
|
|
422
442
|
}
|
|
423
443
|
);
|
|
444
|
+
|
|
445
|
+
// Resolve sentinels at JS chunk render time so later passes
|
|
446
|
+
// (SourceMapDevToolPlugin, size optimizers, RealContentHash) see resolved bytes.
|
|
447
|
+
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
|
|
448
|
+
|
|
449
|
+
const jsHooks =
|
|
450
|
+
JavascriptModulesPlugin.getCompilationHooks(compilation);
|
|
451
|
+
jsHooks.render.tap(PLUGIN_NAME, (source, renderContext) => {
|
|
452
|
+
const raw = source.source();
|
|
453
|
+
if (typeof raw !== "string") return source;
|
|
454
|
+
if (!raw.includes("__WEBPACK_HTML_CHUNK_URL__")) return source;
|
|
455
|
+
const resolved = HtmlGenerator.resolveChunkUrlSentinels(
|
|
456
|
+
raw,
|
|
457
|
+
compilation
|
|
458
|
+
)
|
|
459
|
+
.split(autoPlaceholder)
|
|
460
|
+
.join("");
|
|
461
|
+
if (resolved === raw) return source;
|
|
462
|
+
const chunkId = String(renderContext.chunk.id);
|
|
463
|
+
const prior = sentinelResolvedSourceCache.get(chunkId);
|
|
464
|
+
if (prior !== undefined && prior.content === resolved) {
|
|
465
|
+
return prior.source;
|
|
466
|
+
}
|
|
467
|
+
const newSource = new RawSource(resolved);
|
|
468
|
+
sentinelResolvedSourceCache.set(chunkId, {
|
|
469
|
+
content: resolved,
|
|
470
|
+
source: newSource
|
|
471
|
+
});
|
|
472
|
+
return newSource;
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Prune cache entries for chunks no longer in the graph so a
|
|
476
|
+
// long watch session can't accumulate stale entries.
|
|
477
|
+
compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => {
|
|
478
|
+
if (sentinelResolvedSourceCache.size === 0) return;
|
|
479
|
+
const live = new Set();
|
|
480
|
+
for (const chunk of compilation.chunks) {
|
|
481
|
+
live.add(String(chunk.id));
|
|
482
|
+
}
|
|
483
|
+
for (const id of sentinelResolvedSourceCache.keys()) {
|
|
484
|
+
if (!live.has(id)) sentinelResolvedSourceCache.delete(id);
|
|
485
|
+
}
|
|
486
|
+
});
|
|
424
487
|
}
|
|
425
488
|
);
|
|
426
489
|
}
|
|
@@ -127,7 +127,7 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
|
|
127
127
|
|
|
128
128
|
/** @typedef {Set<DestructuringAssignmentProperty>} DestructuringAssignmentProperties */
|
|
129
129
|
|
|
130
|
-
// TODO remove cast when @types/estree has been updated to import
|
|
130
|
+
// TODO remove cast when @types/estree has been updated to import phases
|
|
131
131
|
/** @typedef {import("estree").ImportExpression & { phase?: "defer" | "source" }} ImportExpression */
|
|
132
132
|
|
|
133
133
|
/** @type {string[]} */
|
|
@@ -111,24 +111,15 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin {
|
|
|
111
111
|
|
|
112
112
|
// `ModuleLibraryPlugin` stashes the on-demand exports source via
|
|
113
113
|
// `onDemandExportsGeneration` and only re-emits it when the
|
|
114
|
-
// module is wrapped in an IIFE/factory. When
|
|
115
|
-
//
|
|
114
|
+
// module is wrapped in an IIFE/factory. When the entry is
|
|
115
|
+
// inlined directly, the stashed source — and the
|
|
116
116
|
// `definePropertyGetters` / `requireScope` runtime helpers it
|
|
117
117
|
// pulled in — never make it into the output. Drop those helpers
|
|
118
|
-
// from the chunk's set
|
|
119
|
-
// clean.
|
|
118
|
+
// from the chunk's set so the bundle stays clean.
|
|
120
119
|
compilation.hooks.additionalChunkRuntimeRequirements.tap(
|
|
121
120
|
PLUGIN_NAME,
|
|
122
121
|
(chunk, set, { chunkGraph, codeGenerationResults }) => {
|
|
123
122
|
if (!set.has(RuntimeGlobals.definePropertyGetters)) return;
|
|
124
|
-
|
|
125
|
-
// Only handle the simple "single concatenated entry"
|
|
126
|
-
// shape. Anything else (additional modules, multiple
|
|
127
|
-
// entries, sibling runtime chunks, or chunk-level
|
|
128
|
-
// requirements that disable inline startup) forces the
|
|
129
|
-
// module through factory/IIFE rendering, which re-emits
|
|
130
|
-
// the source.
|
|
131
|
-
if (chunkGraph.getNumberOfChunkModules(chunk) !== 1) return;
|
|
132
123
|
if (chunkGraph.getNumberOfEntryModules(chunk) !== 1) return;
|
|
133
124
|
if (chunkGraph.hasChunkEntryDependentChunks(chunk)) return;
|
|
134
125
|
if (
|
|
@@ -140,8 +131,6 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin {
|
|
|
140
131
|
) {
|
|
141
132
|
return;
|
|
142
133
|
}
|
|
143
|
-
// Anyone tapping `inlineInRuntimeBailout` may force factory
|
|
144
|
-
// rendering at render time, so conservatively bail out.
|
|
145
134
|
if (javascriptHooks.inlineInRuntimeBailout.isUsed()) return;
|
|
146
135
|
|
|
147
136
|
const [module] = chunkGraph.getChunkEntryModulesIterable(chunk);
|
|
@@ -153,14 +142,6 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin {
|
|
|
153
142
|
) {
|
|
154
143
|
return;
|
|
155
144
|
}
|
|
156
|
-
// If the generated source references any
|
|
157
|
-
// `__webpack_require__.<helper>` (the on-demand `.d(...)`
|
|
158
|
-
// is stashed, but `.r(__webpack_exports__)` from the ESM
|
|
159
|
-
// compat flag, namespace objects, deferred externals, ...
|
|
160
|
-
// stay in the result) the helpers and the require scope
|
|
161
|
-
// they live in are still needed. The dot in the substring
|
|
162
|
-
// avoids matching the bare `"__webpack_require__"` string
|
|
163
|
-
// literals that some test fixtures include.
|
|
164
145
|
const codeGenResult = codeGenerationResults.get(
|
|
165
146
|
module,
|
|
166
147
|
chunk.runtime
|
|
@@ -174,9 +155,34 @@ class ModuleLibraryPlugin extends AbstractLibraryPlugin {
|
|
|
174
155
|
return;
|
|
175
156
|
}
|
|
176
157
|
|
|
158
|
+
// Check whether any other module in the chunk still needs
|
|
159
|
+
// the helpers we want to remove.
|
|
160
|
+
let otherNeedsDefine = false;
|
|
161
|
+
let otherNeedsExports = false;
|
|
162
|
+
let otherNeedsRequireScope = false;
|
|
163
|
+
for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
|
|
164
|
+
if (m === module) continue;
|
|
165
|
+
const requirements = chunkGraph.getModuleRuntimeRequirements(
|
|
166
|
+
m,
|
|
167
|
+
chunk.runtime
|
|
168
|
+
);
|
|
169
|
+
if (!requirements) continue;
|
|
170
|
+
if (requirements.has(RuntimeGlobals.definePropertyGetters)) {
|
|
171
|
+
otherNeedsDefine = true;
|
|
172
|
+
}
|
|
173
|
+
if (requirements.has(RuntimeGlobals.exports)) {
|
|
174
|
+
otherNeedsExports = true;
|
|
175
|
+
}
|
|
176
|
+
if (requirements.has(RuntimeGlobals.requireScope)) {
|
|
177
|
+
otherNeedsRequireScope = true;
|
|
178
|
+
}
|
|
179
|
+
if (otherNeedsDefine) break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (otherNeedsDefine) return;
|
|
177
183
|
set.delete(RuntimeGlobals.definePropertyGetters);
|
|
178
|
-
set.delete(RuntimeGlobals.exports);
|
|
179
|
-
set.delete(RuntimeGlobals.requireScope);
|
|
184
|
+
if (!otherNeedsExports) set.delete(RuntimeGlobals.exports);
|
|
185
|
+
if (!otherNeedsRequireScope) set.delete(RuntimeGlobals.requireScope);
|
|
180
186
|
}
|
|
181
187
|
);
|
|
182
188
|
});
|
|
@@ -82,6 +82,41 @@ class NodeWatchFileSystem {
|
|
|
82
82
|
}
|
|
83
83
|
return { fileTimeInfoEntries, contextTimeInfoEntries };
|
|
84
84
|
};
|
|
85
|
+
const directoriesSet =
|
|
86
|
+
directories instanceof Set ? directories : new Set(directories);
|
|
87
|
+
|
|
88
|
+
// Watchpack reports a watched directory (a context dependency) in
|
|
89
|
+
// `changes` whenever its contents change, alongside the individual
|
|
90
|
+
// file events. The default `fs.purge(dir)` matches cache keys by
|
|
91
|
+
// prefix, so it would wipe the stat cache of every file inside the
|
|
92
|
+
// directory even though only file-level events actually invalidate
|
|
93
|
+
// file stats. For directories we explicitly watch, purge only the
|
|
94
|
+
// directory's own entry (`{ exact: true }`, enhanced-resolve >=
|
|
95
|
+
// 5.22.0); file-level events in the same aggregated batch still
|
|
96
|
+
// handle file stats and the parent readdir invalidation.
|
|
97
|
+
/**
|
|
98
|
+
* @param {Changes | null | undefined} changes changes set
|
|
99
|
+
* @param {Removals | null | undefined} removals removals set
|
|
100
|
+
*/
|
|
101
|
+
const purgeChanges = (changes, removals) => {
|
|
102
|
+
const fs = this.inputFileSystem;
|
|
103
|
+
if (!fs || !fs.purge) return;
|
|
104
|
+
if (changes) {
|
|
105
|
+
for (const item of changes) {
|
|
106
|
+
if (directoriesSet.has(item)) {
|
|
107
|
+
fs.purge(item, { exact: true });
|
|
108
|
+
} else {
|
|
109
|
+
fs.purge(item);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (removals) {
|
|
114
|
+
for (const item of removals) {
|
|
115
|
+
fs.purge(item);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
85
120
|
this.watcher.once(
|
|
86
121
|
"aggregated",
|
|
87
122
|
/**
|
|
@@ -94,15 +129,7 @@ class NodeWatchFileSystem {
|
|
|
94
129
|
/** @type {Watchpack} */
|
|
95
130
|
(this.watcher).pause();
|
|
96
131
|
|
|
97
|
-
|
|
98
|
-
if (fs && fs.purge) {
|
|
99
|
-
for (const item of changes) {
|
|
100
|
-
fs.purge(item);
|
|
101
|
-
}
|
|
102
|
-
for (const item of removals) {
|
|
103
|
-
fs.purge(item);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
132
|
+
purgeChanges(changes, removals);
|
|
106
133
|
const { fileTimeInfoEntries, contextTimeInfoEntries } = fetchTimeInfo();
|
|
107
134
|
callback(
|
|
108
135
|
null,
|
|
@@ -172,19 +199,7 @@ class NodeWatchFileSystem {
|
|
|
172
199
|
getInfo: () => {
|
|
173
200
|
const removals = this.watcher && this.watcher.aggregatedRemovals;
|
|
174
201
|
const changes = this.watcher && this.watcher.aggregatedChanges;
|
|
175
|
-
|
|
176
|
-
if (fs && fs.purge) {
|
|
177
|
-
if (removals) {
|
|
178
|
-
for (const item of removals) {
|
|
179
|
-
fs.purge(item);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
if (changes) {
|
|
183
|
-
for (const item of changes) {
|
|
184
|
-
fs.purge(item);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
202
|
+
purgeChanges(changes, removals);
|
|
188
203
|
const { fileTimeInfoEntries, contextTimeInfoEntries } = fetchTimeInfo();
|
|
189
204
|
return {
|
|
190
205
|
changes,
|
|
@@ -2317,8 +2317,9 @@ ${defineGetters}`
|
|
|
2317
2317
|
info.module.updateHash(hash, context);
|
|
2318
2318
|
break;
|
|
2319
2319
|
case "external":
|
|
2320
|
-
hash.update(
|
|
2321
|
-
|
|
2320
|
+
hash.update(
|
|
2321
|
+
`${chunkGraph.getModuleId(info.module)}|${runtimeConditionToString(info.runtimeCondition)}|${info.nonDeferAccess ? "1" : "0"}|${chunkGraph.moduleGraph.isDeferred(info.module) ? "1" : "0"}`
|
|
2322
|
+
);
|
|
2322
2323
|
break;
|
|
2323
2324
|
}
|
|
2324
2325
|
}
|
package/lib/util/fs.js
CHANGED
|
@@ -308,7 +308,12 @@ const path = require("path");
|
|
|
308
308
|
|
|
309
309
|
/**
|
|
310
310
|
* Defines the purge type used by this module.
|
|
311
|
-
*
|
|
311
|
+
*
|
|
312
|
+
* `options.exact` (supported by enhanced-resolve's `CachedInputFileSystem`
|
|
313
|
+
* from v5.22.0): when true, only entries whose key exactly matches `value`
|
|
314
|
+
* are invalidated; cached entries for descendants are preserved. Default
|
|
315
|
+
* is false (legacy prefix-match behavior).
|
|
316
|
+
* @typedef {(value?: string | string[] | Set<string>, options?: { exact?: boolean }) => void} Purge
|
|
312
317
|
*/
|
|
313
318
|
|
|
314
319
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webpack",
|
|
3
|
-
"version": "5.107.
|
|
3
|
+
"version": "5.107.2",
|
|
4
4
|
"description": "Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
|
|
5
5
|
"homepage": "https://github.com/webpack/webpack",
|
|
6
6
|
"bugs": "https://github.com/webpack/webpack/issues",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"acorn-import-phases": "^1.0.3",
|
|
98
98
|
"browserslist": "^4.28.1",
|
|
99
99
|
"chrome-trace-event": "^1.0.2",
|
|
100
|
-
"enhanced-resolve": "^5.
|
|
100
|
+
"enhanced-resolve": "^5.22.0",
|
|
101
101
|
"es-module-lexer": "^2.1.0",
|
|
102
102
|
"eslint-scope": "5.1.1",
|
|
103
103
|
"events": "^3.2.0",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"tapable": "^2.3.0",
|
|
111
111
|
"terser-webpack-plugin": "^5.5.0",
|
|
112
112
|
"watchpack": "^2.5.1",
|
|
113
|
-
"webpack-sources": "^3.
|
|
113
|
+
"webpack-sources": "^3.5.0"
|
|
114
114
|
},
|
|
115
115
|
"devDependencies": {
|
|
116
116
|
"@babel/core": "^7.27.1",
|