webpack 5.39.0 → 5.41.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 (51) hide show
  1. package/README.md +13 -13
  2. package/bin/webpack.js +0 -0
  3. package/lib/Compilation.js +43 -28
  4. package/lib/ConditionalInitFragment.js +15 -12
  5. package/lib/DependencyTemplate.js +3 -2
  6. package/lib/ExternalModule.js +210 -35
  7. package/lib/ExternalModuleFactoryPlugin.js +2 -1
  8. package/lib/InitFragment.js +10 -7
  9. package/lib/MainTemplate.js +1 -1
  10. package/lib/ModuleTemplate.js +0 -9
  11. package/lib/RuntimeTemplate.js +8 -0
  12. package/lib/Template.js +3 -2
  13. package/lib/TemplatedPathPlugin.js +24 -26
  14. package/lib/Watching.js +2 -1
  15. package/lib/WebpackOptionsApply.js +10 -7
  16. package/lib/async-modules/AwaitDependenciesInitFragment.js +4 -1
  17. package/lib/cache/IdleFileCachePlugin.js +60 -13
  18. package/lib/cache/PackFileCacheStrategy.js +4 -1
  19. package/lib/cli.js +1 -1
  20. package/lib/config/defaults.js +53 -12
  21. package/lib/config/normalization.js +1 -0
  22. package/lib/dependencies/HarmonyExportInitFragment.js +4 -1
  23. package/lib/dependencies/WorkerPlugin.js +25 -10
  24. package/lib/electron/ElectronTargetPlugin.js +3 -3
  25. package/lib/esm/ModuleChunkFormatPlugin.js +97 -0
  26. package/lib/esm/ModuleChunkLoadingPlugin.js +63 -0
  27. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +208 -0
  28. package/lib/hmr/lazyCompilationBackend.js +17 -1
  29. package/lib/javascript/EnableChunkLoadingPlugin.js +5 -3
  30. package/lib/javascript/JavascriptModulesPlugin.js +80 -17
  31. package/lib/javascript/JavascriptParser.js +12 -4
  32. package/lib/node/NodeTargetPlugin.js +2 -1
  33. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +44 -22
  34. package/lib/optimize/InnerGraphPlugin.js +33 -2
  35. package/lib/optimize/ModuleConcatenationPlugin.js +1 -1
  36. package/lib/runtime/AsyncModuleRuntimeModule.js +8 -4
  37. package/lib/serialization/BinaryMiddleware.js +24 -14
  38. package/lib/serialization/FileMiddleware.js +30 -6
  39. package/lib/serialization/PlainObjectSerializer.js +17 -8
  40. package/lib/serialization/Serializer.js +2 -2
  41. package/lib/serialization/SerializerMiddleware.js +26 -4
  42. package/lib/util/ArrayQueue.js +8 -0
  43. package/lib/util/AsyncQueue.js +9 -0
  44. package/lib/util/LazySet.js +26 -17
  45. package/lib/wasm/EnableWasmLoadingPlugin.js +10 -1
  46. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +2 -2
  47. package/lib/wasm-sync/WebAssemblyModulesPlugin.js +1 -1
  48. package/package.json +17 -17
  49. package/schemas/WebpackOptions.check.js +1 -1
  50. package/schemas/WebpackOptions.json +16 -7
  51. package/types.d.ts +107 -158
