webpack 5.42.1 → 5.45.1

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.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

Files changed (43) hide show
  1. package/lib/Compilation.js +5 -2
  2. package/lib/Compiler.js +4 -4
  3. package/lib/ExternalModule.js +18 -0
  4. package/lib/ExternalModuleFactoryPlugin.js +1 -1
  5. package/lib/FileSystemInfo.js +14 -15
  6. package/lib/FlagDependencyUsagePlugin.js +5 -1
  7. package/lib/MultiCompiler.js +10 -8
  8. package/lib/SourceMapDevToolPlugin.js +1 -1
  9. package/lib/Template.js +1 -0
  10. package/lib/Watching.js +12 -0
  11. package/lib/asset/AssetGenerator.js +28 -15
  12. package/lib/container/ContainerPlugin.js +4 -1
  13. package/lib/container/ModuleFederationPlugin.js +1 -0
  14. package/lib/dependencies/WorkerPlugin.js +1 -1
  15. package/lib/esm/ExportWebpackRequireRuntimeModule.js +29 -0
  16. package/lib/esm/ModuleChunkFormatPlugin.js +91 -11
  17. package/lib/esm/ModuleChunkLoadingPlugin.js +13 -0
  18. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +46 -37
  19. package/lib/hmr/lazyCompilationBackend.js +5 -2
  20. package/lib/javascript/JavascriptModulesPlugin.js +3 -1
  21. package/lib/json/JsonData.js +41 -0
  22. package/lib/json/JsonGenerator.js +8 -2
  23. package/lib/json/JsonParser.js +2 -1
  24. package/lib/library/SystemLibraryPlugin.js +1 -1
  25. package/lib/optimize/ConcatenatedModule.js +16 -0
  26. package/lib/optimize/RuntimeChunkPlugin.js +1 -1
  27. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +5 -4
  28. package/lib/rules/RuleSetCompiler.js +2 -2
  29. package/lib/runtime/OnChunksLoadedRuntimeModule.js +5 -1
  30. package/lib/schemes/DataUriPlugin.js +7 -6
  31. package/lib/util/StackedCacheMap.js +110 -0
  32. package/lib/util/internalSerializables.js +1 -0
  33. package/lib/util/makeSerializable.js +0 -1
  34. package/lib/webpack.js +1 -1
  35. package/package.json +24 -18
  36. package/schemas/WebpackOptions.check.js +1 -1
  37. package/schemas/WebpackOptions.json +9 -2
  38. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  39. package/schemas/plugins/container/ContainerPlugin.json +15 -0
  40. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  41. package/schemas/plugins/container/ModuleFederationPlugin.json +15 -0
  42. package/types.d.ts +22 -9
  43. package/lib/util/StackedSetMap.js +0 -166
@@ -855,10 +855,13 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
855
855
  logger: this.getLogger("webpack.FileSystemInfo")
856
856
  });
857
857
  if (compiler.fileTimestamps) {
858
- this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps);
858
+ this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps, true);
859
859
  }
860
860
  if (compiler.contextTimestamps) {
861
- this.fileSystemInfo.addContextTimestamps(compiler.contextTimestamps);
861
+ this.fileSystemInfo.addContextTimestamps(
862
+ compiler.contextTimestamps,
863
+ true
864
+ );
862
865
  }
863
866
  /** @type {Map<string, string | Set<string>>} */
864
867
  this.valueCacheVersions = new Map();
