webpack 5.110.0 → 5.110.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/README.md +10 -17
- package/lib/ExportsInfo.js +10 -0
- package/lib/FileSystemInfo.js +17 -2
- package/lib/Generator.js +17 -0
- package/lib/NormalModule.js +3 -3
- package/lib/RuntimeTemplate.js +423 -430
- package/lib/asset/AssetBytesGenerator.js +1 -3
- package/lib/asset/AssetGenerator.js +1 -3
- package/lib/asset/AssetSourceGenerator.js +1 -3
- package/lib/config/defaults.js +6 -0
- package/lib/css/CssGenerator.js +1 -3
- package/lib/css/CssLoadingRuntimeModule.js +32 -13
- package/lib/css/CssModulesPlugin.js +9 -17
- package/lib/css/data.js +13 -3
- package/lib/css/syntax.js +78 -10
- package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +10 -4
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +2 -0
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +48 -3
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +83 -14
- package/lib/dependencies/HarmonyImportSideEffectDependency.js +114 -0
- package/lib/dependencies/WorkerAndWorkletPlugin.js +1 -0
- package/lib/dependencies/WorkerDependency.js +6 -12
- package/lib/dependencies/WorkletDependency.js +7 -11
- package/lib/esm/ModuleChunkLoadingPlugin.js +6 -9
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +7 -1
- package/lib/html/HtmlGenerator.js +1 -1
- package/lib/html/HtmlModulesPlugin.js +55 -16
- package/lib/html/syntax.js +113 -26
- package/lib/javascript/JavascriptGenerator.js +1 -1
- package/lib/javascript/JavascriptModulesPlugin.js +3 -10
- package/lib/json/JsonGenerator.js +1 -1
- package/lib/loaders/LoaderRunner.js +33 -5
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +8 -15
- package/lib/optimize/ConcatenatedModule.js +8 -0
- package/lib/optimize/ConstExportsPlugin.js +5 -0
- package/lib/optimize/InlineExports.js +121 -0
- package/lib/optimize/RealContentHashPlugin.js +111 -35
- package/lib/prefetch/ResourceHintPlugin.js +6 -12
- package/lib/serialization/ObjectMiddleware.js +128 -108
- package/lib/typescript/TypeScriptPlugin.js +8 -10
- package/lib/util/SourceProcessor.js +24 -8
- package/lib/util/createMappings.js +25 -3
- package/lib/util/removeBOM.js +82 -1
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +5 -3
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +5 -3
- package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +3 -1
- package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +7 -12
- package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +3 -1
- package/lib/web/FetchCompileAsyncWasmPlugin.js +10 -6
- package/lib/web/FetchCompileWasmPlugin.js +4 -2
- package/package.json +1 -1
- package/types.d.ts +77 -10
package/lib/RuntimeTemplate.js
CHANGED
|
@@ -178,6 +178,20 @@ const DEFER_BAILOUT =
|
|
|
178
178
|
* @property {boolean | null} loaded whether the chunk loader fetched the chunk
|
|
179
179
|
*/
|
|
180
180
|
|
|
181
|
+
/**
|
|
182
|
+
* @typedef {object} AnalyzableChunkUrls
|
|
183
|
+
* @property {Map<ChunkId, string>} urls the urls that could be written, by chunk id
|
|
184
|
+
* @property {boolean} complete false when some chunk kept the runtime form, whose
|
|
185
|
+
* ids the consumer then still resolves through the runtime name lookup
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @typedef {object} WasmGroups
|
|
190
|
+
* @property {(key: string) => string} groupOf the group a runtime key answers with
|
|
191
|
+
* @property {Set<string>} fetching groups an entry of which reads binaries with `fetch`
|
|
192
|
+
* @property {Map<string, boolean>} onlyFetching groups every entry of which fetches
|
|
193
|
+
*/
|
|
194
|
+
|
|
181
195
|
// A reference in no chunk at all: nothing is known about where it is read from.
|
|
182
196
|
/** @type {Placement} */
|
|
183
197
|
const NO_PLACEMENT = { undo: null, loaded: null };
|
|
@@ -242,6 +256,10 @@ const SPECIFIER_PART_KINDS = new Set([
|
|
|
242
256
|
// Only these carry a chunk id, which is the one part value that may be a number.
|
|
243
257
|
const CHUNK_SPECIFIER_PART_KINDS = new Set(["chunk", "cssChunk"]);
|
|
244
258
|
|
|
259
|
+
// Only these are spelled out of the compilation hash, so a stand-in holding one moves
|
|
260
|
+
// the chunk it lands in into the round after that hash settles.
|
|
261
|
+
const FULL_HASH_PART_KINDS = new Set(["publicPath", "template", "unserved"]);
|
|
262
|
+
|
|
245
263
|
// What the deferred pass scans for — the other half of what the class spells.
|
|
246
264
|
const ANALYZABLE_TOKEN_REGEXP = /\.\/@@webpackAnalyzableChunk:([\w-]+)@@/g;
|
|
247
265
|
|
|
@@ -331,6 +349,25 @@ const createHashProbeChunk = (chunk, hash, present) => {
|
|
|
331
349
|
return probeChunk;
|
|
332
350
|
};
|
|
333
351
|
|
|
352
|
+
/**
|
|
353
|
+
* A filename function's answer to the stand-in hash, which says what shape the name
|
|
354
|
+
* has before any real hash exists.
|
|
355
|
+
* @param {Exclude<ChunkFilenameTemplate, string>} template the filename function
|
|
356
|
+
* @param {Chunk} chunk the chunk being referenced
|
|
357
|
+
* @param {string} contentHashType which of the chunk's hashes the name reads
|
|
358
|
+
* @param {string} hash the stand-in hash
|
|
359
|
+
* @param {boolean} present whether the chunk is claimed to carry content hashes
|
|
360
|
+
* @returns {string} what the function names it
|
|
361
|
+
*/
|
|
362
|
+
const probeTemplateName = (template, chunk, contentHashType, hash, present) =>
|
|
363
|
+
template({
|
|
364
|
+
chunk: createHashProbeChunk(chunk, hash, present),
|
|
365
|
+
runtime: chunk.runtime,
|
|
366
|
+
contentHashType,
|
|
367
|
+
hash,
|
|
368
|
+
contentHash: hash
|
|
369
|
+
});
|
|
370
|
+
|
|
334
371
|
/**
|
|
335
372
|
* No module id error message.
|
|
336
373
|
* @param {Module} module the module
|
|
@@ -426,14 +463,10 @@ class RuntimeTemplate {
|
|
|
426
463
|
this._placementByChunk = new WeakMap();
|
|
427
464
|
/** @type {Map<string, string | null | undefined>} */
|
|
428
465
|
this._entryBaseUriByRuntime = new Map();
|
|
429
|
-
/** @type {
|
|
430
|
-
this.
|
|
431
|
-
/** @type {Set<string> | false | undefined} */
|
|
432
|
-
this._wasmFetchingGroupSet = undefined;
|
|
466
|
+
/** @type {WasmGroups | undefined} */
|
|
467
|
+
this._wasmGroupsValue = undefined;
|
|
433
468
|
/** @type {Map<string, boolean> | undefined} */
|
|
434
469
|
this._wasmAnchorKnownByGroup = undefined;
|
|
435
|
-
/** @type {Map<string, boolean> | undefined} */
|
|
436
|
-
this._wasmGroupOnlyFetchesMap = undefined;
|
|
437
470
|
}
|
|
438
471
|
|
|
439
472
|
isIIFE() {
|
|
@@ -630,28 +663,28 @@ class RuntimeTemplate {
|
|
|
630
663
|
placedModule
|
|
631
664
|
)
|
|
632
665
|
) {
|
|
633
|
-
this._analyzableBailout(
|
|
666
|
+
return this._analyzableBailout(
|
|
634
667
|
module,
|
|
635
|
-
"__webpack_public_path__ is reassigned in a runtime this module belongs to"
|
|
668
|
+
"__webpack_public_path__ is reassigned in a runtime this module belongs to",
|
|
669
|
+
false
|
|
636
670
|
);
|
|
637
|
-
return false;
|
|
638
671
|
}
|
|
639
672
|
|
|
640
673
|
if (form === "import") {
|
|
641
674
|
// Read through a native `import()`, or it is not this feature at all.
|
|
642
675
|
if (outputOptions.chunkFormat !== "module") {
|
|
643
|
-
this._analyzableBailout(
|
|
676
|
+
return this._analyzableBailout(
|
|
644
677
|
module,
|
|
645
|
-
`output.chunkFormat is ${JSON.stringify(outputOptions.chunkFormat)}, so chunks are not read through a native import()
|
|
678
|
+
`output.chunkFormat is ${JSON.stringify(outputOptions.chunkFormat)}, so chunks are not read through a native import()`,
|
|
679
|
+
false
|
|
646
680
|
);
|
|
647
|
-
return false;
|
|
648
681
|
}
|
|
649
682
|
if (outputOptions.importFunctionName !== "import") {
|
|
650
|
-
this._analyzableBailout(
|
|
683
|
+
return this._analyzableBailout(
|
|
651
684
|
module,
|
|
652
|
-
`output.importFunctionName is ${JSON.stringify(outputOptions.importFunctionName)}, so the call site is not a native import()
|
|
685
|
+
`output.importFunctionName is ${JSON.stringify(outputOptions.importFunctionName)}, so the call site is not a native import()`,
|
|
686
|
+
false
|
|
653
687
|
);
|
|
654
|
-
return false;
|
|
655
688
|
}
|
|
656
689
|
// A worker loading its own chunks some other way keeps that runtime; one on
|
|
657
690
|
// `import` uses the same ESM loader as the main graph, so it can be analyzable.
|
|
@@ -662,29 +695,23 @@ class RuntimeTemplate {
|
|
|
662
695
|
if (!entryOptions || !entryOptions.worker) continue;
|
|
663
696
|
// `WorkerAndWorkletPlugin` always seeds this from `output.workerChunkLoading`.
|
|
664
697
|
if (entryOptions.chunkLoading !== "import") {
|
|
665
|
-
this._analyzableBailout(
|
|
698
|
+
return this._analyzableBailout(
|
|
666
699
|
module,
|
|
667
|
-
`this worker loads its chunks with ${JSON.stringify(entryOptions.chunkLoading)}, not "import"
|
|
700
|
+
`this worker loads its chunks with ${JSON.stringify(entryOptions.chunkLoading)}, not "import"`,
|
|
701
|
+
false
|
|
668
702
|
);
|
|
669
|
-
return false;
|
|
670
703
|
}
|
|
671
704
|
}
|
|
672
705
|
return true;
|
|
673
706
|
}
|
|
674
707
|
|
|
675
708
|
// `url-inline` asks whether the file can be named at the call site at all, and
|
|
676
|
-
// its `.p + <file>` fallback spells that without `import.meta` — so
|
|
677
|
-
// below
|
|
709
|
+
// its `.p + <file>` fallback spells that without `import.meta` — so the gate
|
|
710
|
+
// below does not rule it out, and the asset's javascript wrapper stays dropped.
|
|
711
|
+
// `environment.module` is deliberately not consulted: ESM output writes
|
|
712
|
+
// `import.meta` regardless (the public path, the chunk loader), so the url forms
|
|
713
|
+
// only match what the rest of the bundle already assumes the target reads.
|
|
678
714
|
if (form === "url-inline") return true;
|
|
679
|
-
// `import.meta` is ESM syntax the target has to read. A chunk `import()` is
|
|
680
|
-
// emitted by the module chunk loader either way, so only the url forms check.
|
|
681
|
-
if (!this.supportsEcmaScriptModuleSyntax()) {
|
|
682
|
-
this._analyzableBailout(
|
|
683
|
-
module,
|
|
684
|
-
"output.environment.module is false, so the target does not read the import.meta this form needs"
|
|
685
|
-
);
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
715
|
// `eval` devtool wraps each module in `eval(...)`, where `import.meta` is a
|
|
689
716
|
// syntax error. Runtime modules are emitted beside them, never wrapped.
|
|
690
717
|
const { devtool } = this.compilation.options;
|
|
@@ -693,22 +720,22 @@ class RuntimeTemplate {
|
|
|
693
720
|
typeof devtool === "string" &&
|
|
694
721
|
devtool.includes("eval")
|
|
695
722
|
) {
|
|
696
|
-
this._analyzableBailout(
|
|
723
|
+
return this._analyzableBailout(
|
|
697
724
|
module,
|
|
698
|
-
`devtool ${JSON.stringify(devtool)} wraps the module in eval(), where import.meta does not parse
|
|
725
|
+
`devtool ${JSON.stringify(devtool)} wraps the module in eval(), where import.meta does not parse`,
|
|
726
|
+
false
|
|
699
727
|
);
|
|
700
|
-
return false;
|
|
701
728
|
}
|
|
702
729
|
if (form === "url" || form === "url-runtime") return true;
|
|
703
730
|
// A bare relative URL is what `__webpack_require__.p + path` means only under an
|
|
704
731
|
// `auto` public path; anything else has to be baked, which is the "wasm" form.
|
|
705
732
|
if (form === "wasm-relative") {
|
|
706
733
|
if (outputOptions.publicPath === "auto") return true;
|
|
707
|
-
this._analyzableBailout(
|
|
734
|
+
return this._analyzableBailout(
|
|
708
735
|
module,
|
|
709
|
-
"output.publicPath is set, so a bare relative url no longer means what the public path would have resolved to"
|
|
736
|
+
"output.publicPath is set, so a bare relative url no longer means what the public path would have resolved to",
|
|
737
|
+
false
|
|
710
738
|
);
|
|
711
|
-
return false;
|
|
712
739
|
}
|
|
713
740
|
|
|
714
741
|
// The rest is the `"wasm"` form: whether the whole binary url can be spelled
|
|
@@ -727,11 +754,11 @@ class RuntimeTemplate {
|
|
|
727
754
|
this._anyWasmChunkFetches(runtime) &&
|
|
728
755
|
!this._wasmFetchAnchorIsKnown(runtime)
|
|
729
756
|
) {
|
|
730
|
-
this._analyzableBailout(
|
|
757
|
+
return this._analyzableBailout(
|
|
731
758
|
module,
|
|
732
|
-
"output.publicPath needs a base, and no one path back to the document fits every chunk `fetch` reads it from"
|
|
759
|
+
"output.publicPath needs a base, and no one path back to the document fits every chunk `fetch` reads it from",
|
|
760
|
+
false
|
|
733
761
|
);
|
|
734
|
-
return false;
|
|
735
762
|
}
|
|
736
763
|
}
|
|
737
764
|
// The compilation hash is settled after code generation, so a name carrying one
|
|
@@ -753,19 +780,22 @@ class RuntimeTemplate {
|
|
|
753
780
|
* the channel `ModuleConcatenationPlugin` already reports through, so it reaches
|
|
754
781
|
* `stats.optimizationBailout`. Silent unless the build asked for ESM output, where
|
|
755
782
|
* alone the answer is actionable; deduplicated because a module may write many.
|
|
783
|
+
* Answers with `answer` so a caller states the refusal and its reason at once —
|
|
784
|
+
* `false` where it answers a question, `null` where it was building a specifier.
|
|
785
|
+
* @template {false | null} T
|
|
756
786
|
* @param {Module | undefined} module the module the reference is emitted into
|
|
757
787
|
* @param {string} reason why no literal could be baked
|
|
758
|
-
* @
|
|
788
|
+
* @param {T} answer what the caller hands back
|
|
789
|
+
* @returns {T} that answer
|
|
759
790
|
*/
|
|
760
|
-
_analyzableBailout(module, reason) {
|
|
761
|
-
if (module
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
if (existing === text) return;
|
|
791
|
+
_analyzableBailout(module, reason, answer) {
|
|
792
|
+
if (module !== undefined && this.outputOptions.module) {
|
|
793
|
+
const text = `Analyzable ESM bailout: ${reason}`;
|
|
794
|
+
const bailouts =
|
|
795
|
+
this.compilation.moduleGraph.getOptimizationBailout(module);
|
|
796
|
+
if (!bailouts.includes(text)) bailouts.push(text);
|
|
767
797
|
}
|
|
768
|
-
|
|
798
|
+
return answer;
|
|
769
799
|
}
|
|
770
800
|
|
|
771
801
|
/**
|
|
@@ -810,8 +840,7 @@ class RuntimeTemplate {
|
|
|
810
840
|
*/
|
|
811
841
|
_canDeferOrBail(chunks, module) {
|
|
812
842
|
if (this._canDeferAnalyzableName(chunks)) return true;
|
|
813
|
-
this._analyzableBailout(module, DEFER_BAILOUT);
|
|
814
|
-
return false;
|
|
843
|
+
return this._analyzableBailout(module, DEFER_BAILOUT, false);
|
|
815
844
|
}
|
|
816
845
|
|
|
817
846
|
/**
|
|
@@ -861,9 +890,7 @@ class RuntimeTemplate {
|
|
|
861
890
|
*/
|
|
862
891
|
_partsBakeFullHash(parts) {
|
|
863
892
|
for (const [kind, value] of parts) {
|
|
864
|
-
if (kind
|
|
865
|
-
return true;
|
|
866
|
-
}
|
|
893
|
+
if (FULL_HASH_PART_KINDS.has(kind)) return true;
|
|
867
894
|
if (kind === "literal" && this._hasReservedFullHash(String(value))) {
|
|
868
895
|
return true;
|
|
869
896
|
}
|
|
@@ -962,95 +989,83 @@ class RuntimeTemplate {
|
|
|
962
989
|
const base = this.analyzableUrlReadsBaseUri()
|
|
963
990
|
? this.entryBaseUri(runtime)
|
|
964
991
|
: undefined;
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
}
|
|
973
|
-
// A relative one is no base of its own: the runtime reads it against the
|
|
974
|
-
// chunk, so the literal spells it there rather than resolving against it.
|
|
975
|
-
if (isChunkRelativeBaseUri(base)) {
|
|
976
|
-
return this._getAnalyzableFileSpecifier(
|
|
977
|
-
module,
|
|
978
|
-
chunkGraph,
|
|
979
|
-
[["literal", filename]],
|
|
980
|
-
true,
|
|
981
|
-
base
|
|
982
|
-
);
|
|
983
|
-
}
|
|
984
|
-
const chunks = this._moduleChunks(module, chunkGraph);
|
|
985
|
-
// A protocol-relative base names a host but no scheme, and the runtime reads it
|
|
986
|
-
// against the chunk's own url to get one — the very url this literal is
|
|
987
|
-
// resolved against — so it may stay protocol-relative instead of being settled
|
|
988
|
-
// here. Nothing walks back to the output root first: the base replaces it.
|
|
989
|
-
if (base.startsWith("//")) {
|
|
990
|
-
const relative = this._resolvePublicPathPrefix(
|
|
991
|
-
publicPath,
|
|
992
|
-
module,
|
|
993
|
-
chunks
|
|
994
|
-
);
|
|
995
|
-
return relative === null
|
|
996
|
-
? null
|
|
997
|
-
: this._specifierOf(
|
|
998
|
-
[
|
|
999
|
-
["literal", base],
|
|
1000
|
-
...rootedParts(relative),
|
|
1001
|
-
["literal", filename]
|
|
1002
|
-
],
|
|
1003
|
-
chunks,
|
|
1004
|
-
module
|
|
1005
|
-
);
|
|
1006
|
-
}
|
|
1007
|
-
if (!isAbsoluteBaseUri(base)) {
|
|
1008
|
-
this._analyzableBailout(
|
|
1009
|
-
module,
|
|
1010
|
-
`an entry sets a baseUri of ${JSON.stringify(base)}, whose scheme names no base anything can be resolved against`
|
|
1011
|
-
);
|
|
1012
|
-
return null;
|
|
1013
|
-
}
|
|
1014
|
-
const parts = this._resolvePublicPathPrefix(publicPath, module, chunks);
|
|
1015
|
-
if (parts === null) return null;
|
|
1016
|
-
// Resolved here rather than against the output root, and only an absolute base
|
|
1017
|
-
// settles it — a relative one has no base of its own to be read against.
|
|
1018
|
-
const spelled = literalText(parts);
|
|
1019
|
-
// A hash the deferred pass still has to fill in cannot be resolved against the
|
|
1020
|
-
// base here: the fill would land inside an already-resolved url, where a hash
|
|
1021
|
-
// opening with a letter reads as a scheme and drops the base entirely.
|
|
1022
|
-
const text =
|
|
1023
|
-
spelled !== null && !this._hasReservedFullHash(spelled)
|
|
1024
|
-
? spelled
|
|
1025
|
-
: null;
|
|
1026
|
-
/** @type {URL} */
|
|
1027
|
-
let resolved;
|
|
1028
|
-
try {
|
|
1029
|
-
// Empty where only the deferred pass can spell the rest, which still settles
|
|
1030
|
-
// whether the base itself is one anything may be resolved against.
|
|
1031
|
-
resolved = new URL(text === null ? "" : text + filename, base);
|
|
1032
|
-
} catch (_error) {
|
|
1033
|
-
this._analyzableBailout(
|
|
1034
|
-
module,
|
|
1035
|
-
`an entry sets a baseUri of ${JSON.stringify(base)}, which is not absolute, so no url can be resolved against it here`
|
|
1036
|
-
);
|
|
1037
|
-
return null;
|
|
1038
|
-
}
|
|
1039
|
-
if (text !== null) return toJsStringLiteral(resolved.href);
|
|
1040
|
-
if (!this._canDeferOrBail(chunks, module)) return null;
|
|
1041
|
-
return toJsStringLiteral(
|
|
1042
|
-
this._reserveAnalyzableSpecifier([
|
|
1043
|
-
["base", base],
|
|
1044
|
-
...parts,
|
|
1045
|
-
["literal", filename]
|
|
1046
|
-
])
|
|
992
|
+
// No base of its own: the name is spelled against the output root, as a chunk is.
|
|
993
|
+
if (base === undefined) {
|
|
994
|
+
return this._getAnalyzableFileSpecifier(
|
|
995
|
+
module,
|
|
996
|
+
chunkGraph,
|
|
997
|
+
[["literal", filename]],
|
|
998
|
+
true
|
|
1047
999
|
);
|
|
1048
1000
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1001
|
+
if (base === null) {
|
|
1002
|
+
return this._analyzableBailout(
|
|
1003
|
+
module,
|
|
1004
|
+
"the entries this module is generated for set different baseUri values, so no one url resolves for all of them",
|
|
1005
|
+
null
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
// A relative one is no base of its own: the runtime reads it against the
|
|
1009
|
+
// chunk, so the literal spells it there rather than resolving against it.
|
|
1010
|
+
if (isChunkRelativeBaseUri(base)) {
|
|
1011
|
+
return this._getAnalyzableFileSpecifier(
|
|
1012
|
+
module,
|
|
1013
|
+
chunkGraph,
|
|
1014
|
+
[["literal", filename]],
|
|
1015
|
+
true,
|
|
1016
|
+
base
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
const chunks = this._moduleChunks(module, chunkGraph);
|
|
1020
|
+
const parts = this._resolvePublicPathPrefix(publicPath, module, chunks);
|
|
1021
|
+
if (parts === null) return null;
|
|
1022
|
+
// A protocol-relative base names a host but no scheme, and the runtime reads it
|
|
1023
|
+
// against the chunk's own url to get one — the very url this literal is
|
|
1024
|
+
// resolved against — so it may stay protocol-relative instead of being settled
|
|
1025
|
+
// here. Nothing walks back to the output root first: the base replaces it.
|
|
1026
|
+
if (base.startsWith("//")) {
|
|
1027
|
+
return this._specifierOf(
|
|
1028
|
+
[["literal", base], ...rootedParts(parts), ["literal", filename]],
|
|
1029
|
+
chunks,
|
|
1030
|
+
module
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
if (!isAbsoluteBaseUri(base)) {
|
|
1034
|
+
return this._analyzableBailout(
|
|
1035
|
+
module,
|
|
1036
|
+
`an entry sets a baseUri of ${JSON.stringify(base)}, whose scheme names no base anything can be resolved against`,
|
|
1037
|
+
null
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
// Resolved here rather than against the output root, and only an absolute base
|
|
1041
|
+
// settles it — a relative one has no base of its own to be read against.
|
|
1042
|
+
const spelled = literalText(parts);
|
|
1043
|
+
// A hash the deferred pass still has to fill in cannot be resolved against the
|
|
1044
|
+
// base here: the fill would land inside an already-resolved url, where a hash
|
|
1045
|
+
// opening with a letter reads as a scheme and drops the base entirely.
|
|
1046
|
+
const text =
|
|
1047
|
+
spelled !== null && !this._hasReservedFullHash(spelled) ? spelled : null;
|
|
1048
|
+
/** @type {URL} */
|
|
1049
|
+
let resolved;
|
|
1050
|
+
try {
|
|
1051
|
+
// Empty where only the deferred pass can spell the rest, which still settles
|
|
1052
|
+
// whether the base itself is one anything may be resolved against.
|
|
1053
|
+
resolved = new URL(text === null ? "" : text + filename, base);
|
|
1054
|
+
} catch (_error) {
|
|
1055
|
+
return this._analyzableBailout(
|
|
1056
|
+
module,
|
|
1057
|
+
`an entry sets a baseUri of ${JSON.stringify(base)}, which is not absolute, so no url can be resolved against it here`,
|
|
1058
|
+
null
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
if (text !== null) return toJsStringLiteral(resolved.href);
|
|
1062
|
+
if (!this._canDeferOrBail(chunks, module)) return null;
|
|
1063
|
+
return toJsStringLiteral(
|
|
1064
|
+
this._reserveAnalyzableSpecifier([
|
|
1065
|
+
["base", base],
|
|
1066
|
+
...parts,
|
|
1067
|
+
["literal", filename]
|
|
1068
|
+
])
|
|
1054
1069
|
);
|
|
1055
1070
|
}
|
|
1056
1071
|
|
|
@@ -1121,55 +1136,119 @@ class RuntimeTemplate {
|
|
|
1121
1136
|
return publicPath.includes("[") ? undefined : publicPath;
|
|
1122
1137
|
}
|
|
1123
1138
|
|
|
1139
|
+
/**
|
|
1140
|
+
* Runtime keys grouped by the binaries they share, with what the entries of each
|
|
1141
|
+
* group asked for. Code generation runs once for runtimes a module hashes alike in,
|
|
1142
|
+
* and nothing in a binary's hash knows which loader will read it — so a binary two
|
|
1143
|
+
* runtimes reach carries one shape into both, and a third runtime sharing another
|
|
1144
|
+
* binary with either is pulled in after them. Only an entry names a loader; every
|
|
1145
|
+
* other chunk of the runtime is served by the one its entry asked for. Asked of the
|
|
1146
|
+
* same modules the loaders are created for, and only once per compilation.
|
|
1147
|
+
* @returns {WasmGroups} the grouping, and which groups fetch
|
|
1148
|
+
*/
|
|
1149
|
+
_wasmGroups() {
|
|
1150
|
+
if (this._wasmGroupsValue === undefined) {
|
|
1151
|
+
const { chunkGraph, chunks, modules } = this.compilation;
|
|
1152
|
+
/** @type {Map<string, string>} */
|
|
1153
|
+
const parent = new Map();
|
|
1154
|
+
/**
|
|
1155
|
+
* @param {string} key runtime key
|
|
1156
|
+
* @returns {string} the key naming its group
|
|
1157
|
+
*/
|
|
1158
|
+
const find = (key) => {
|
|
1159
|
+
let root = key;
|
|
1160
|
+
let seen = parent.get(root);
|
|
1161
|
+
while (seen !== undefined && seen !== root) {
|
|
1162
|
+
root = seen;
|
|
1163
|
+
seen = parent.get(root);
|
|
1164
|
+
}
|
|
1165
|
+
// Path compression keeps a long share chain from costing more than once.
|
|
1166
|
+
let walk = key;
|
|
1167
|
+
let next = parent.get(walk);
|
|
1168
|
+
while (next !== undefined && next !== root) {
|
|
1169
|
+
parent.set(walk, root);
|
|
1170
|
+
walk = next;
|
|
1171
|
+
next = parent.get(walk);
|
|
1172
|
+
}
|
|
1173
|
+
return root;
|
|
1174
|
+
};
|
|
1175
|
+
/** @type {string[]} */
|
|
1176
|
+
const keys = [];
|
|
1177
|
+
for (const module of modules) {
|
|
1178
|
+
if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
|
|
1179
|
+
keys.length = 0;
|
|
1180
|
+
for (const runtime of chunkGraph.getModuleRuntimes(module)) {
|
|
1181
|
+
forEachRuntime(runtime, (key) => {
|
|
1182
|
+
keys.push(/** @type {string} */ (key));
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
for (const key of keys) if (!parent.has(key)) parent.set(key, key);
|
|
1186
|
+
// Every runtime this binary reaches answers with the first one.
|
|
1187
|
+
for (let i = 1; i < keys.length; i++) {
|
|
1188
|
+
parent.set(find(keys[i]), find(keys[0]));
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
// Flattened once, so a lookup is a single `get` rather than a chain walk.
|
|
1192
|
+
for (const key of parent.keys()) parent.set(key, find(key));
|
|
1193
|
+
/**
|
|
1194
|
+
* @param {string} key a runtime key
|
|
1195
|
+
* @returns {string} the group it answers with, or itself when it shares nothing
|
|
1196
|
+
*/
|
|
1197
|
+
const groupOf = (key) => {
|
|
1198
|
+
const group = parent.get(key);
|
|
1199
|
+
// An entry named "" makes "" a runtime key, so test absence, not a falsy value.
|
|
1200
|
+
return group === undefined ? key : group;
|
|
1201
|
+
};
|
|
1202
|
+
/** @type {Set<string>} */
|
|
1203
|
+
const fetching = new Set();
|
|
1204
|
+
/** @type {Map<string, boolean>} */
|
|
1205
|
+
const onlyFetching = new Map();
|
|
1206
|
+
for (const chunk of chunks) {
|
|
1207
|
+
if (!chunk.getEntryOptions()) continue;
|
|
1208
|
+
const fetches = this._chunkWasmLoading(chunk) === "fetch";
|
|
1209
|
+
forEachRuntime(chunk.runtime, (key) => {
|
|
1210
|
+
const group = groupOf(/** @type {string} */ (key));
|
|
1211
|
+
if (fetches) fetching.add(group);
|
|
1212
|
+
onlyFetching.set(group, onlyFetching.get(group) !== false && fetches);
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
this._wasmGroupsValue = { groupOf, fetching, onlyFetching };
|
|
1216
|
+
}
|
|
1217
|
+
return this._wasmGroupsValue;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* @param {RuntimeSpec} runtime the runtime being asked about
|
|
1222
|
+
* @returns {string[]} the wasm runtime groups it reaches
|
|
1223
|
+
*/
|
|
1224
|
+
_wasmGroupsOf(runtime) {
|
|
1225
|
+
const { groupOf } = this._wasmGroups();
|
|
1226
|
+
/** @type {string[]} */
|
|
1227
|
+
const reached = [];
|
|
1228
|
+
forEachRuntime(runtime, (key) => {
|
|
1229
|
+
reached.push(groupOf(/** @type {string} */ (key)));
|
|
1230
|
+
});
|
|
1231
|
+
return reached;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1124
1234
|
/**
|
|
1125
1235
|
* Whether a chunk loads WebAssembly through `fetch`, which is the only loader the
|
|
1126
1236
|
* public path reaches: `readFile` resolves the binary's name against the chunk it is
|
|
1127
1237
|
* read from, exactly as a baked literal does, so a public path is irrelevant to it.
|
|
1128
|
-
* Answered per
|
|
1238
|
+
* Answered per group rather than per chunk on purpose — a module's generated source
|
|
1129
1239
|
* and the runtime module of every chunk holding it have to agree on the shape, and
|
|
1130
|
-
* they ask from opposite ends; one loader serves a whole
|
|
1131
|
-
*
|
|
1132
|
-
* told apart, the answer covers the compilation.
|
|
1240
|
+
* they ask from opposite ends; one loader serves a whole group, so that is the finest
|
|
1241
|
+
* scope on which they can. Without a runtime the answer covers the compilation.
|
|
1133
1242
|
* @param {RuntimeSpec=} runtime the runtime being asked about
|
|
1134
1243
|
* @returns {boolean} true when a chunk of that runtime fetches its binaries
|
|
1135
1244
|
*/
|
|
1136
1245
|
_anyWasmChunkFetches(runtime) {
|
|
1137
|
-
const fetching = this.
|
|
1138
|
-
if (fetching ===
|
|
1246
|
+
const { fetching } = this._wasmGroups();
|
|
1247
|
+
if (fetching.size === 0) return false;
|
|
1139
1248
|
// Without a runtime to place it in there is nothing to narrow by, so any chunk
|
|
1140
1249
|
// answers for all of them.
|
|
1141
1250
|
if (runtime === undefined) return true;
|
|
1142
|
-
|
|
1143
|
-
if (typeof runtime === "string") {
|
|
1144
|
-
return fetching.has(this._wasmGroupOf(groups, runtime));
|
|
1145
|
-
}
|
|
1146
|
-
for (const key of runtime) {
|
|
1147
|
-
if (fetching.has(this._wasmGroupOf(groups, key))) return true;
|
|
1148
|
-
}
|
|
1149
|
-
return false;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
/**
|
|
1153
|
-
* Whether every entry of a wasm runtime group reads its binaries with `fetch`. Only
|
|
1154
|
-
* an entry names a loader, so the scan is of entries, as `_wasmFetchingGroups` is.
|
|
1155
|
-
* @returns {Map<string, boolean>} whether each group fetches and nothing else
|
|
1156
|
-
*/
|
|
1157
|
-
_wasmGroupOnlyFetches() {
|
|
1158
|
-
if (this._wasmGroupOnlyFetchesMap === undefined) {
|
|
1159
|
-
const groups = this._wasmRuntimeGroups();
|
|
1160
|
-
/** @type {Map<string, boolean>} */
|
|
1161
|
-
const only = new Map();
|
|
1162
|
-
for (const chunk of this.compilation.chunks) {
|
|
1163
|
-
if (!chunk.getEntryOptions()) continue;
|
|
1164
|
-
const fetches = this._chunkWasmLoading(chunk) === "fetch";
|
|
1165
|
-
forEachRuntime(chunk.runtime, (key) => {
|
|
1166
|
-
const group = this._wasmGroupOf(groups, /** @type {string} */ (key));
|
|
1167
|
-
only.set(group, only.get(group) !== false && fetches);
|
|
1168
|
-
});
|
|
1169
|
-
}
|
|
1170
|
-
this._wasmGroupOnlyFetchesMap = only;
|
|
1171
|
-
}
|
|
1172
|
-
return this._wasmGroupOnlyFetchesMap;
|
|
1251
|
+
return this._wasmGroupsOf(runtime).some((group) => fetching.has(group));
|
|
1173
1252
|
}
|
|
1174
1253
|
|
|
1175
1254
|
/**
|
|
@@ -1182,30 +1261,31 @@ class RuntimeTemplate {
|
|
|
1182
1261
|
_wasmFetchAnchorIsKnown(runtime) {
|
|
1183
1262
|
if (this._wasmAnchorKnownByGroup === undefined) {
|
|
1184
1263
|
const { chunkGraph, modules } = this.compilation;
|
|
1185
|
-
const
|
|
1186
|
-
this.outputOptions.publicPath
|
|
1187
|
-
);
|
|
1188
|
-
const groups = this._wasmRuntimeGroups();
|
|
1264
|
+
const { groupOf, onlyFetching } = this._wasmGroups();
|
|
1189
1265
|
/** @type {Map<string, boolean>} */
|
|
1190
1266
|
const known = new Map();
|
|
1191
1267
|
for (const module of modules) {
|
|
1192
1268
|
if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
|
|
1269
|
+
// Probed through the very builder the generator runs, so the gate is
|
|
1270
|
+
// exact: a prefix it can spell — the per-asset deferrals included — is
|
|
1271
|
+
// one the group may bake. The probe name stands in for the binary's.
|
|
1193
1272
|
const spellable =
|
|
1194
|
-
this.
|
|
1195
|
-
|
|
1273
|
+
this._getAnalyzableFileSpecifier(
|
|
1274
|
+
module,
|
|
1275
|
+
/** @type {ChunkGraph} */ (chunkGraph),
|
|
1276
|
+
[["literal", "x"]],
|
|
1277
|
+
true
|
|
1278
|
+
) !== null;
|
|
1196
1279
|
for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
|
|
1197
1280
|
forEachRuntime(moduleRuntime, (key) => {
|
|
1198
|
-
const group =
|
|
1199
|
-
groups,
|
|
1200
|
-
/** @type {string} */ (key)
|
|
1201
|
-
);
|
|
1281
|
+
const group = groupOf(/** @type {string} */ (key));
|
|
1202
1282
|
known.set(group, known.get(group) !== false && spellable);
|
|
1203
1283
|
});
|
|
1204
1284
|
}
|
|
1205
1285
|
}
|
|
1206
1286
|
// A group one entry reads with `readFile` cannot take a prefix meant for the
|
|
1207
1287
|
// document, and only an entry names its loader.
|
|
1208
|
-
for (const [group, only] of
|
|
1288
|
+
for (const [group, only] of onlyFetching) {
|
|
1209
1289
|
if (!only) known.set(group, false);
|
|
1210
1290
|
}
|
|
1211
1291
|
this._wasmAnchorKnownByGroup = known;
|
|
@@ -1217,124 +1297,9 @@ class RuntimeTemplate {
|
|
|
1217
1297
|
for (const value of known.values()) if (!value) return false;
|
|
1218
1298
|
return known.size > 0;
|
|
1219
1299
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
}
|
|
1224
|
-
for (const key of runtime) {
|
|
1225
|
-
if (known.get(this._wasmGroupOf(groups, key)) !== true) return false;
|
|
1226
|
-
}
|
|
1227
|
-
return true;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
/**
|
|
1231
|
-
* The runtime groups an entry of which asked for the `fetch` loader, or `undefined`
|
|
1232
|
-
* where none did — the cheap answer for a compilation with no fetching entry at all,
|
|
1233
|
-
* which is every non-web target. Only an entry names a loader; every other chunk of
|
|
1234
|
-
* the runtime is served by the one its entry asked for.
|
|
1235
|
-
* @returns {Set<string> | undefined} the groups that fetch
|
|
1236
|
-
*/
|
|
1237
|
-
_wasmFetchingGroups() {
|
|
1238
|
-
if (this._wasmFetchingGroupSet === undefined) {
|
|
1239
|
-
/** @type {Set<string>} */
|
|
1240
|
-
const fetching = new Set();
|
|
1241
|
-
/** @type {Map<string, string> | undefined} */
|
|
1242
|
-
let groups;
|
|
1243
|
-
for (const chunk of this.compilation.chunks) {
|
|
1244
|
-
// Only an entry names a loader; every other chunk of the runtime is served
|
|
1245
|
-
// by the one its entry asked for, so it says nothing on its own.
|
|
1246
|
-
if (!chunk.getEntryOptions()) continue;
|
|
1247
|
-
if (this._chunkWasmLoading(chunk) !== "fetch") continue;
|
|
1248
|
-
// Built only once something fetches, so nothing pays for the grouping.
|
|
1249
|
-
if (groups === undefined) groups = this._wasmRuntimeGroups();
|
|
1250
|
-
const named = /** @type {Map<string, string>} */ (groups);
|
|
1251
|
-
forEachRuntime(chunk.runtime, (key) => {
|
|
1252
|
-
fetching.add(this._wasmGroupOf(named, /** @type {string} */ (key)));
|
|
1253
|
-
});
|
|
1254
|
-
}
|
|
1255
|
-
this._wasmFetchingGroupSet = fetching.size === 0 ? false : fetching;
|
|
1256
|
-
}
|
|
1257
|
-
return this._wasmFetchingGroupSet === false
|
|
1258
|
-
? undefined
|
|
1259
|
-
: this._wasmFetchingGroupSet;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
/**
|
|
1263
|
-
* Runtime keys mapped to the group they answer with, named by one key of it. Code
|
|
1264
|
-
* generation runs once for runtimes a module hashes alike in, and nothing in a
|
|
1265
|
-
* binary's hash knows which loader will read it — so a binary two runtimes reach
|
|
1266
|
-
* carries one shape into both, and a third runtime sharing another binary with
|
|
1267
|
-
* either is pulled in after them. A key in no group answers as itself. Asked of the
|
|
1268
|
-
* same modules the loaders are created for, and only once per compilation.
|
|
1269
|
-
* @returns {Map<string, string>} runtime key to the group it answers with
|
|
1270
|
-
*/
|
|
1271
|
-
_wasmRuntimeGroups() {
|
|
1272
|
-
if (this._wasmRuntimeGroupsByKey === undefined) {
|
|
1273
|
-
const { chunkGraph } = this.compilation;
|
|
1274
|
-
/** @type {Map<string, string>} */
|
|
1275
|
-
const parent = new Map();
|
|
1276
|
-
/**
|
|
1277
|
-
* @param {string} key runtime key
|
|
1278
|
-
* @returns {string} the key naming its group
|
|
1279
|
-
*/
|
|
1280
|
-
const find = (key) => {
|
|
1281
|
-
let root = key;
|
|
1282
|
-
let seen = parent.get(root);
|
|
1283
|
-
while (seen !== undefined && seen !== root) {
|
|
1284
|
-
root = seen;
|
|
1285
|
-
seen = parent.get(root);
|
|
1286
|
-
}
|
|
1287
|
-
// Path compression keeps a long share chain from costing more than once.
|
|
1288
|
-
let walk = key;
|
|
1289
|
-
let next = parent.get(walk);
|
|
1290
|
-
while (next !== undefined && next !== root) {
|
|
1291
|
-
parent.set(walk, root);
|
|
1292
|
-
walk = next;
|
|
1293
|
-
next = parent.get(walk);
|
|
1294
|
-
}
|
|
1295
|
-
return root;
|
|
1296
|
-
};
|
|
1297
|
-
/** @type {string[]} */
|
|
1298
|
-
const keys = [];
|
|
1299
|
-
/**
|
|
1300
|
-
* @param {RuntimeSpec} runtime a runtime the module is generated for
|
|
1301
|
-
* @returns {void}
|
|
1302
|
-
*/
|
|
1303
|
-
const collectKeys = (runtime) => {
|
|
1304
|
-
forEachRuntime(runtime, (key) => {
|
|
1305
|
-
keys.push(/** @type {string} */ (key));
|
|
1306
|
-
});
|
|
1307
|
-
};
|
|
1308
|
-
for (const module of this.compilation.modules) {
|
|
1309
|
-
if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
|
|
1310
|
-
keys.length = 0;
|
|
1311
|
-
for (const runtime of chunkGraph.getModuleRuntimes(module)) {
|
|
1312
|
-
collectKeys(runtime);
|
|
1313
|
-
}
|
|
1314
|
-
for (const key of keys) {
|
|
1315
|
-
if (!parent.has(key)) parent.set(key, key);
|
|
1316
|
-
}
|
|
1317
|
-
// Every runtime this binary reaches answers with the first one.
|
|
1318
|
-
for (let i = 1; i < keys.length; i++) {
|
|
1319
|
-
parent.set(find(keys[i]), find(keys[0]));
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
// Flattened once, so a lookup is a single `get` rather than a chain walk.
|
|
1323
|
-
for (const key of parent.keys()) parent.set(key, find(key));
|
|
1324
|
-
this._wasmRuntimeGroupsByKey = parent;
|
|
1325
|
-
}
|
|
1326
|
-
return this._wasmRuntimeGroupsByKey;
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
/**
|
|
1330
|
-
* @param {Map<string, string>} groups runtime key to the group it answers with
|
|
1331
|
-
* @param {string} key a runtime key
|
|
1332
|
-
* @returns {string} the group it answers with, or itself when it shares nothing
|
|
1333
|
-
*/
|
|
1334
|
-
_wasmGroupOf(groups, key) {
|
|
1335
|
-
const group = groups.get(key);
|
|
1336
|
-
// An entry named "" makes "" a runtime key, so test absence, not a falsy value.
|
|
1337
|
-
return group === undefined ? key : group;
|
|
1300
|
+
return this._wasmGroupsOf(runtime).every(
|
|
1301
|
+
(group) => known.get(group) === true
|
|
1302
|
+
);
|
|
1338
1303
|
}
|
|
1339
1304
|
|
|
1340
1305
|
supportTemplateLiteral() {
|
|
@@ -2684,6 +2649,22 @@ class RuntimeTemplate {
|
|
|
2684
2649
|
return `Promise.resolve(${comment.trim()})`;
|
|
2685
2650
|
}
|
|
2686
2651
|
|
|
2652
|
+
/**
|
|
2653
|
+
* Whether any module of `chunk` carries a source type with a chunk handler of its
|
|
2654
|
+
* own, which `.ei` dispatches alongside the javascript one.
|
|
2655
|
+
* @param {Chunk} chunk the chunk being imported
|
|
2656
|
+
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
2657
|
+
* @returns {boolean} true when a handler beyond the javascript one is reached
|
|
2658
|
+
*/
|
|
2659
|
+
_chunkLoadsBeyondJs(chunk, chunkGraph) {
|
|
2660
|
+
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
|
2661
|
+
for (const type of chunkGraph.getModuleSourceTypes(module)) {
|
|
2662
|
+
if (!TYPES_WITHOUT_CHUNK_HANDLER.has(type)) return true;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
return false;
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2687
2668
|
/**
|
|
2688
2669
|
* For ESM module output, load a single statically-named chunk through the
|
|
2689
2670
|
* `analyzableChunkImport` helper — a literal `import("./chunk.js")` other bundlers
|
|
@@ -2711,30 +2692,15 @@ class RuntimeTemplate {
|
|
|
2711
2692
|
) {
|
|
2712
2693
|
return null;
|
|
2713
2694
|
}
|
|
2714
|
-
// Prefetch/preload children are injected by the runtime `.f` handlers, which `.ei`
|
|
2715
|
-
// runs too — but they attach to `.f`, so it has to exist.
|
|
2716
|
-
const needsHintHandlers =
|
|
2717
|
-
chunk.hasChildByOrder(chunkGraph, "prefetch", true) ||
|
|
2718
|
-
chunk.hasChildByOrder(chunkGraph, "preload", true) ||
|
|
2719
|
-
chunk.hasChildByOrder(chunkGraph, "cssPreload", true);
|
|
2720
2695
|
// `.ei` always performs the import, where `.e` only reaches the javascript
|
|
2721
2696
|
// loader when there is javascript to load. A module federation remote is the
|
|
2722
2697
|
// case that matters: its chunk is emitted by the container's build, not this one.
|
|
2723
2698
|
if (!JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)) {
|
|
2724
|
-
this._analyzableBailout(
|
|
2699
|
+
return this._analyzableBailout(
|
|
2725
2700
|
originModule,
|
|
2726
|
-
"this compilation emits no javascript for the chunk, so there is nothing to import"
|
|
2701
|
+
"this compilation emits no javascript for the chunk, so there is nothing to import",
|
|
2702
|
+
null
|
|
2727
2703
|
);
|
|
2728
|
-
return null;
|
|
2729
|
-
}
|
|
2730
|
-
let hasNonJsTypes = false;
|
|
2731
|
-
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
|
2732
|
-
for (const type of chunkGraph.getModuleSourceTypes(module)) {
|
|
2733
|
-
if (!TYPES_WITHOUT_CHUNK_HANDLER.has(type)) {
|
|
2734
|
-
// Loaded by that type's own `.f` handler, which `.ei` still dispatches.
|
|
2735
|
-
hasNonJsTypes = true;
|
|
2736
|
-
}
|
|
2737
|
-
}
|
|
2738
2704
|
}
|
|
2739
2705
|
// Relative to the consuming chunk (`import.meta.url`) for `auto`, else an
|
|
2740
2706
|
// absolute publicPath prefix.
|
|
@@ -2756,9 +2722,15 @@ class RuntimeTemplate {
|
|
|
2756
2722
|
? specifier
|
|
2757
2723
|
: `"./${specifier.slice(1)}`;
|
|
2758
2724
|
runtimeRequirements.add(RuntimeGlobals.analyzableChunkImport);
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2725
|
+
// Prefetch/preload children and every non-javascript source type are loaded by a
|
|
2726
|
+
// `.f` handler, which `.ei` dispatches — but they attach to `.f`, so it has to
|
|
2727
|
+
// exist. The runtime `ensureChunk` around it does not.
|
|
2728
|
+
if (
|
|
2729
|
+
chunk.hasChildByOrder(chunkGraph, "prefetch", true) ||
|
|
2730
|
+
chunk.hasChildByOrder(chunkGraph, "preload", true) ||
|
|
2731
|
+
chunk.hasChildByOrder(chunkGraph, "cssPreload", true) ||
|
|
2732
|
+
this._chunkLoadsBeyondJs(chunk, chunkGraph)
|
|
2733
|
+
) {
|
|
2762
2734
|
runtimeRequirements.add(RuntimeGlobals.ensureChunkHandlers);
|
|
2763
2735
|
}
|
|
2764
2736
|
// Drop-in for `ensureChunk(id)`: the literal `import()` can be statically
|
|
@@ -2928,6 +2900,11 @@ class RuntimeTemplate {
|
|
|
2928
2900
|
/** @type {Set<string>} */
|
|
2929
2901
|
const names = new Set();
|
|
2930
2902
|
let found = false;
|
|
2903
|
+
// Its own copy, since `lastIndex` is walked below; reset by the loop that ends it.
|
|
2904
|
+
const regexp = new RegExp(
|
|
2905
|
+
ANALYZABLE_TOKEN_REGEXP.source,
|
|
2906
|
+
ANALYZABLE_TOKEN_REGEXP.flags
|
|
2907
|
+
);
|
|
2931
2908
|
for (const module of modules) {
|
|
2932
2909
|
if (!results.has(module, chunk.runtime)) continue;
|
|
2933
2910
|
const source = results.getSource(module, chunk.runtime, JAVASCRIPT_TYPE);
|
|
@@ -2937,10 +2914,6 @@ class RuntimeTemplate {
|
|
|
2937
2914
|
carriesFullHash = true;
|
|
2938
2915
|
found = true;
|
|
2939
2916
|
}
|
|
2940
|
-
const regexp = new RegExp(
|
|
2941
|
-
ANALYZABLE_TOKEN_REGEXP.source,
|
|
2942
|
-
ANALYZABLE_TOKEN_REGEXP.flags
|
|
2943
|
-
);
|
|
2944
2917
|
/** @type {RegExpExecArray | null} */
|
|
2945
2918
|
let match;
|
|
2946
2919
|
while ((match = regexp.exec(content)) !== null) {
|
|
@@ -2948,11 +2921,7 @@ class RuntimeTemplate {
|
|
|
2948
2921
|
if (parts === null) continue;
|
|
2949
2922
|
found = true;
|
|
2950
2923
|
for (const [kind, value] of parts) {
|
|
2951
|
-
if (
|
|
2952
|
-
kind === "publicPath" ||
|
|
2953
|
-
kind === "template" ||
|
|
2954
|
-
kind === "unserved"
|
|
2955
|
-
) {
|
|
2924
|
+
if (FULL_HASH_PART_KINDS.has(kind)) {
|
|
2956
2925
|
carriesFullHash = true;
|
|
2957
2926
|
} else if (CHUNK_SPECIFIER_PART_KINDS.has(kind)) {
|
|
2958
2927
|
names.add(String(value));
|
|
@@ -3213,13 +3182,13 @@ class RuntimeTemplate {
|
|
|
3213
3182
|
return template.replace(HASH_IN_FILENAME_GLOBAL, "x");
|
|
3214
3183
|
}
|
|
3215
3184
|
try {
|
|
3216
|
-
return
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3185
|
+
return probeTemplateName(
|
|
3186
|
+
template,
|
|
3187
|
+
chunk,
|
|
3188
|
+
JAVASCRIPT_TYPE,
|
|
3189
|
+
HASH_PROBE,
|
|
3190
|
+
true
|
|
3191
|
+
).replace(HASH_IN_FILENAME_GLOBAL, "x");
|
|
3223
3192
|
} catch (_error) {
|
|
3224
3193
|
// Nothing to report: the naming call is given strictly less than this probe, so
|
|
3225
3194
|
// one that throws here fails the build where the name is actually needed.
|
|
@@ -3311,6 +3280,41 @@ class RuntimeTemplate {
|
|
|
3311
3280
|
: { undo, loaded };
|
|
3312
3281
|
}
|
|
3313
3282
|
|
|
3283
|
+
/**
|
|
3284
|
+
* Static literal specifier (already quoted) for the `new URL(<here>, import.meta.url)`
|
|
3285
|
+
* a worker or worklet entry chunk bakes to, or `null` to keep the runtime form. The
|
|
3286
|
+
* gate and the build are asked together so every call site agrees on both — the
|
|
3287
|
+
* `new Worker(...)` emit, and the resource hint `ResourceHintPlugin` spells for it.
|
|
3288
|
+
* @param {string | undefined} overridePublicPath a `publicPath` set on the worker itself
|
|
3289
|
+
* @param {Chunk} chunk the worker's entry chunk
|
|
3290
|
+
* @param {Module} module the module the reference is emitted into
|
|
3291
|
+
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3292
|
+
* @param {RuntimeRequirements} runtimeRequirements what the consuming chunk needs
|
|
3293
|
+
* @returns {string | null} a quoted literal, or `null` to fall back
|
|
3294
|
+
*/
|
|
3295
|
+
getAnalyzableWorkerUrl(
|
|
3296
|
+
overridePublicPath,
|
|
3297
|
+
chunk,
|
|
3298
|
+
module,
|
|
3299
|
+
chunkGraph,
|
|
3300
|
+
runtimeRequirements
|
|
3301
|
+
) {
|
|
3302
|
+
// Without an id nothing can name the chunk in a stand-in.
|
|
3303
|
+
if (
|
|
3304
|
+
chunk.id === null ||
|
|
3305
|
+
!this.supportsAnalyzable("url", chunkGraph, module)
|
|
3306
|
+
) {
|
|
3307
|
+
return null;
|
|
3308
|
+
}
|
|
3309
|
+
return this._getAnalyzableChunkSpecifier(
|
|
3310
|
+
overridePublicPath,
|
|
3311
|
+
chunk,
|
|
3312
|
+
module,
|
|
3313
|
+
chunkGraph,
|
|
3314
|
+
runtimeRequirements
|
|
3315
|
+
);
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3314
3318
|
/**
|
|
3315
3319
|
* Static literal specifier (already quoted) for a `new URL(<here>, import.meta.url)`
|
|
3316
3320
|
* or `import(<here>)` pointing at `chunk`'s JS file, or `null` when it can't be known
|
|
@@ -3358,33 +3362,30 @@ class RuntimeTemplate {
|
|
|
3358
3362
|
const chunks =
|
|
3359
3363
|
consumingChunks ||
|
|
3360
3364
|
this._moduleChunks(/** @type {Module} */ (consumingModule), chunkGraph);
|
|
3361
|
-
|
|
3362
|
-
// reaches back has no fixed point if both bake, so only the lower id's name does.
|
|
3363
|
-
const cycles =
|
|
3364
|
-
deferred &&
|
|
3365
|
-
this._reachesAny(chunk, chunks) &&
|
|
3366
|
-
!this._namesBeforeAll(chunk, chunks);
|
|
3365
|
+
const namesFirst = this._namesBeforeAll(chunk, chunks);
|
|
3367
3366
|
// An id names the chunk in the stand-in. No reference reaches here without one —
|
|
3368
3367
|
// `blockPromise` drops an id-less chunk before asking, and one the whole build
|
|
3369
3368
|
// keeps has no name to be emitted under — so the guard carries no reason of its
|
|
3370
|
-
// own; it only keeps `null` out of a name.
|
|
3369
|
+
// own; it only keeps `null` out of a name. A pair naming each other is fine here:
|
|
3370
|
+
// `RealContentHashPlugin`, which deferring requires, re-hashes the pair as one
|
|
3371
|
+
// group, so neither hash chases the other.
|
|
3371
3372
|
const canReserve =
|
|
3372
|
-
chunk.id !== null &&
|
|
3373
|
+
chunk.id !== null && this._canDeferAnalyzableName(chunks);
|
|
3373
3374
|
// A content-named consumer bakes anyway when this chunk settles first: the fold
|
|
3374
|
-
// puts the name into its hash. Only what `_foldsWholeName` covers, though
|
|
3375
|
-
|
|
3375
|
+
// puts the name into its hash. Only what `_foldsWholeName` covers, though — and
|
|
3376
|
+
// a pair that reaches back has no fold order, so only the one hashing first does.
|
|
3377
|
+
const canFold = !canReserve && namesFirst;
|
|
3376
3378
|
/**
|
|
3377
3379
|
* @returns {null} always, having recorded why no stand-in may be reserved
|
|
3378
3380
|
*/
|
|
3379
|
-
const cannotReserve = () =>
|
|
3381
|
+
const cannotReserve = () =>
|
|
3380
3382
|
this._analyzableBailout(
|
|
3381
3383
|
consumingModule,
|
|
3382
|
-
|
|
3383
|
-
? "this chunk and the one it references name each other,
|
|
3384
|
-
: DEFER_BAILOUT
|
|
3384
|
+
!namesFirst && this._reachesAny(chunk, chunks)
|
|
3385
|
+
? "this chunk and the one it references name each other, which only optimization.realContentHash could settle"
|
|
3386
|
+
: DEFER_BAILOUT,
|
|
3387
|
+
null
|
|
3385
3388
|
);
|
|
3386
|
-
return null;
|
|
3387
|
-
};
|
|
3388
3389
|
if (deferred && !canReserve && !canFold) return cannotReserve();
|
|
3389
3390
|
const filename = deferred
|
|
3390
3391
|
? ""
|
|
@@ -3483,24 +3484,17 @@ class RuntimeTemplate {
|
|
|
3483
3484
|
// Each knows its own answer, so the fill asks per asset — where each has one,
|
|
3484
3485
|
// and where nothing else goes between the two shapes.
|
|
3485
3486
|
if (relativeBase !== undefined || !this._eachChunkServedOneWay(chunks)) {
|
|
3486
|
-
this._analyzableBailout(module, SERVED_BAILOUT);
|
|
3487
|
-
return null;
|
|
3487
|
+
return this._analyzableBailout(module, SERVED_BAILOUT, null);
|
|
3488
3488
|
}
|
|
3489
3489
|
return [...head, ["unserved", ""]];
|
|
3490
3490
|
}
|
|
3491
3491
|
if (climb !== "" && relativeBase === undefined) return head;
|
|
3492
3492
|
const resolved = resolve();
|
|
3493
3493
|
if (resolved === null) return null;
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
),
|
|
3499
|
-
.../** @type {SpecifierPart[]} */ (
|
|
3500
|
-
relativeBase === undefined ? [] : [["literal", relativeBase]]
|
|
3501
|
-
),
|
|
3502
|
-
...rootedParts(resolved)
|
|
3503
|
-
];
|
|
3494
|
+
if (climb !== "") head.push(["literal", climb]);
|
|
3495
|
+
if (relativeBase !== undefined) head.push(["literal", relativeBase]);
|
|
3496
|
+
head.push(...rootedParts(resolved));
|
|
3497
|
+
return head;
|
|
3504
3498
|
}
|
|
3505
3499
|
|
|
3506
3500
|
/**
|
|
@@ -3626,11 +3620,6 @@ class RuntimeTemplate {
|
|
|
3626
3620
|
) {
|
|
3627
3621
|
const { publicPath } = this.outputOptions;
|
|
3628
3622
|
const chunks = this._moduleChunks(module, chunkGraph);
|
|
3629
|
-
/**
|
|
3630
|
-
* @param {SpecifierPart[]} parts the whole specifier
|
|
3631
|
-
* @returns {string | null} it already quoted, or `null` when no stand-in may be reserved
|
|
3632
|
-
*/
|
|
3633
|
-
const specifier = (parts) => this._specifierOf(parts, chunks, module);
|
|
3634
3623
|
if (bakePublicPath && publicPath !== "auto") {
|
|
3635
3624
|
const prefix = this._analyzablePathPrefix(
|
|
3636
3625
|
module,
|
|
@@ -3638,25 +3627,24 @@ class RuntimeTemplate {
|
|
|
3638
3627
|
chunks,
|
|
3639
3628
|
relativeBase
|
|
3640
3629
|
);
|
|
3641
|
-
|
|
3630
|
+
if (prefix === null) return null;
|
|
3631
|
+
return this._specifierOf([...prefix, ...file], chunks, module);
|
|
3642
3632
|
}
|
|
3643
3633
|
// No public path to place it against, so the `../` path back to the output root
|
|
3644
3634
|
// is the whole prefix. Different depths — no one is right for every asset the
|
|
3645
3635
|
// reference is emitted into, so the deferred pass builds each asset's own.
|
|
3646
3636
|
const { undo } = this._modulePlacement(module, chunkGraph);
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
...file
|
|
3653
|
-
]);
|
|
3637
|
+
/** @type {SpecifierPart[]} */
|
|
3638
|
+
const parts = [undo === null ? ["undo", ""] : ["literal", undo]];
|
|
3639
|
+
if (relativeBase !== undefined) parts.push(["literal", relativeBase]);
|
|
3640
|
+
parts.push(...file);
|
|
3641
|
+
return this._specifierOf(parts, chunks, module);
|
|
3654
3642
|
}
|
|
3655
3643
|
|
|
3656
3644
|
/**
|
|
3657
3645
|
* Static `new URL(<file>, import.meta.url)` for every stylesheet a runtime can load,
|
|
3658
|
-
* keyed by chunk id
|
|
3659
|
-
* `publicPath + getChunkCssFilename(id)` form. Both the runtime module reading them
|
|
3646
|
+
* keyed by chunk id — one that cannot be named leaves the map incomplete, and its
|
|
3647
|
+
* id keeps the runtime `publicPath + getChunkCssFilename(id)` form. Both the runtime module reading them
|
|
3660
3648
|
* and the plugin declaring what it needs ask this, so the two always agree. The
|
|
3661
3649
|
* runtime hands an absolute url string to `link.href`, and so does this — the browser
|
|
3662
3650
|
* resolves the element against the document, which is not where the chunk sits, and
|
|
@@ -3666,7 +3654,7 @@ class RuntimeTemplate {
|
|
|
3666
3654
|
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3667
3655
|
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
|
|
3668
3656
|
* @param {Module=} consumingModule the runtime module, where one exists to report against
|
|
3669
|
-
* @returns {
|
|
3657
|
+
* @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
|
|
3670
3658
|
*/
|
|
3671
3659
|
analyzableCssChunkUrls(
|
|
3672
3660
|
runtimeChunk,
|
|
@@ -3698,14 +3686,14 @@ class RuntimeTemplate {
|
|
|
3698
3686
|
/**
|
|
3699
3687
|
* Static `new URL(<file>, import.meta.url).href` for every javascript chunk a
|
|
3700
3688
|
* runtime can hint at with `<link rel="prefetch"/"modulepreload">`, keyed by chunk
|
|
3701
|
-
* id
|
|
3702
|
-
* `publicPath + getChunkScriptFilename(id)` form. Both the runtime module reading
|
|
3689
|
+
* id — one that cannot be named leaves the map incomplete, and its id keeps the
|
|
3690
|
+
* runtime `publicPath + getChunkScriptFilename(id)` form. Both the runtime module reading
|
|
3703
3691
|
* them and the plugin declaring what it needs ask this, so the two always agree.
|
|
3704
3692
|
* @param {Chunk} runtimeChunk the chunk holding the hint handlers
|
|
3705
3693
|
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3706
3694
|
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
|
|
3707
3695
|
* @param {Module=} consumingModule the runtime module, where one exists to report against
|
|
3708
|
-
* @returns {
|
|
3696
|
+
* @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
|
|
3709
3697
|
*/
|
|
3710
3698
|
analyzableChunkScriptUrls(
|
|
3711
3699
|
runtimeChunk,
|
|
@@ -3722,11 +3710,9 @@ class RuntimeTemplate {
|
|
|
3722
3710
|
);
|
|
3723
3711
|
/** @type {Set<ChunkId>} */
|
|
3724
3712
|
const hinted = new Set();
|
|
3725
|
-
for (const
|
|
3726
|
-
for (const
|
|
3727
|
-
for (const id of
|
|
3728
|
-
hinted.add(id);
|
|
3729
|
-
}
|
|
3713
|
+
for (const byParent of Object.values(orders)) {
|
|
3714
|
+
for (const ids of Object.values(byParent)) {
|
|
3715
|
+
for (const id of ids) hinted.add(id);
|
|
3730
3716
|
}
|
|
3731
3717
|
}
|
|
3732
3718
|
/** @type {Chunk[]} */
|
|
@@ -3746,14 +3732,15 @@ class RuntimeTemplate {
|
|
|
3746
3732
|
|
|
3747
3733
|
/**
|
|
3748
3734
|
* The urls of one asset of each of `chunks`, written out so they can be read by
|
|
3749
|
-
* chunk id
|
|
3735
|
+
* chunk id. A chunk that cannot be named here leaves the map incomplete rather
|
|
3736
|
+
* than losing it — the consumer keeps the runtime form for the ids the map lacks.
|
|
3750
3737
|
* @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
|
|
3751
3738
|
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3752
3739
|
* @param {Module | undefined} consumingModule the runtime module, where one exists to report against
|
|
3753
3740
|
* @param {Chunk[]} consumingChunks the chunks the urls are written into
|
|
3754
3741
|
* @param {string} sourceType which asset of each chunk to name
|
|
3755
3742
|
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
|
|
3756
|
-
* @returns {
|
|
3743
|
+
* @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
|
|
3757
3744
|
*/
|
|
3758
3745
|
_analyzableChunkUrls(
|
|
3759
3746
|
chunks,
|
|
@@ -3773,6 +3760,7 @@ class RuntimeTemplate {
|
|
|
3773
3760
|
}
|
|
3774
3761
|
/** @type {Map<ChunkId, string>} */
|
|
3775
3762
|
const urls = new Map();
|
|
3763
|
+
let complete = true;
|
|
3776
3764
|
for (const chunk of chunks) {
|
|
3777
3765
|
if (chunk.id === null) continue;
|
|
3778
3766
|
const specifier = this._getAnalyzableChunkSpecifier(
|
|
@@ -3784,10 +3772,14 @@ class RuntimeTemplate {
|
|
|
3784
3772
|
consumingChunks,
|
|
3785
3773
|
sourceType
|
|
3786
3774
|
);
|
|
3787
|
-
|
|
3775
|
+
// `_getAnalyzableChunkSpecifier` has already recorded why.
|
|
3776
|
+
if (specifier === null) {
|
|
3777
|
+
complete = false;
|
|
3778
|
+
continue;
|
|
3779
|
+
}
|
|
3788
3780
|
urls.set(chunk.id, `${this.importMetaUrl(specifier)}.href`);
|
|
3789
3781
|
}
|
|
3790
|
-
return urls.size > 0 ? urls : null;
|
|
3782
|
+
return urls.size > 0 ? { urls, complete } : null;
|
|
3791
3783
|
}
|
|
3792
3784
|
|
|
3793
3785
|
/**
|
|
@@ -3852,20 +3844,20 @@ class RuntimeTemplate {
|
|
|
3852
3844
|
try {
|
|
3853
3845
|
// Everything the naming call is given except the hashes, so only a hash can
|
|
3854
3846
|
// make the two answers differ.
|
|
3855
|
-
const template =
|
|
3856
|
-
|
|
3857
|
-
|
|
3847
|
+
const template = probeTemplateName(
|
|
3848
|
+
filenameTemplate,
|
|
3849
|
+
chunk,
|
|
3858
3850
|
contentHashType,
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
const probe =
|
|
3863
|
-
|
|
3864
|
-
|
|
3851
|
+
HASH_PROBE,
|
|
3852
|
+
true
|
|
3853
|
+
);
|
|
3854
|
+
const probe = probeTemplateName(
|
|
3855
|
+
filenameTemplate,
|
|
3856
|
+
chunk,
|
|
3865
3857
|
contentHashType,
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3858
|
+
HASH_PROBE_ALTERNATE,
|
|
3859
|
+
false
|
|
3860
|
+
);
|
|
3869
3861
|
return template === probe ? template : undefined;
|
|
3870
3862
|
} catch (_error) {
|
|
3871
3863
|
// Nothing to report: the probe is given strictly more than the naming call,
|
|
@@ -3882,21 +3874,16 @@ class RuntimeTemplate {
|
|
|
3882
3874
|
* @returns {boolean} true when every runtime reaching it fetches
|
|
3883
3875
|
*/
|
|
3884
3876
|
_wasmModuleFetches(module, chunkGraph) {
|
|
3885
|
-
|
|
3886
|
-
|
|
3877
|
+
const { onlyFetching } = this._wasmGroups();
|
|
3878
|
+
let placed = false;
|
|
3887
3879
|
for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3880
|
+
for (const group of this._wasmGroupsOf(moduleRuntime)) {
|
|
3881
|
+
placed = true;
|
|
3882
|
+
if (!onlyFetching.get(group)) return false;
|
|
3883
|
+
}
|
|
3891
3884
|
}
|
|
3892
3885
|
// In no runtime at all nothing named a loader, so `output` answers.
|
|
3893
|
-
|
|
3894
|
-
const only = this._wasmGroupOnlyFetches();
|
|
3895
|
-
const groups = this._wasmRuntimeGroups();
|
|
3896
|
-
for (const key of keys) {
|
|
3897
|
-
if (!only.get(this._wasmGroupOf(groups, key))) return false;
|
|
3898
|
-
}
|
|
3899
|
-
return true;
|
|
3886
|
+
return placed || this.outputOptions.wasmLoading === "fetch";
|
|
3900
3887
|
}
|
|
3901
3888
|
|
|
3902
3889
|
/**
|
|
@@ -4073,6 +4060,18 @@ class RuntimeTemplate {
|
|
|
4073
4060
|
let chunksById;
|
|
4074
4061
|
/** @type {Map<string, Chunk> | undefined} */
|
|
4075
4062
|
let chunkByAsset;
|
|
4063
|
+
/** @type {string | undefined} */
|
|
4064
|
+
let publicPathText;
|
|
4065
|
+
// One value for the whole pass, however many stand-ins read it.
|
|
4066
|
+
const resolvedPublicPath = () => {
|
|
4067
|
+
if (publicPathText === undefined) {
|
|
4068
|
+
publicPathText = compilation.getPath(
|
|
4069
|
+
outputOptions.publicPath || "",
|
|
4070
|
+
{}
|
|
4071
|
+
);
|
|
4072
|
+
}
|
|
4073
|
+
return publicPathText;
|
|
4074
|
+
};
|
|
4076
4075
|
/**
|
|
4077
4076
|
* @param {string} name an emitted asset's name
|
|
4078
4077
|
* @returns {Chunk | undefined} the chunk it was emitted for
|
|
@@ -4127,10 +4126,7 @@ class RuntimeTemplate {
|
|
|
4127
4126
|
{}
|
|
4128
4127
|
);
|
|
4129
4128
|
} else if (kind === "publicPath") {
|
|
4130
|
-
specifier +=
|
|
4131
|
-
outputOptions.publicPath || "",
|
|
4132
|
-
{}
|
|
4133
|
-
);
|
|
4129
|
+
specifier += resolvedPublicPath();
|
|
4134
4130
|
} else if (kind === "unserved") {
|
|
4135
4131
|
const holder = chunkOf(assetName);
|
|
4136
4132
|
if (holder === undefined) return null;
|
|
@@ -4141,10 +4137,7 @@ class RuntimeTemplate {
|
|
|
4141
4137
|
compilation.runtimeTemplate._chunkPlacement(holder).loaded ===
|
|
4142
4138
|
false
|
|
4143
4139
|
) {
|
|
4144
|
-
const path =
|
|
4145
|
-
outputOptions.publicPath || "",
|
|
4146
|
-
{}
|
|
4147
|
-
);
|
|
4140
|
+
const path = resolvedPublicPath();
|
|
4148
4141
|
// The `../` already reached the root this is read from.
|
|
4149
4142
|
specifier += path.startsWith("./") ? path.slice(2) : path;
|
|
4150
4143
|
}
|