@@ -17,11 +17,18 @@ class IdleFileCachePlugin {
17
17
  * @param {TODO} strategy cache strategy
18
18
  * @param {number} idleTimeout timeout
19
19
  * @param {number} idleTimeoutForInitialStore initial timeout
20
+ * @param {number} idleTimeoutAfterLargeChanges timeout after changes
20
21
  */
21
- constructor(strategy, idleTimeout, idleTimeoutForInitialStore) {
22
+ constructor(
23
+ strategy,
24
+ idleTimeout,
25
+ idleTimeoutForInitialStore,
26
+ idleTimeoutAfterLargeChanges
27
+ ) {
22
28
  this.strategy = strategy;
23
29
  this.idleTimeout = idleTimeout;
24
30
  this.idleTimeoutForInitialStore = idleTimeoutForInitialStore;
31
+ this.idleTimeoutAfterLargeChanges = idleTimeoutAfterLargeChanges;
25
32
  }
26
33
 
27
34
  /**
@@ -36,9 +43,13 @@ class IdleFileCachePlugin {
36
43
  idleTimeout,
37
44
  this.idleTimeoutForInitialStore
38
45
  );
39
-
46
+ const idleTimeoutAfterLargeChanges = this.idleTimeoutAfterLargeChanges;
40
47
  const resolvedPromise = Promise.resolve();
41
48
 
49
+ let timeSpendInBuild = 0;
50
+ let timeSpendInStore = 0;
51
+ let avgTimeSpendInStore = 0;
52
+
42
53
  /** @type {Map<string | typeof BUILD_DEPENDENCIES_KEY, () => Promise>} */
43
54
  const pendingIdleTasks = new Map();
44
55
 
@@ -121,9 +132,10 @@ class IdleFileCachePlugin {
121
132
  let isInitialStore = true;
122
133
  const processIdleTasks = () => {
123
134
  if (isIdle) {
135
+ const startTime = Date.now();
124
136
  if (pendingIdleTasks.size > 0) {
125
137
  const promises = [currentIdlePromise];
126
- const maxTime = Date.now() + 100;
138
+ const maxTime = startTime + 100;
127
139
  let maxCount = 100;
128
140
  for (const [filename, factory] of pendingIdleTasks) {
129
141
  pendingIdleTasks.delete(filename);
@@ -132,13 +144,23 @@ class IdleFileCachePlugin {
132
144
  }
133
145
  currentIdlePromise = Promise.all(promises);
134
146
  currentIdlePromise.then(() => {
147
+ timeSpendInStore += Date.now() - startTime;
135
148
  // Allow to exit the process between
136
- setTimeout(processIdleTasks, 0).unref();
149
+ idleTimer = setTimeout(processIdleTasks, 0);
150
+ idleTimer.unref();
137
151
  });
138
152
  return;
139
153
  }
140
154
  currentIdlePromise = currentIdlePromise
141
- .then(() => strategy.afterAllStored())
155
+ .then(async () => {
156
+ await strategy.afterAllStored();
157
+ timeSpendInStore += Date.now() - startTime;
158
+ avgTimeSpendInStore =
159
+ Math.max(avgTimeSpendInStore, timeSpendInStore) * 0.9 +
160
+ timeSpendInStore * 0.1;
161
+ timeSpendInStore = 0;
162
+ timeSpendInBuild = 0;
163
+ })
142
164
  .catch(err => {
143
165
  const logger = compiler.getInfrastructureLogger(
144
166
  "IdleFileCachePlugin"
@@ -153,14 +175,34 @@ class IdleFileCachePlugin {
153
175
  compiler.cache.hooks.beginIdle.tap(
154
176
  { name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
155
177
  () => {
156
- idleTimer = setTimeout(
157
- () => {
158
- idleTimer = undefined;
159
- isIdle = true;
160
- resolvedPromise.then(processIdleTasks);
161
- },
162
- isInitialStore ? idleTimeoutForInitialStore : idleTimeout
163
- );
178
+ const isLargeChange = timeSpendInBuild > avgTimeSpendInStore * 2;
179
+ if (isInitialStore && idleTimeoutForInitialStore < idleTimeout) {
180
+ compiler
181
+ .getInfrastructureLogger("IdleFileCachePlugin")
182
+ .log(
183
+ `Initial cache was generated and cache will be persisted in ${
184
+ idleTimeoutForInitialStore / 1000
185
+ }s.`
186
+ );
187
+ } else if (
188
+ isLargeChange &&
189
+ idleTimeoutAfterLargeChanges < idleTimeout
190
+ ) {
191
+ compiler
192
+ .getInfrastructureLogger("IdleFileCachePlugin")
193
+ .log(
194
+ `Spend ${Math.round(timeSpendInBuild) / 1000}s in build and ${
195
+ Math.round(avgTimeSpendInStore) / 1000
196
+ }s in average in cache store. This is considered as large change and cache will be persisted in ${
197
+ idleTimeoutAfterLargeChanges / 1000
198
+ }s.`
199
+ );
200
+ }
201
+ idleTimer = setTimeout(() => {
202
+ idleTimer = undefined;
203
+ isIdle = true;
204
+ resolvedPromise.then(processIdleTasks);
205
+ }, Math.min(isInitialStore ? idleTimeoutForInitialStore : Infinity, isLargeChange ? idleTimeoutAfterLargeChanges : Infinity, idleTimeout));
164
206
  idleTimer.unref();
165
207
  }
166
208
  );
@@ -174,6 +216,11 @@ class IdleFileCachePlugin {
174
216
  isIdle = false;
175
217
  }
176
218
  );
219
+ compiler.hooks.done.tap("IdleFileCachePlugin", stats => {
220
+ // 10% build overhead is ignored, as it's not cacheable
221
+ timeSpendInBuild *= 0.9;
222
+ timeSpendInBuild += stats.endTime - stats.startTime;
223
+ });
177
224
  }
178
225
  }
179
226
 
@@ -8,6 +8,7 @@
8
8
  const FileSystemInfo = require("../FileSystemInfo");
9
9
  const ProgressPlugin = require("../ProgressPlugin");
10
10
  const { formatSize } = require("../SizeFormatHelpers");
11
+ const SerializerMiddleware = require("../serialization/SerializerMiddleware");
11
12
  const LazySet = require("../util/LazySet");
12
13
  const makeSerializable = require("../util/makeSerializable");
13
14
  const memoize = require("../util/memoize");
@@ -677,7 +678,7 @@ class PackContent {
677
678
  */
678
679
  constructor(items, usedItems, dataOrFn, logger, lazyName) {
679
680
  this.items = items;
680
- /** @type {function(): PackContentItems | Promise<PackContentItems>} */
681
+ /** @type {function(): Promise<PackContentItems> | PackContentItems } */
681
682
  this.lazy = typeof dataOrFn === "function" ? dataOrFn : undefined;
682
683
  /** @type {Map<string, any>} */
683
684
  this.content = typeof dataOrFn === "function" ? undefined : dataOrFn.map;
@@ -715,6 +716,7 @@ class PackContent {
715
716
  this.logger.timeEnd(timeMessage);
716
717
  }
717
718
  this.content = map;
719
+ this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
718
720
  return map.get(identifier);
719
721
  });
720
722
  } else {
@@ -723,6 +725,7 @@ class PackContent {
723
725
  this.logger.timeEnd(timeMessage);
724
726
  }
725
727
  this.content = map;
728
+ this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
726
729
  return map.get(identifier);
727
730
  }
728
731
  }
package/lib/cli.js CHANGED
@@ -148,7 +148,7 @@ const getArguments = (schema = webpackSchema) => {
148
148
  {
149
149
  type: "reset",
150
150
  multiple: false,
151
- description: `Clear all items provided in configuration. ${description}`,
151
+ description: `Clear all items provided in '${schemaPath}' configuration. ${description}`,
152
152
  path: schemaPath
153
153
  }
154
154
  ],
@@ -182,6 +182,11 @@ const applyWebpackOptionsDefaults = options => {
182
182
  applyOutputDefaults(options.output, {
183
183
  context: options.context,
184
184
  targetProperties,
185
+ isAffectedByBrowserslist:
186
+ target === undefined ||
187
+ (typeof target === "string" && target.startsWith("browserslist")) ||
188
+ (Array.isArray(target) &&
189
+ target.some(target => target.startsWith("browserslist"))),
185
190
  outputModule: options.experiments.outputModule,
186
191
  development,
187
192
  entry: options.entry,
@@ -295,7 +300,8 @@ const applyCacheDefaults = (cache, { name, mode, development }) => {
295
300
  D(cache, "store", "pack");
296
301
  D(cache, "profile", false);
297
302
  D(cache, "idleTimeout", 60000);
298
- D(cache, "idleTimeoutForInitialStore", 0);
303
+ D(cache, "idleTimeoutForInitialStore", 5000);
304
+ D(cache, "idleTimeoutAfterLargeChanges", 1000);
299
305
  D(cache, "maxMemoryGenerations", development ? 5 : Infinity);
300
306
  D(cache, "maxAge", 1000 * 60 * 60 * 24 * 60); // 1 month
301
307
  D(cache, "allowCollectingMemory", development);
@@ -543,6 +549,7 @@ const applyModuleDefaults = (
543
549
  * @param {Object} options options
544
550
  * @param {string} options.context context
545
551
  * @param {TargetProperties | false} options.targetProperties target properties
552
+ * @param {boolean} options.isAffectedByBrowserslist is affected by browserslist
546
553
  * @param {boolean} options.outputModule is outputModule experiment enabled
547
554
  * @param {boolean} options.development is development mode
548
555
  * @param {Entry} options.entry entry option
@@ -551,7 +558,15 @@ const applyModuleDefaults = (
551
558
  */
552
559
  const applyOutputDefaults = (
553
560
  output,
554
- { context, targetProperties: tp, outputModule, development, entry, module }
561
+ {
562
+ context,
563
+ targetProperties: tp,
564
+ isAffectedByBrowserslist,
565
+ outputModule,
566
+ development,
567
+ entry,
568
+ module
569
+ }
555
570
  ) => {
556
571
  /**
557
572
  * @param {Library=} library the library option
@@ -591,8 +606,8 @@ const applyOutputDefaults = (
591
606
  }
592
607
  });
593
608
 
594
- D(output, "filename", "[name].js");
595
609
  F(output, "module", () => !!outputModule);
610
+ D(output, "filename", output.module ? "[name].mjs" : "[name].js");
596
611
  F(output, "iife", () => !output.module);
597
612
  D(output, "importFunctionName", "import");
598
613
  D(output, "importMetaName", "import.meta");
@@ -608,7 +623,7 @@ const applyOutputDefaults = (
608
623
  // Otherwise prefix "[id]." in front of the basename to make it changing
609
624
  return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
610
625
  }
611
- return "[id].js";
626
+ return output.module ? "[id].mjs" : "[id].js";
612
627
  });
613
628
  D(output, "assetModuleFilename", "[hash][ext][query]");
614
629
  D(output, "webassemblyModuleFilename", "[hash].module.wasm");
@@ -633,13 +648,34 @@ const applyOutputDefaults = (
633
648
  });
634
649
  F(output, "chunkFormat", () => {
635
650
  if (tp) {
636
- if (tp.document) return "array-push";
637
- if (tp.require) return "commonjs";
638
- if (tp.nodeBuiltins) return "commonjs";
639
- if (tp.importScripts) return "array-push";
640
- if (tp.dynamicImport && output.module) return "module";
651
+ const helpMessage = isAffectedByBrowserslist
652
+ ? "Make sure that your 'browserslist' includes only platforms that support these features or select an appropriate 'target' to allow selecting a chunk format by default. Alternatively specify the 'output.chunkFormat' directly."
653
+ : "Select an appropriate 'target' to allow selecting one by default, or specify the 'output.chunkFormat' directly.";
654
+ if (output.module) {
655
+ if (tp.dynamicImport) return "module";
656
+ if (tp.document) return "array-push";
657
+ throw new Error(
658
+ "For the selected environment is no default ESM chunk format available:\n" +
659
+ "ESM exports can be chosen when 'import()' is available.\n" +
660
+ "JSONP Array push can be chosen when 'document' is available.\n" +
661
+ helpMessage
662
+ );
663
+ } else {
664
+ if (tp.document) return "array-push";
665
+ if (tp.require) return "commonjs";
666
+ if (tp.nodeBuiltins) return "commonjs";
667
+ if (tp.importScripts) return "array-push";
668
+ throw new Error(
669
+ "For the selected environment is no default script chunk format available:\n" +
670
+ "JSONP Array push can be chosen when 'document' or 'importScripts' is available.\n" +
671
+ "CommonJs exports can be chosen when 'require' or node builtins are available.\n" +
672
+ helpMessage
673
+ );
674
+ }
641
675
  }
642
- return false;
676
+ throw new Error(
677
+ "Chunk format can't be selected by default when no target is specified"
678
+ );
643
679
  });
644
680
  F(output, "chunkLoading", () => {
645
681
  if (tp) {
@@ -694,7 +730,8 @@ const applyOutputDefaults = (
694
730
  F(output, "wasmLoading", () => {
695
731
  if (tp) {
696
732
  if (tp.fetchWasm) return "fetch";
697
- if (tp.nodeBuiltins) return "async-node";
733
+ if (tp.nodeBuiltins)
734
+ return output.module ? "async-node-module" : "async-node";
698
735
  if (tp.nodeBuiltins === null || tp.fetchWasm === null) {
699
736
  return "universal";
700
737
  }
@@ -709,7 +746,11 @@ const applyOutputDefaults = (
709
746
  F(output, "path", () => path.join(process.cwd(), "dist"));
710
747
  F(output, "pathinfo", () => development);
711
748
  D(output, "sourceMapFilename", "[file].map[query]");
712
- D(output, "hotUpdateChunkFilename", "[id].[fullhash].hot-update.js");
749
+ D(
750
+ output,
751
+ "hotUpdateChunkFilename",
752
+ `[id].[fullhash].hot-update.${output.module ? "mjs" : "js"}`
753
+ );
713
754
  D(output, "hotUpdateMainFilename", "[runtime].[fullhash].hot-update.json");
714
755
  D(output, "crossOriginLoading", false);
715
756
  F(output, "scriptType", () => (output.module ? "module" : false));
@@ -139,6 +139,7 @@ const getNormalizedWebpackOptions = config => {
139
139
  hashAlgorithm: cache.hashAlgorithm,
140
140
  idleTimeout: cache.idleTimeout,
141
141
  idleTimeoutForInitialStore: cache.idleTimeoutForInitialStore,
142
+ idleTimeoutAfterLargeChanges: cache.idleTimeoutAfterLargeChanges,
142
143
  name: cache.name,
143
144
  store: cache.store,
144
145
  version: cache.version
@@ -31,6 +31,9 @@ const joinIterableWithComma = iterable => {
31
31
  const EMPTY_MAP = new Map();
32
32
  const EMPTY_SET = new Set();
33
33
 
34
+ /**
35
+ * @typedef {GenerateContext} Context
36
+ */
34
37
  class HarmonyExportInitFragment extends InitFragment {
35
38
  /**
36
39
  * @param {string} exportsArgument the exports identifier
@@ -126,7 +129,7 @@ class HarmonyExportInitFragment extends InitFragment {
126
129
  }
127
130
 
128
131
  /**
129
- * @param {GenerateContext} generateContext context for generate
132
+ * @param {Context} context context
130
133
  * @returns {string|Source} the source code that will be included as initialization code
131
134
  */
132
135
  getContent({ runtimeTemplate, runtimeRequirements }) {
@@ -48,9 +48,10 @@ const DEFAULT_SYNTAX = [
48
48
  const workerIndexMap = new WeakMap();
49
49
 
50
50
  class WorkerPlugin {
51
- constructor(chunkLoading, wasmLoading) {
51
+ constructor(chunkLoading, wasmLoading, module) {
52
52
  this._chunkLoading = chunkLoading;
53
53
  this._wasmLoading = wasmLoading;
54
+ this._module = module;
54
55
  }
55
56
  /**
56
57
  * Apply the plugin
@@ -311,31 +312,45 @@ class WorkerPlugin {
311
312
  if (expressions.type) {
312
313
  const expr = expressions.type;
313
314
  if (options.type !== false) {
314
- const dep = new ConstDependency("undefined", expr.range);
315
+ const dep = new ConstDependency(
316
+ this._module ? '"module"' : "undefined",
317
+ expr.range
318
+ );
315
319
  dep.loc = expr.loc;
316
320
  parser.state.module.addPresentationalDependency(dep);
317
321
  expressions.type = undefined;
318
322
  }
319
- } else if (hasSpreadInOptions && insertType === "comma") {
320
- const dep = new ConstDependency(
321
- ", type: undefined",
322
- insertLocation
323
- );
324
- dep.loc = expr.loc;
325
- parser.state.module.addPresentationalDependency(dep);
323
+ } else if (insertType === "comma") {
324
+ if (this._module || hasSpreadInOptions) {
325
+ const dep = new ConstDependency(
326
+ `, type: ${this._module ? '"module"' : "undefined"}`,
327
+ insertLocation
328
+ );
329
+ dep.loc = expr.loc;
330
+ parser.state.module.addPresentationalDependency(dep);
331
+ }
326
332
  } else if (insertType === "spread") {
327
333
  const dep1 = new ConstDependency(
328
334
  "Object.assign({}, ",
329
335
  insertLocation[0]
330
336
  );
331
337
  const dep2 = new ConstDependency(
332
- ", { type: undefined })",
338
+ `, { type: ${this._module ? '"module"' : "undefined"} })`,
333
339
  insertLocation[1]
334
340
  );
335
341
  dep1.loc = expr.loc;
336
342
  dep2.loc = expr.loc;
337
343
  parser.state.module.addPresentationalDependency(dep1);
338
344
  parser.state.module.addPresentationalDependency(dep2);
345
+ } else if (insertType === "argument") {
346
+ if (this._module) {
347
+ const dep = new ConstDependency(
348
+ ', { type: "module" }',
349
+ insertLocation
350
+ );
351
+ dep.loc = expr.loc;
352
+ parser.state.module.addPresentationalDependency(dep);
353
+ }
339
354
  }
340
355
 
341
356
  parser.walkExpression(expr.callee);
@@ -22,7 +22,7 @@ class ElectronTargetPlugin {
22
22
  * @returns {void}
23
23
  */
24
24
  apply(compiler) {
25
- new ExternalsPlugin("commonjs", [
25
+ new ExternalsPlugin("node-commonjs", [
26
26
  "clipboard",
27
27
  "crash-reporter",
28
28
  "electron",
@@ -34,7 +34,7 @@ class ElectronTargetPlugin {
34
34
  ]).apply(compiler);
35
35
  switch (this._context) {
36
36
  case "main":
37
- new ExternalsPlugin("commonjs", [
37
+ new ExternalsPlugin("node-commonjs", [
38
38
  "app",
39
39
  "auto-updater",
40
40
  "browser-window",
@@ -54,7 +54,7 @@ class ElectronTargetPlugin {
54
54
  break;
55
55
  case "preload":
56
56
  case "renderer":
57
- new ExternalsPlugin("commonjs", [
57
+ new ExternalsPlugin("node-commonjs", [
58
58
  "desktop-capturer",
59
59
  "ipc-renderer",
60
60
  "remote",
@@ -0,0 +1,97 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const { ConcatSource } = require("webpack-sources");
9
+ const { RuntimeGlobals } = require("..");
10
+ const HotUpdateChunk = require("../HotUpdateChunk");
11
+ const Template = require("../Template");
12
+ const {
13
+ getCompilationHooks
14
+ } = require("../javascript/JavascriptModulesPlugin");
15
+
16
+ /** @typedef {import("../Compiler")} Compiler */
17
+
18
+ class ModuleChunkFormatPlugin {
19
+ /**
20
+ * Apply the plugin
21
+ * @param {Compiler} compiler the compiler instance
22
+ * @returns {void}
23
+ */
24
+ apply(compiler) {
25
+ compiler.hooks.thisCompilation.tap(
26
+ "ModuleChunkFormatPlugin",
27
+ compilation => {
28
+ compilation.hooks.additionalChunkRuntimeRequirements.tap(
29
+ "ModuleChunkFormatPlugin",
30
+ (chunk, set) => {
31
+ if (chunk.hasRuntime()) return;
32
+ if (compilation.chunkGraph.getNumberOfEntryModules(chunk) > 0) {
33
+ set.add(RuntimeGlobals.onChunksLoaded);
34
+ set.add(RuntimeGlobals.require);
35
+ }
36
+ }
37
+ );
38
+ const hooks = getCompilationHooks(compilation);
39
+ hooks.renderChunk.tap(
40
+ "ModuleChunkFormatPlugin",
41
+ (modules, renderContext) => {
42
+ const { chunk, chunkGraph } = renderContext;
43
+ const hotUpdateChunk =
44
+ chunk instanceof HotUpdateChunk ? chunk : null;
45
+ const source = new ConcatSource();
46
+ if (hotUpdateChunk) {
47
+ throw new Error(
48
+ "HMR is not implemented for module chunk format yet"
49
+ );
50
+ } else {
51
+ source.add(`export const id = ${JSON.stringify(chunk.id)};\n`);
52
+ source.add(`export const ids = ${JSON.stringify(chunk.ids)};\n`);
53
+ source.add(`export const modules = `);
54
+ source.add(modules);
55
+ source.add(`;\n`);
56
+ const runtimeModules =
57
+ chunkGraph.getChunkRuntimeModulesInOrder(chunk);
58
+ if (runtimeModules.length > 0) {
59
+ source.add("export const runtime =\n");
60
+ source.add(
61
+ Template.renderChunkRuntimeModules(
62
+ runtimeModules,
63
+ renderContext
64
+ )
65
+ );
66
+ }
67
+ const entries = Array.from(
68
+ chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
69
+ );
70
+ if (entries.length > 0) {
71
+ throw new Error(
72
+ "Entry modules in chunk is not implemented for module chunk format yet"
73
+ );
74
+ }
75
+ }
76
+ return source;
77
+ }
78
+ );
79
+ hooks.chunkHash.tap(
80
+ "ModuleChunkFormatPlugin",
81
+ (chunk, hash, { chunkGraph, runtimeTemplate }) => {
82
+ if (chunk.hasRuntime()) return;
83
+ hash.update("ModuleChunkFormatPlugin");
84
+ hash.update("1");
85
+ // TODO
86
+ // const entries = Array.from(
87
+ // chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
88
+ // );
89
+ // updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
90
+ }
91
+ );
92
+ }
93
+ );
94
+ }
95
+ }
96
+
97
+ module.exports = ModuleChunkFormatPlugin;
@@ -0,0 +1,63 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const RuntimeGlobals = require("../RuntimeGlobals");
9
+ const ModuleChunkLoadingRuntimeModule = require("./ModuleChunkLoadingRuntimeModule");
10
+
11
+ /** @typedef {import("../Compiler")} Compiler */
12
+
13
+ class ModuleChunkLoadingPlugin {
14
+ /**
15
+ * Apply the plugin
16
+ * @param {Compiler} compiler the compiler instance
17
+ * @returns {void}
18
+ */
19
+ apply(compiler) {
20
+ compiler.hooks.thisCompilation.tap(
21
+ "ModuleChunkLoadingPlugin",
22
+ compilation => {
23
+ const globalChunkLoading = compilation.outputOptions.chunkLoading;
24
+ const isEnabledForChunk = chunk => {
25
+ const options = chunk.getEntryOptions();
26
+ const chunkLoading =
27
+ (options && options.chunkLoading) || globalChunkLoading;
28
+ return chunkLoading === "import";
29
+ };
30
+ const onceForChunkSet = new WeakSet();
31
+ const handler = (chunk, set) => {
32
+ if (onceForChunkSet.has(chunk)) return;
33
+ onceForChunkSet.add(chunk);
34
+ if (!isEnabledForChunk(chunk)) return;
35
+ set.add(RuntimeGlobals.moduleFactoriesAddOnly);
36
+ set.add(RuntimeGlobals.hasOwnProperty);
37
+ compilation.addRuntimeModule(
38
+ chunk,
39
+ new ModuleChunkLoadingRuntimeModule(set)
40
+ );
41
+ };
42
+ compilation.hooks.runtimeRequirementInTree
43
+ .for(RuntimeGlobals.ensureChunkHandlers)
44
+ .tap("ModuleChunkLoadingPlugin", handler);
45
+ compilation.hooks.runtimeRequirementInTree
46
+ .for(RuntimeGlobals.baseURI)
47
+ .tap("ModuleChunkLoadingPlugin", handler);
48
+ compilation.hooks.runtimeRequirementInTree
49
+ .for(RuntimeGlobals.onChunksLoaded)
50
+ .tap("ModuleChunkLoadingPlugin", handler);
51
+
52
+ compilation.hooks.runtimeRequirementInTree
53
+ .for(RuntimeGlobals.ensureChunkHandlers)
54
+ .tap("ModuleChunkLoadingPlugin", (chunk, set) => {
55
+ if (!isEnabledForChunk(chunk)) return;
56
+ set.add(RuntimeGlobals.getChunkScriptFilename);
57
+ });
58
+ }
59
+ );
60
+ }
61
+ }
62
+
63
+ module.exports = ModuleChunkLoadingPlugin;