package/lib/Compiler.js CHANGED
@@ -222,13 +222,13 @@ class Compiler {
222
222
  /** @type {Set<string>} */
223
223
  this.immutablePaths = new Set();
224
224
 
225
- /** @type {Set<string>} */
225
+ /** @type {ReadonlySet<string>} */
226
226
  this.modifiedFiles = undefined;
227
- /** @type {Set<string>} */
227
+ /** @type {ReadonlySet<string>} */
228
228
  this.removedFiles = undefined;
229
- /** @type {Map<string, FileSystemInfoEntry | "ignore" | null>} */
229
+ /** @type {ReadonlyMap<string, FileSystemInfoEntry | "ignore" | null>} */
230
230
  this.fileTimestamps = undefined;
231
- /** @type {Map<string, FileSystemInfoEntry | "ignore" | null>} */
231
+ /** @type {ReadonlyMap<string, FileSystemInfoEntry | "ignore" | null>} */
232
232
  this.contextTimestamps = undefined;
233
233
  /** @type {number} */
234
234
  this.fsStartTime = undefined;
@@ -16,6 +16,7 @@ const StaticExportsDependency = require("./dependencies/StaticExportsDependency"
16
16
  const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");
17
17
  const makeSerializable = require("./util/makeSerializable");
18
18
  const propertyAccess = require("./util/propertyAccess");
19
+ const { register } = require("./util/serialization");
19
20
 
20
21
  /** @typedef {import("webpack-sources").Source} Source */
21
22
  /** @typedef {import("../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
@@ -169,6 +170,8 @@ class ModuleExternalInitFragment extends InitFragment {
169
170
  `external module import ${id}`
170
171
  );
171
172
  this._identifier = identifier;
173
+ this._id = id;
174
+ this._request = request;
172
175
  }
173
176
 
174
177
  getNamespaceIdentifier() {
@@ -176,6 +179,21 @@ class ModuleExternalInitFragment extends InitFragment {
176
179
  }
177
180
  }
178
181
 
182
+ register(
183
+ ModuleExternalInitFragment,
184
+ "webpack/lib/ExternalModule",
185
+ "ModuleExternalInitFragment",
186
+ {
187
+ serialize(obj, { write }) {
188
+ write(obj._id);
189
+ write(obj._request);
190
+ },
191
+ deserialize({ read }) {
192
+ return new ModuleExternalInitFragment(read(), read());
193
+ }
194
+ }
195
+ );
196
+
179
197
  const generateModuleRemapping = (input, exportsInfo, runtime) => {
180
198
  if (exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused) {
181
199
  const properties = [];
@@ -12,7 +12,7 @@ const { resolveByProperty, cachedSetProperty } = require("./util/cleverMerge");
12
12
  /** @typedef {import("../declarations/WebpackOptions").Externals} Externals */
13
13
  /** @typedef {import("./NormalModuleFactory")} NormalModuleFactory */
14
14
 
15
- const UNSPECIFIED_EXTERNAL_TYPE_REGEXP = /^[a-z0-9]+ /;
15
+ const UNSPECIFIED_EXTERNAL_TYPE_REGEXP = /^[a-z0-9-]+ /;
16
16
  const EMPTY_RESOLVE_OPTIONS = {};
17
17
 
18
18
  // TODO webpack 6 remove this
@@ -8,6 +8,7 @@
8
8
  const { create: createResolver } = require("enhanced-resolve");
9
9
  const asyncLib = require("neo-async");
10
10
  const AsyncQueue = require("./util/AsyncQueue");
11
+ const StackedCacheMap = require("./util/StackedCacheMap");
11
12
  const createHash = require("./util/createHash");
12
13
  const { join, dirname, relative } = require("./util/fs");
13
14
  const makeSerializable = require("./util/makeSerializable");
@@ -365,7 +366,7 @@ class Snapshot {
365
366
  }
366
367
 
367
368
  /**
368
- * @param {function(Snapshot): (Map<string, any> | Set<string>)[]} getMaps first
369
+ * @param {function(Snapshot): (ReadonlyMap<string, any> | ReadonlySet<string>)[]} getMaps first
369
370
  * @returns {Iterable<string>} iterable
370
371
  */
371
372
  _createIterable(getMaps) {
@@ -853,14 +854,14 @@ class FileSystemInfo {
853
854
  (s, v) => s.setManagedMissing(v),
854
855
  true
855
856
  );
856
- /** @type {Map<string, FileSystemInfoEntry | "ignore" | null>} */
857
- this._fileTimestamps = new Map();
857
+ /** @type {StackedCacheMap<string, FileSystemInfoEntry | "ignore" | null>} */
858
+ this._fileTimestamps = new StackedCacheMap();
858
859
  /** @type {Map<string, string>} */
859
860
  this._fileHashes = new Map();
860
861
  /** @type {Map<string, TimestampAndHash | string>} */
861
862
  this._fileTshs = new Map();
862
- /** @type {Map<string, FileSystemInfoEntry | "ignore" | null>} */
863
- this._contextTimestamps = new Map();
863
+ /** @type {StackedCacheMap<string, FileSystemInfoEntry | "ignore" | null>} */
864
+ this._contextTimestamps = new StackedCacheMap();
864
865
  /** @type {Map<string, string>} */
865
866
  this._contextHashes = new Map();
866
867
  /** @type {Map<string, TimestampAndHash | string>} */
@@ -1060,24 +1061,22 @@ class FileSystemInfo {
1060
1061
  }
1061
1062
 
1062
1063
  /**
1063
- * @param {Map<string, FileSystemInfoEntry | "ignore" | null>} map timestamps
1064
+ * @param {ReadonlyMap<string, FileSystemInfoEntry | "ignore" | null>} map timestamps
1065
+ * @param {boolean=} immutable if 'map' is immutable and FileSystemInfo can keep referencing it
1064
1066
  * @returns {void}
1065
1067
  */
1066
- addFileTimestamps(map) {
1067
- for (const [path, ts] of map) {
1068
- this._fileTimestamps.set(path, ts);
1069
- }
1068
+ addFileTimestamps(map, immutable) {
1069
+ this._fileTimestamps.addAll(map, immutable);
1070
1070
  this._cachedDeprecatedFileTimestamps = undefined;
1071
1071
  }
1072
1072
 
1073
1073
  /**
1074
- * @param {Map<string, FileSystemInfoEntry | "ignore" | null>} map timestamps
1074
+ * @param {ReadonlyMap<string, FileSystemInfoEntry | "ignore" | null>} map timestamps
1075
+ * @param {boolean=} immutable if 'map' is immutable and FileSystemInfo can keep referencing it
1075
1076
  * @returns {void}
1076
1077
  */
1077
- addContextTimestamps(map) {
1078
- for (const [path, ts] of map) {
1079
- this._contextTimestamps.set(path, ts);
1080
- }
1078
+ addContextTimestamps(map, immutable) {
1079
+ this._contextTimestamps.addAll(map, immutable);
1081
1080
  this._cachedDeprecatedContextTimestamps = undefined;
1082
1081
  }
1083
1082
 
@@ -180,7 +180,11 @@ class FlagDependencyUsagePlugin {
180
180
  b.groupOptions &&
181
181
  b.groupOptions.entryOptions
182
182
  ) {
183
- processModule(b, b.groupOptions.entryOptions.runtime, true);
183
+ processModule(
184
+ b,
185
+ b.groupOptions.entryOptions.runtime || undefined,
186
+ true
187
+ );
184
188
  } else {
185
189
  queue.enqueue(b);
186
190
  }
@@ -313,12 +313,12 @@ module.exports = class MultiCompiler {
313
313
  /**
314
314
  * @template SetupResult
315
315
  * @param {function(Compiler, number, Callback<Stats>, function(): boolean, function(): void, function(): void): SetupResult} setup setup a single compiler
316
- * @param {function(Compiler, Callback<Stats>): void} run run/continue a single compiler
316
+ * @param {function(Compiler, SetupResult, Callback<Stats>): void} run run/continue a single compiler
317
317
  * @param {Callback<MultiStats>} callback callback when all compilers are done, result includes Stats of all changed compilers
318
318
  * @returns {SetupResult[]} result of setup
319
319
  */
320
320
  _runGraph(setup, run, callback) {
321
- /** @typedef {{ compiler: Compiler, result: Stats, state: "pending" | "blocked" | "queued" | "starting" | "running" | "running-outdated" | "done", children: Node[], parents: Node[] }} Node */
321
+ /** @typedef {{ compiler: Compiler, setupResult: SetupResult, result: Stats, state: "pending" | "blocked" | "queued" | "starting" | "running" | "running-outdated" | "done", children: Node[], parents: Node[] }} Node */
322
322
 
323
323
  // State transitions for nodes:
324
324
  // -> blocked (initial)
@@ -335,6 +335,7 @@ module.exports = class MultiCompiler {
335
335
  /** @type {Node[]} */
336
336
  const nodes = this.compilers.map(compiler => ({
337
337
  compiler,
338
+ setupResult: undefined,
338
339
  result: undefined,
339
340
  state: "blocked",
340
341
  children: [],
@@ -444,14 +445,14 @@ module.exports = class MultiCompiler {
444
445
  const setupResults = [];
445
446
  nodes.forEach((node, i) => {
446
447
  setupResults.push(
447
- setup(
448
+ (node.setupResult = setup(
448
449
  node.compiler,
449
450
  i,
450
451
  nodeDone.bind(null, node),
451
452
  () => node.state !== "starting" && node.state !== "running",
452
453
  () => nodeChange(node),
453
454
  () => nodeInvalid(node)
454
- )
455
+ ))
455
456
  );
456
457
  });
457
458
  let processing = true;
@@ -470,7 +471,7 @@ module.exports = class MultiCompiler {
470
471
  ) {
471
472
  running++;
472
473
  node.state = "starting";
473
- run(node.compiler, nodeDone.bind(null, node));
474
+ run(node.compiler, node.setupResult, nodeDone.bind(null, node));
474
475
  node.state = "running";
475
476
  }
476
477
  }
@@ -522,8 +523,9 @@ module.exports = class MultiCompiler {
522
523
  }
523
524
  return watching;
524
525
  },
525
- (compiler, initial, callback) => {
526
- if (!compiler.watching.running) compiler.watching.invalidate();
526
+ (compiler, watching, callback) => {
527
+ if (compiler.watching !== watching) return;
528
+ if (!watching.running) watching.invalidate();
527
529
  },
528
530
  handler
529
531
  );
@@ -546,7 +548,7 @@ module.exports = class MultiCompiler {
546
548
  if (this.validateDependencies(callback)) {
547
549
  this._runGraph(
548
550
  () => {},
549
- (compiler, callback) => compiler.run(callback),
551
+ (compiler, setupResult, callback) => compiler.run(callback),
550
552
  (err, stats) => {
551
553
  this.running = false;
552
554
 
@@ -152,7 +152,7 @@ class SourceMapDevToolPlugin {
152
152
  const fallbackModuleFilenameTemplate = this.fallbackModuleFilenameTemplate;
153
153
  const requestShortener = compiler.requestShortener;
154
154
  const options = this.options;
155
- options.test = options.test || /\.(m?js|css)($|\?)/i;
155
+ options.test = options.test || /\.((c|m)?js|css)($|\?)/i;
156
156
 
157
157
  const matchObject = ModuleFilenameHelpers.matchObject.bind(
158
158
  undefined,
package/lib/Template.js CHANGED
@@ -379,6 +379,7 @@ class Template {
379
379
  source.add(Template.toNormalComment(module.identifier()) + "\n");
380
380
  if (!module.shouldIsolate()) {
381
381
  source.add(runtimeSource);
382
+ source.add("\n\n");
382
383
  } else if (renderContext.runtimeTemplate.supportsArrowFunction()) {
383
384
  source.add("(() => {\n");
384
385
  if (renderContext.useStrict) source.add('\t"use strict";\n');
package/lib/Watching.js CHANGED
@@ -10,6 +10,7 @@ const Stats = require("./Stats");
10
10
  /** @typedef {import("../declarations/WebpackOptions").WatchOptions} WatchOptions */
11
11
  /** @typedef {import("./Compilation")} Compilation */
12
12
  /** @typedef {import("./Compiler")} Compiler */
13
+ /** @typedef {import("./FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
13
14
 
14
15
  /**
15
16
  * @template T
@@ -67,6 +68,10 @@ class Watching {
67
68
  });
68
69
  }
69
70
 
71
+ /**
72
+ * @param {ReadonlySet<string>} changedFiles changed files
73
+ * @param {ReadonlySet<string>} removedFiles removed files
74
+ */
70
75
  _mergeWithCollected(changedFiles, removedFiles) {
71
76
  if (!changedFiles) return;
72
77
  if (!this._collectedChangedFiles) {
@@ -84,6 +89,13 @@ class Watching {
84
89
  }
85
90
  }
86
91
 
92
+ /**
93
+ * @param {ReadonlyMap<string, FileSystemInfoEntry | "ignore">=} fileTimeInfoEntries info for files
94
+ * @param {ReadonlyMap<string, FileSystemInfoEntry | "ignore">=} contextTimeInfoEntries info for directories
95
+ * @param {ReadonlySet<string>=} changedFiles changed files
96
+ * @param {ReadonlySet<string>=} removedFiles removed files
97
+ * @returns {void}
98
+ */
87
99
  _go(fileTimeInfoEntries, contextTimeInfoEntries, changedFiles, removedFiles) {
88
100
  this._initial = false;
89
101
  if (this.startTime === null) this.startTime = Date.now();
@@ -141,7 +141,9 @@ class AssetGenerator extends Generator {
141
141
  module.resourceResolveData &&
142
142
  module.resourceResolveData.mimetype !== undefined
143
143
  ) {
144
- mimeType = module.resourceResolveData.mimetype;
144
+ mimeType =
145
+ module.resourceResolveData.mimetype +
146
+ module.resourceResolveData.parameters;
145
147
  } else if (ext) {
146
148
  mimeType = mimeTypes.lookup(ext);
147
149
  }
@@ -156,22 +158,33 @@ class AssetGenerator extends Generator {
156
158
  }
157
159
 
158
160
  let encodedContent;
159
- switch (encoding) {
160
- case "base64": {
161
- encodedContent = originalSource.buffer().toString("base64");
162
- break;
163
- }
164
- case false: {
165
- const content = originalSource.source();
166
- if (typeof content === "string") {
167
- encodedContent = encodeURI(content);
168
- } else {
169
- encodedContent = encodeURI(content.toString("utf-8"));
161
+ if (
162
+ module.resourceResolveData &&
163
+ module.resourceResolveData.encoding === encoding
164
+ ) {
165
+ encodedContent = module.resourceResolveData.encodedContent;
166
+ } else {
167
+ switch (encoding) {
168
+ case "base64": {
169
+ encodedContent = originalSource.buffer().toString("base64");
170
+ break;
171
+ }
172
+ case false: {
173
+ const content = originalSource.source();
174
+
175
+ if (typeof content !== "string") {
176
+ encodedContent = content.toString("utf-8");
177
+ }
178
+
179
+ encodedContent = encodeURIComponent(encodedContent).replace(
180
+ /[!'()*]/g,
181
+ character => "%" + character.codePointAt(0).toString(16)
182
+ );
183
+ break;
170
184
  }
171
- break;
185
+ default:
186
+ throw new Error(`Unsupported encoding '${encoding}'`);
172
187
  }
173
- default:
174
- throw new Error(`Unsupported encoding '${encoding}'`);
175
188
  }
176
189
 
177
190
  encodedSource = `data:${mimeType}${
@@ -39,6 +39,7 @@ class ContainerPlugin {
39
39
  type: "var",
40
40
  name: options.name
41
41
  },
42
+ runtime: options.runtime,
42
43
  filename: options.filename || undefined,
43
44
  exposes: parseOptions(
44
45
  options.exposes,
@@ -60,7 +61,8 @@ class ContainerPlugin {
60
61
  * @returns {void}
61
62
  */
62
63
  apply(compiler) {
63
- const { name, exposes, shareScope, filename, library } = this._options;
64
+ const { name, exposes, shareScope, filename, library, runtime } =
65
+ this._options;
64
66
 
65
67
  compiler.options.output.enabledLibraryTypes.push(library.type);
66
68
 
@@ -73,6 +75,7 @@ class ContainerPlugin {
73
75
  {
74
76
  name,
75
77
  filename,
78
+ runtime,
76
79
  library
77
80
  },
78
81
  error => {
@@ -64,6 +64,7 @@ class ModuleFederationPlugin {
64
64
  name: options.name,
65
65
  library,
66
66
  filename: options.filename,
67
+ runtime: options.runtime,
67
68
  exposes: options.exposes
68
69
  }).apply(compiler);
69
70
  }
@@ -270,7 +270,7 @@ class WorkerPlugin {
270
270
  entryOptions.name = options.name;
271
271
  }
272
272
 
273
- if (!entryOptions.runtime) {
273
+ if (entryOptions.runtime === undefined) {
274
274
  let i = workerIndexMap.get(parser.state) || 0;
275
275
  workerIndexMap.set(parser.state, i + 1);
276
276
  let name = `${cachedContextify(
@@ -0,0 +1,29 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ */
4
+
5
+ "use strict";
6
+
7
+ const RuntimeModule = require("../RuntimeModule");
8
+
9
+ class ExportWebpackRequireRuntimeModule extends RuntimeModule {
10
+ constructor() {
11
+ super("export webpack runtime", RuntimeModule.STAGE_ATTACH);
12
+ }
13
+
14
+ /**
15
+ * @returns {boolean} true, if the runtime module should get it's own scope
16
+ */
17
+ shouldIsolate() {
18
+ return false;
19
+ }
20
+
21
+ /**
22
+ * @returns {string} runtime code
23
+ */
24
+ generate() {
25
+ return "export default __webpack_require__;";
26
+ }
27
+ }
28
+
29
+ module.exports = ExportWebpackRequireRuntimeModule;
@@ -5,13 +5,18 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const { ConcatSource } = require("webpack-sources");
8
+ const { ConcatSource, RawSource } = require("webpack-sources");
9
9
  const { RuntimeGlobals } = require("..");
10
10
  const HotUpdateChunk = require("../HotUpdateChunk");
11
11
  const Template = require("../Template");
12
12
  const {
13
- getCompilationHooks
13
+ getCompilationHooks,
14
+ getChunkFilenameTemplate
14
15
  } = require("../javascript/JavascriptModulesPlugin");
16
+ const {
17
+ generateEntryStartup,
18
+ updateHashForEntryStartup
19
+ } = require("../javascript/StartupHelpers");
15
20
 
16
21
  /** @typedef {import("../Compiler")} Compiler */
17
22
 
@@ -30,8 +35,9 @@ class ModuleChunkFormatPlugin {
30
35
  (chunk, set) => {
31
36
  if (chunk.hasRuntime()) return;
32
37
  if (compilation.chunkGraph.getNumberOfEntryModules(chunk) > 0) {
33
- set.add(RuntimeGlobals.onChunksLoaded);
34
38
  set.add(RuntimeGlobals.require);
39
+ set.add(RuntimeGlobals.startupEntrypoint);
40
+ set.add(RuntimeGlobals.externalInstallChunk);
35
41
  }
36
42
  }
37
43
  );
@@ -39,7 +45,7 @@ class ModuleChunkFormatPlugin {
39
45
  hooks.renderChunk.tap(
40
46
  "ModuleChunkFormatPlugin",
41
47
  (modules, renderContext) => {
42
- const { chunk, chunkGraph } = renderContext;
48
+ const { chunk, chunkGraph, runtimeTemplate } = renderContext;
43
49
  const hotUpdateChunk =
44
50
  chunk instanceof HotUpdateChunk ? chunk : null;
45
51
  const source = new ConcatSource();
@@ -68,9 +74,84 @@ class ModuleChunkFormatPlugin {
68
74
  chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
69
75
  );
70
76
  if (entries.length > 0) {
71
- throw new Error(
72
- "Entry modules in chunk is not implemented for module chunk format yet"
77
+ const runtimeChunk = entries[0][1].getRuntimeChunk();
78
+ const currentOutputName = compilation
79
+ .getPath(
80
+ getChunkFilenameTemplate(chunk, compilation.outputOptions),
81
+ {
82
+ chunk,
83
+ contentHashType: "javascript"
84
+ }
85
+ )
86
+ .split("/");
87
+ const runtimeOutputName = compilation
88
+ .getPath(
89
+ getChunkFilenameTemplate(
90
+ runtimeChunk,
91
+ compilation.outputOptions
92
+ ),
93
+ {
94
+ chunk: runtimeChunk,
95
+ contentHashType: "javascript"
96
+ }
97
+ )
98
+ .split("/");
99
+
100
+ // remove filename, we only need the directory
101
+ const outputFilename = currentOutputName.pop();
102
+
103
+ // remove common parts
104
+ while (
105
+ currentOutputName.length > 0 &&
106
+ runtimeOutputName.length > 0 &&
107
+ currentOutputName[0] === runtimeOutputName[0]
108
+ ) {
109
+ currentOutputName.shift();
110
+ runtimeOutputName.shift();
111
+ }
112
+
113
+ // create final path
114
+ const runtimePath =
115
+ (currentOutputName.length > 0
116
+ ? "../".repeat(currentOutputName.length)
117
+ : "./") + runtimeOutputName.join("/");
118
+
119
+ const entrySource = new ConcatSource();
120
+ entrySource.add(source);
121
+ entrySource.add(";\n\n// load runtime\n");
122
+ entrySource.add(
123
+ `import __webpack_require__ from ${JSON.stringify(
124
+ runtimePath
125
+ )};\n`
126
+ );
127
+ entrySource.add(
128
+ `import * as __webpack_self_exports__ from ${JSON.stringify(
129
+ "./" + outputFilename
130
+ )};\n`
131
+ );
132
+ entrySource.add(
133
+ `${RuntimeGlobals.externalInstallChunk}(__webpack_self_exports__);\n`
134
+ );
135
+ const startupSource = new RawSource(
136
+ generateEntryStartup(
137
+ chunkGraph,
138
+ runtimeTemplate,
139
+ entries,
140
+ chunk,
141
+ false
142
+ )
143
+ );
144
+ entrySource.add(
145
+ hooks.renderStartup.call(
146
+ startupSource,
147
+ entries[entries.length - 1][0],
148
+ {
149
+ ...renderContext,
150
+ inlined: false
151
+ }
152
+ )
73
153
  );
154
+ return entrySource;
74
155
  }
75
156
  }
76
157
  return source;
@@ -82,11 +163,10 @@ class ModuleChunkFormatPlugin {
82
163
  if (chunk.hasRuntime()) return;
83
164
  hash.update("ModuleChunkFormatPlugin");
84
165
  hash.update("1");
85
- // TODO
86
- // const entries = Array.from(
87
- // chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
88
- // );
89
- // updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
166
+ const entries = Array.from(
167
+ chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
168
+ );
169
+ updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
90
170
  }
91
171
  );
92
172
  }
@@ -6,6 +6,7 @@
6
6
  "use strict";
7
7
 
8
8
  const RuntimeGlobals = require("../RuntimeGlobals");
9
+ const ExportWebpackRequireRuntimeModule = require("./ExportWebpackRequireRuntimeModule");
9
10
  const ModuleChunkLoadingRuntimeModule = require("./ModuleChunkLoadingRuntimeModule");
10
11
 
11
12
  /** @typedef {import("../Compiler")} Compiler */
@@ -45,9 +46,21 @@ class ModuleChunkLoadingPlugin {
45
46
  compilation.hooks.runtimeRequirementInTree
46
47
  .for(RuntimeGlobals.baseURI)
47
48
  .tap("ModuleChunkLoadingPlugin", handler);
49
+ compilation.hooks.runtimeRequirementInTree
50
+ .for(RuntimeGlobals.externalInstallChunk)
51
+ .tap("ModuleChunkLoadingPlugin", handler);
48
52
  compilation.hooks.runtimeRequirementInTree
49
53
  .for(RuntimeGlobals.onChunksLoaded)
50
54
  .tap("ModuleChunkLoadingPlugin", handler);
55
+ compilation.hooks.runtimeRequirementInTree
56
+ .for(RuntimeGlobals.externalInstallChunk)
57
+ .tap("ModuleChunkLoadingPlugin", (chunk, set) => {
58
+ if (!isEnabledForChunk(chunk)) return;
59
+ compilation.addRuntimeModule(
60
+ chunk,
61
+ new ExportWebpackRequireRuntimeModule()
62
+ );
63
+ });
51
64
 
52
65
  compilation.hooks.runtimeRequirementInTree
53
66
  .for(RuntimeGlobals.ensureChunkHandlers)