webpack 5.110.2 → 5.111.0

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.
Files changed (226) hide show
  1. package/README.md +5 -2
  2. package/lib/APIPlugin.js +23 -7
  3. package/lib/AutomaticPrefetchPlugin.js +1 -1
  4. package/lib/Cache.js +8 -3
  5. package/lib/CacheFacade.js +1 -1
  6. package/lib/ChunkGraph.js +20 -18
  7. package/lib/CircularModulesPlugin.js +157 -55
  8. package/lib/CleanPlugin.js +2 -2
  9. package/lib/Compilation.js +321 -303
  10. package/lib/Compiler.js +209 -46
  11. package/lib/ConcatenationScope.js +25 -35
  12. package/lib/ContextModule.js +17 -81
  13. package/lib/ContextModuleFactory.js +1 -1
  14. package/lib/CopyPlugin.js +1054 -0
  15. package/lib/DefinePlugin.js +24 -8
  16. package/lib/DotenvPlugin.js +41 -13
  17. package/lib/ExternalModule.js +41 -14
  18. package/lib/FileSystemInfo.js +17 -14
  19. package/lib/FlagDependencyExportsPlugin.js +45 -21
  20. package/lib/FlagDependencyUsagePlugin.js +8 -2
  21. package/lib/HotModuleReplacementPlugin.js +53 -7
  22. package/lib/JavascriptMetaInfoPlugin.js +5 -3
  23. package/lib/MainTemplate.js +5 -1
  24. package/lib/Module.js +16 -7
  25. package/lib/MultiCompiler.js +1 -1
  26. package/lib/MultiWatching.js +1 -1
  27. package/lib/NormalModule.js +58 -32
  28. package/lib/NormalModuleFactory.js +1 -1
  29. package/lib/RuntimeGlobals.js +21 -7
  30. package/lib/RuntimeModule.js +28 -12
  31. package/lib/RuntimePlugin.js +33 -3
  32. package/lib/RuntimeTemplate.js +794 -477
  33. package/lib/SourceMapDevToolPlugin.js +1 -1
  34. package/lib/Watching.js +9 -0
  35. package/lib/WebpackOptionsApply.js +84 -91
  36. package/lib/asset/AssetGenerator.js +25 -8
  37. package/lib/asset/AssetModule.js +3 -0
  38. package/lib/asset/WebManifestParser.js +7 -5
  39. package/lib/async-modules/AsyncModuleHelpers.js +10 -4
  40. package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
  41. package/lib/cache/IdleFileCachePlugin.js +2 -2
  42. package/lib/cache/PackFileCacheStrategy.js +14 -1
  43. package/lib/config/browserslistTargetHandler.js +19 -0
  44. package/lib/config/defaults.js +110 -64
  45. package/lib/config/normalization.js +100 -20
  46. package/lib/config/target.js +10 -0
  47. package/lib/container/ContainerReferencePlugin.js +6 -0
  48. package/lib/container/RemoteRuntimeModule.js +9 -0
  49. package/lib/container/declaredRemotes.js +39 -0
  50. package/lib/css/CssGenerator.js +8 -0
  51. package/lib/css/CssInjectStyleRuntimeModule.js +9 -0
  52. package/lib/css/CssLoadingRuntimeModule.js +94 -36
  53. package/lib/css/CssModule.js +1 -1
  54. package/lib/css/CssModulesPlugin.js +7 -6
  55. package/lib/css/CssParser.js +144 -11
  56. package/lib/css/CssServerStylesRuntimeModule.js +9 -0
  57. package/lib/css/cssMinify.js +11 -3
  58. package/lib/css/data.js +2814 -678
  59. package/lib/css/syntax.js +4082 -248
  60. package/lib/debug/ProfilingPlugin.js +4 -0
  61. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
  62. package/lib/dependencies/AMDRuntimeModules.js +18 -0
  63. package/lib/dependencies/CommonJsExportRequireDependency.js +3 -1
  64. package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
  65. package/lib/dependencies/CommonJsImportsParserPlugin.js +1 -0
  66. package/lib/dependencies/CommonJsPlugin.js +19 -3
  67. package/lib/dependencies/CommonJsRequireDependency.js +32 -9
  68. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +20 -7
  69. package/lib/dependencies/CssIcssExportDependency.js +7 -1
  70. package/lib/dependencies/HarmonyCompatibilityDependency.js +58 -4
  71. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +8 -3
  72. package/lib/dependencies/HarmonyExportExpressionDependency.js +44 -29
  73. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +171 -32
  74. package/lib/dependencies/HarmonyExportInitFragment.js +99 -19
  75. package/lib/dependencies/HarmonyExportSpecifierDependency.js +18 -30
  76. package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
  77. package/lib/dependencies/HarmonyImportDependency.js +99 -41
  78. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +20 -3
  79. package/lib/dependencies/HarmonyImportSpecifierDependency.js +24 -1
  80. package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
  81. package/lib/dependencies/HtmlEntryDependency.js +62 -2
  82. package/lib/dependencies/ImportContextDependency.js +43 -3
  83. package/lib/dependencies/ImportDependency.js +8 -29
  84. package/lib/dependencies/ImportMetaMainDependency.js +104 -0
  85. package/lib/dependencies/ImportMetaPlugin.js +59 -15
  86. package/lib/dependencies/ImportParserPlugin.js +24 -14
  87. package/lib/dependencies/RequireHeaderDependency.js +20 -21
  88. package/lib/dependencies/SystemRuntimeModule.js +9 -0
  89. package/lib/dependencies/WorkerDependency.js +1 -2
  90. package/lib/dependencies/WorkletDependency.js +1 -2
  91. package/lib/dependencies/importOptionsCheck.js +47 -0
  92. package/lib/dll/DelegatedModule.js +18 -1
  93. package/lib/dll/DllReferencePlugin.js +11 -8
  94. package/lib/dll/LibManifestPlugin.js +1 -1
  95. package/lib/errors/AnalyzableBailoutsWarning.js +41 -0
  96. package/lib/errors/DotenvFileError.js +29 -0
  97. package/lib/errors/DuplicateModulesWarning.js +12 -7
  98. package/lib/errors/EmptyCopyPatternWarning.js +26 -0
  99. package/lib/errors/ExternalStarReexportError.js +44 -0
  100. package/lib/errors/ImportedBindingAssignmentError.js +30 -0
  101. package/lib/errors/MissingSourceMapsWarning.js +36 -0
  102. package/lib/errors/ModuleParseError.js +2 -1
  103. package/lib/errors/UnusedAssetsWarning.js +36 -0
  104. package/lib/errors/UnusedFederationWarning.js +35 -0
  105. package/lib/errors/UnusedModulesWarning.js +38 -0
  106. package/lib/esm/ExportWebpackRequireRuntimeModule.js +9 -0
  107. package/lib/esm/ModuleChunkFormatPlugin.js +28 -3
  108. package/lib/esm/ModuleChunkLoadingPlugin.js +30 -11
  109. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +92 -60
  110. package/lib/hmr/HotModuleReplacement.runtime.js +8 -2
  111. package/lib/hmr/HotModuleReplacementRuntimeModule.js +9 -0
  112. package/lib/html/HtmlGenerator.js +11 -5
  113. package/lib/html/HtmlModulesPlugin.js +360 -84
  114. package/lib/html/HtmlParser.js +13 -6
  115. package/lib/html/builtinEmbeddedRenderer.js +107 -0
  116. package/lib/html/data.js +121 -7
  117. package/lib/html/htmlMinify.js +84 -113
  118. package/lib/html/syntax.js +1067 -569
  119. package/lib/ids/HashedModuleIdsPlugin.js +2 -1
  120. package/lib/index.js +3 -0
  121. package/lib/javascript/JavascriptModule.js +1 -0
  122. package/lib/javascript/JavascriptModulesPlugin.js +52 -22
  123. package/lib/javascript/JavascriptParser.js +1255 -728
  124. package/lib/javascript/StartupHelpers.js +27 -3
  125. package/lib/javascript/data.js +172 -0
  126. package/lib/javascript/grammar.js +5546 -0
  127. package/lib/javascript/parser.js +1494 -0
  128. package/lib/javascript/regexp.js +1762 -0
  129. package/lib/javascript/regexpData.js +51 -0
  130. package/lib/javascript/syntax.js +8696 -5225
  131. package/lib/library/ModuleLibraryPlugin.js +116 -5
  132. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
  133. package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
  134. package/lib/optimize/ConcatenatedModule.js +133 -25
  135. package/lib/optimize/ConstExportsPlugin.js +50 -39
  136. package/lib/optimize/InlineExports.js +20 -123
  137. package/lib/optimize/MangleExportsPlugin.js +10 -0
  138. package/lib/optimize/ModuleConcatenationPlugin.js +24 -1
  139. package/lib/optimize/RealContentHashPlugin.js +68 -9
  140. package/lib/optimize/SideEffectsFlagPlugin.js +17 -9
  141. package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
  142. package/lib/performance/CacheEffectivenessPlugin.js +4 -3
  143. package/lib/performance/DuplicateModulesPlugin.js +57 -13
  144. package/lib/performance/EvalUsagePlugin.js +5 -2
  145. package/lib/performance/MissingSourceMapsPlugin.js +115 -0
  146. package/lib/performance/PureAnnotationsPlugin.js +6 -3
  147. package/lib/performance/TopLevelThisPlugin.js +5 -4
  148. package/lib/performance/UnusedAssetsPlugin.js +109 -0
  149. package/lib/performance/UnusedFederationPlugin.js +147 -0
  150. package/lib/performance/UnusedModulesPlugin.js +141 -0
  151. package/lib/performance/UnusedReexportsPlugin.js +1 -55
  152. package/lib/performance/isOnlyReexported.js +65 -0
  153. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +25 -5
  154. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +2 -0
  155. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +9 -0
  156. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +9 -0
  157. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +9 -0
  158. package/lib/prefetch/ResourceHintPlugin.js +7 -3
  159. package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
  160. package/lib/prefetch/StartupAssetHintRuntimeModule.js +9 -0
  161. package/lib/rules/RuleSetCompiler.js +211 -4
  162. package/lib/runtime/AsyncModuleRuntimeModule.js +105 -67
  163. package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -0
  164. package/lib/runtime/BaseUriRuntimeModule.js +9 -0
  165. package/lib/runtime/ChunkNameRuntimeModule.js +9 -0
  166. package/lib/runtime/EnsureChunkRuntimeModule.js +35 -16
  167. package/lib/runtime/GetChunkFilenameRuntimeModule.js +9 -0
  168. package/lib/runtime/GetFullHashRuntimeModule.js +9 -0
  169. package/lib/runtime/GetMainFilenameRuntimeModule.js +9 -0
  170. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +9 -0
  171. package/lib/runtime/GlobalRuntimeModule.js +9 -0
  172. package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
  173. package/lib/runtime/HelperRuntimeModule.js +10 -0
  174. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +338 -217
  175. package/lib/runtime/NonceRuntimeModule.js +9 -0
  176. package/lib/runtime/OnChunksLoadedRuntimeModule.js +67 -20
  177. package/lib/runtime/PublicPathRuntimeModule.js +9 -0
  178. package/lib/runtime/RuntimeIdRuntimeModule.js +9 -0
  179. package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +90 -0
  180. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +9 -0
  181. package/lib/runtime/StartupEntrypointRuntimeModule.js +9 -0
  182. package/lib/runtime/SystemContextRuntimeModule.js +9 -0
  183. package/lib/runtime/ToBinaryRuntimeModule.js +9 -0
  184. package/lib/schemes/HttpUriPlugin.js +22 -5
  185. package/lib/serialization/FileMiddleware.js +15 -2
  186. package/lib/serialization/ObjectMiddleware.js +138 -106
  187. package/lib/sharing/ConsumeSharedPlugin.js +12 -0
  188. package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -0
  189. package/lib/sharing/ShareRuntimeModule.js +9 -0
  190. package/lib/sharing/declaredShared.js +47 -0
  191. package/lib/stats/DefaultStatsFactoryPlugin.js +3 -1
  192. package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
  193. package/lib/util/ArrayQueue.js +3 -3
  194. package/lib/util/SourceProcessor.js +76 -69
  195. package/lib/util/URLAbsoluteSpecifier.js +3 -1
  196. package/lib/util/async.js +292 -0
  197. package/lib/util/buildDiagnostics.js +69 -0
  198. package/lib/util/conventions.js +5 -1
  199. package/lib/util/fs.js +27 -1
  200. package/lib/util/handlerKeys.js +40 -0
  201. package/lib/util/identifier.js +20 -0
  202. package/lib/util/internalSerializables.js +6 -0
  203. package/lib/util/registerExternalSerializer.js +6 -45
  204. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +9 -0
  205. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -0
  206. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +9 -0
  207. package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
  208. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
  209. package/package.json +22 -16
  210. package/schemas/WebpackOptions.check.js +1 -1
  211. package/schemas/WebpackOptions.json +388 -76
  212. package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
  213. package/schemas/plugins/ManifestPlugin.check.js +1 -1
  214. package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
  215. package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
  216. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
  217. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  218. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  219. package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
  220. package/schemas/plugins/dll/DllReferencePlugin.check.js +1 -1
  221. package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -1
  222. package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
  223. package/types.d.ts +1440 -331
  224. package/lib/dependencies/ExportBindingInitFragment.js +0 -191
  225. package/lib/errors/EntrypointOverlapWarning.js +0 -45
  226. package/lib/performance/EntrypointOverlapPlugin.js +0 -122
@@ -20,6 +20,7 @@ const {
20
20
  evaluateToString,
21
21
  toConstantDependency
22
22
  } = require("./javascript/JavascriptParserHelpers");
23
+ const { getBuildDiagnostics } = require("./util/buildDiagnostics");
23
24
  const createHash = require("./util/createHash");
24
25
  const createHooksRegistry = require("./util/createHooksRegistry");
25
26
 
@@ -92,8 +93,10 @@ class RuntimeValue {
92
93
  const buildInfo = /** @type {BuildInfo} */ (parser.state.module.buildInfo);
93
94
  if (this.options === true) {
94
95
  buildInfo.cacheable = false;
96
+ const diagnostics = getBuildDiagnostics(buildInfo);
95
97
  const reasons =
96
- buildInfo.notCacheableReasons || (buildInfo.notCacheableReasons = []);
98
+ diagnostics.notCacheableReasons ||
99
+ (diagnostics.notCacheableReasons = []);
97
100
  const reason = `DefinePlugin runtime value ${key}`;
98
101
  if (!reasons.includes(reason)) reasons.push(reason);
99
102
  } else {
@@ -375,7 +378,7 @@ const PLUGIN_NAME = "DefinePlugin";
375
378
  const VALUE_DEP_PREFIX = `webpack/${PLUGIN_NAME} `;
376
379
  const VALUE_DEP_MAIN = `webpack/${PLUGIN_NAME}_hash`;
377
380
 
378
- // Keys webpack injects itself are not the user's to remove, so `performance.unusedDefines`
381
+ // Keys webpack injects itself are not the user's to remove, so `performance.unusedConfig`
379
382
  // never sees them.
380
383
  /** @type {WeakSet<DefinePlugin>} */
381
384
  const INTERNAL_PLUGINS = new WeakSet();
@@ -721,11 +724,11 @@ class DefinePlugin {
721
724
  (compilation, { normalModuleFactory }) => {
722
725
  const definitions = this.definitions;
723
726
  const { performance } = compilation.options;
724
- // Only `performance.unusedDefines` reads these, so a build without it
727
+ // Only `performance.unusedConfig` reads these, so a build without it
725
728
  // collects nothing.
726
729
  const collectDeclared =
727
730
  performance !== false &&
728
- performance.unusedDefines === true &&
731
+ performance.unusedConfig === true &&
729
732
  !INTERNAL_PLUGINS.has(this);
730
733
  /** @type {Set<string> | undefined} */
731
734
  let declaredKeys;
@@ -1218,13 +1221,26 @@ class DefinePlugin {
1218
1221
  }
1219
1222
  return -1;
1220
1223
  };
1224
+ // Cut the chain at the undefined member, so a read after it still
1225
+ // throws; an optional link there short-circuits the whole chain.
1221
1226
  parser.hooks.expressionMemberChain
1222
1227
  .for(chainRoot)
1223
- .tap(PLUGIN_NAME, (expr, members) => {
1228
+ .tap(PLUGIN_NAME, (expr, members, membersOptionals) => {
1224
1229
  const deps = [key];
1225
- if (findUndefinedMemberAccess(members, deps) === -1) return;
1230
+ const undefinedIndex = findUndefinedMemberAccess(members, deps);
1231
+ if (undefinedIndex === -1) return;
1226
1232
  for (const dep of deps) addValueDependency(dep);
1227
- return toConstantDependency(parser, "undefined")(expr);
1233
+ return toConstantDependency(
1234
+ parser,
1235
+ "undefined"
1236
+ )(
1237
+ membersOptionals[undefinedIndex + 1]
1238
+ ? expr
1239
+ : dropTrailingMembers(
1240
+ expr,
1241
+ members.length - 1 - undefinedIndex
1242
+ )
1243
+ );
1228
1244
  });
1229
1245
  // Cut the chain at the undefined member, so what follows still
1230
1246
  // throws; an optional link there takes the call, arguments unevaluated.
@@ -1331,7 +1347,7 @@ class DefinePlugin {
1331
1347
  DefinePlugin.getCompilationHooks = createHooksRegistry(createCompilationHooks);
1332
1348
 
1333
1349
  /**
1334
- * Marks an instance as webpack's own, so `performance.unusedDefines` never
1350
+ * Marks an instance as webpack's own, so `performance.unusedConfig` never
1335
1351
  * reports the keys it declares against the user.
1336
1352
  * @param {DefinePlugin} plugin the instance webpack constructed itself
1337
1353
  * @returns {DefinePlugin} the same instance
@@ -6,6 +6,7 @@
6
6
  "use strict";
7
7
 
8
8
  const FileSystemInfo = require("./FileSystemInfo");
9
+ const DotenvFileError = require("./errors/DotenvFileError");
9
10
  const { join } = require("./util/fs");
10
11
 
11
12
  /** @import { DotenvPluginOptions } from "../declarations/WebpackOptions" */
@@ -155,8 +156,8 @@ function expandValue(value, processEnv, runningParsed) {
155
156
  const opMatch = expression.match(opRegex);
156
157
  const splitter = opMatch ? opMatch[0] : null;
157
158
 
158
- const r = expression.split(/** @type {string} */ (splitter));
159
- // const r = splitter ? expression.split(splitter) : [expression];
159
+ // `split(null)` splits on the string "null", cutting up names containing it
160
+ const r = splitter ? expression.split(splitter) : [expression];
160
161
 
161
162
  /** @type {string} */
162
163
  let defaultValue;
@@ -235,16 +236,21 @@ function expand(options) {
235
236
  /**
236
237
  * Format environment variables as DefinePlugin definitions
237
238
  * @param {Env} env environment variables
238
- * @returns {Record<string, string>} formatted definitions
239
+ * @returns {Record<string, string | Env>} formatted definitions
239
240
  */
240
241
  const envToDefinitions = (env) => {
241
- const definitions = /** @type {Record<string, string>} */ ({});
242
+ const definitions = /** @type {Record<string, string | Env>} */ ({});
243
+ // one nested definition rather than a `import.meta.env.<key>` per key: a
244
+ // dotted key would otherwise read back as a nested object, not as the key
245
+ const importMetaEnv = /** @type {Env} */ (Object.create(null));
242
246
 
243
247
  for (const [key, value] of Object.entries(env)) {
244
248
  const defValue = JSON.stringify(value);
249
+ // `process.env` stays flat — it must not shadow the real one at runtime
245
250
  definitions[`process.env.${key}`] = defValue;
246
- definitions[`import.meta.env.${key}`] = defValue;
251
+ importMetaEnv[key] = defValue;
247
252
  }
253
+ definitions["import.meta.env"] = importMetaEnv;
248
254
 
249
255
  return definitions;
250
256
  };
@@ -296,6 +302,8 @@ class DotenvPlugin {
296
302
 
297
303
  /** @type {undefined | InstanceType<Snapshot>} */
298
304
  let snapshot;
305
+ /** @type {undefined | DotenvFileError} */
306
+ let loadError;
299
307
 
300
308
  const cache = compiler.getCache(PLUGIN_NAME);
301
309
  const identifier = JSON.stringify(
@@ -304,16 +312,31 @@ class DotenvPlugin {
304
312
  const itemCache = cache.getItemCache(identifier, null);
305
313
 
306
314
  compiler.hooks.beforeCompile.tapPromise(PLUGIN_NAME, async () => {
307
- const { parsed, snapshot: newSnapshot } = dir
308
- ? await this._loadEnv(compiler, itemCache, dir)
309
- : { parsed: {} };
310
- const env = this._getEnv(prefixes, parsed);
311
-
312
- definePlugin.definitions = envToDefinitions(env || {});
313
- snapshot = newSnapshot;
315
+ loadError = undefined;
316
+ try {
317
+ const { parsed, snapshot: newSnapshot } = dir
318
+ ? await this._loadEnv(compiler, itemCache, dir)
319
+ : { parsed: {} };
320
+ const env = this._getEnv(prefixes, parsed);
321
+
322
+ definePlugin.definitions = envToDefinitions(env || {});
323
+ snapshot = newSnapshot;
324
+ } catch (err) {
325
+ // reported on the compilation so watch mode recovers when it is fixed
326
+ if (!(err instanceof DotenvFileError)) throw err;
327
+ loadError = err;
328
+ definePlugin.definitions = envToDefinitions({});
329
+ snapshot = undefined;
330
+ }
314
331
  });
315
332
 
316
333
  compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
334
+ if (loadError) {
335
+ compilation.errors.push(loadError);
336
+ compilation.fileDependencies.add(
337
+ /** @type {string} */ (loadError.file)
338
+ );
339
+ }
317
340
  if (snapshot) {
318
341
  compilation.fileDependencies.addAll(snapshot.getFileIterable());
319
342
  compilation.missingDependencies.addAll(snapshot.getMissingIterable());
@@ -369,7 +392,12 @@ class DotenvPlugin {
369
392
  fileDependencies.push(filePath);
370
393
  return content;
371
394
  },
372
- () => {
395
+ (err) => {
396
+ const code = /** @type {NodeJS.ErrnoException} */ (err).code;
397
+ // only an absent file is normal; anything else is a real fault
398
+ if (code !== "ENOENT" && code !== "ENOTDIR") {
399
+ throw new DotenvFileError(filePath, err);
400
+ }
373
401
  // File doesn't exist, add to missingDependencies (this is normal)
374
402
  missingDependencies.push(filePath);
375
403
  return "";
@@ -29,6 +29,7 @@ const { coreModules } = require("./node/nodeBuiltins");
29
29
  const createHash = require("./util/createHash");
30
30
  const createHooksRegistry = require("./util/createHooksRegistry");
31
31
  const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");
32
+ const { toJsStringLiteral } = require("./util/identifier");
32
33
  const makeSerializable = require("./util/makeSerializable");
33
34
  const memoize = require("./util/memoize");
34
35
  const { propertyAccess } = require("./util/property");
@@ -110,6 +111,7 @@ const getEnvironmentNotSupportAsyncWarning = memoize(() =>
110
111
  * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
111
112
  * @property {ReadOnlyRuntimeRequirements=} runtimeRequirements
112
113
  * @property {[string, string][]=} specifiers
114
+ * @property {string=} externalReexport native reexport source and attributes
113
115
  */
114
116
 
115
117
  /** @typedef {true | [string, string][]} Imported */
@@ -417,6 +419,18 @@ const importAssertionReplacer = (key, value) => {
417
419
  return value;
418
420
  };
419
421
 
422
+ /**
423
+ * Renders the import attributes clause of a static import or reexport.
424
+ * @param {ImportDependencyMeta | undefined} dependencyMeta import metadata
425
+ * @returns {string} static import attributes
426
+ */
427
+ const getImportAttributes = (dependencyMeta) =>
428
+ dependencyMeta && dependencyMeta.attributes
429
+ ? dependencyMeta.attributes._isLegacyAssert
430
+ ? ` assert ${JSON.stringify(dependencyMeta.attributes, importAssertionReplacer)}`
431
+ : ` with ${JSON.stringify(dependencyMeta.attributes)}`
432
+ : "";
433
+
420
434
  /**
421
435
  * Represents ModuleExternalInitFragment.
422
436
  * @extends {InitFragment<GenerateContext>}
@@ -503,33 +517,25 @@ class ModuleExternalInitFragment extends InitFragment {
503
517
  _request: request,
504
518
  _identifier: identifier
505
519
  } = this;
506
- const attributes =
507
- dependencyMeta && dependencyMeta.attributes
508
- ? dependencyMeta.attributes._isLegacyAssert
509
- ? ` assert ${JSON.stringify(
510
- dependencyMeta.attributes,
511
- importAssertionReplacer
512
- )}`
513
- : ` with ${JSON.stringify(dependencyMeta.attributes)}`
514
- : "";
520
+ const attributes = getImportAttributes(dependencyMeta);
515
521
  const phase = dependencyMeta && dependencyMeta.phase;
516
522
  checkPhaseIsSupported(phase, context.runtimeTemplate);
517
523
  let content = "";
518
524
  if (ImportPhaseUtils.isSource(phase) && imported === true) {
519
525
  // There is no `import source * as ns` form: the source phase binds one
520
526
  // identifier, so it stands in for the namespace the other branches build.
521
- content = `import source ${identifier} from ${JSON.stringify(
527
+ content = `import source ${identifier} from ${toJsStringLiteral(
522
528
  request
523
529
  )}${attributes};\n`;
524
530
  } else if (imported === true) {
525
531
  // namespace
526
532
  const phaseKeyword = ImportPhaseUtils.isDefer(phase) ? "defer " : "";
527
- content = `import ${phaseKeyword}* as ${identifier} from ${JSON.stringify(
533
+ content = `import ${phaseKeyword}* as ${identifier} from ${toJsStringLiteral(
528
534
  request
529
535
  )}${attributes};\n`;
530
536
  } else if (imported.length === 0) {
531
537
  // just import, no use
532
- content = `import ${JSON.stringify(request)}${attributes};\n`;
538
+ content = `import ${toJsStringLiteral(request)}${attributes};\n`;
533
539
  } else if (
534
540
  ImportPhaseUtils.isSource(phase) &&
535
541
  imported.length === 1 &&
@@ -537,7 +543,7 @@ class ModuleExternalInitFragment extends InitFragment {
537
543
  ) {
538
544
  // `import source x from "…"` — the source-phase form binds the source
539
545
  // object directly to a single identifier (no namespace, no destructuring).
540
- content = `import source ${imported[0][1]} from ${JSON.stringify(
546
+ content = `import source ${imported[0][1]} from ${toJsStringLiteral(
541
547
  request
542
548
  )}${attributes};\n`;
543
549
  } else {
@@ -548,7 +554,7 @@ class ModuleExternalInitFragment extends InitFragment {
548
554
  }
549
555
  return name;
550
556
  })
551
- .join(", ")} } from ${JSON.stringify(request)}${attributes};\n`;
557
+ .join(", ")} } from ${toJsStringLiteral(request)}${attributes};\n`;
552
558
  }
553
559
  return content;
554
560
  }
@@ -738,6 +744,12 @@ const getSourceForModuleExternal = (
738
744
  }
739
745
  return {
740
746
  expression,
747
+ externalReexport:
748
+ moduleAndSpecifiers.length === 1 &&
749
+ !ImportPhaseUtils.isDefer(phase) &&
750
+ !ImportPhaseUtils.isSource(phase)
751
+ ? `from ${toJsStringLiteral(moduleAndSpecifiers[0])}${getImportAttributes(dependencyMeta)}`
752
+ : undefined,
741
753
  init: moduleRemapping
742
754
  ? `${runtimeTemplate.renderConst()} x = ${runtimeTemplate.basicFunction(
743
755
  "y",
@@ -1238,6 +1250,17 @@ class ExternalModule extends Module {
1238
1250
  return this._resolveExternalType(this.externalType) !== "module";
1239
1251
  }
1240
1252
 
1253
+ /**
1254
+ * The request this external resolves to for its own type, with the record form
1255
+ * narrowed to its entry. An array is a module specifier plus a property path.
1256
+ * @returns {string | string[] | undefined} the resolved request
1257
+ */
1258
+ getResolvedRequest() {
1259
+ return /** @type {string | string[] | undefined} */ (
1260
+ this._getRequestAndExternalType().request
1261
+ );
1262
+ }
1263
+
1241
1264
  /**
1242
1265
  * Get request and external type.
1243
1266
  * @private
@@ -1535,6 +1558,10 @@ class ExternalModule extends Module {
1535
1558
  data = new Map();
1536
1559
  data.set("chunkInitFragments", sourceData.chunkInitFragments);
1537
1560
  }
1561
+ if (sourceData.externalReexport) {
1562
+ if (!data) data = new Map();
1563
+ data.set("externalReexport", sourceData.externalReexport);
1564
+ }
1538
1565
 
1539
1566
  /** @type {Sources} */
1540
1567
  const sources = new Map();
@@ -8,11 +8,11 @@
8
8
  const nodeModule = require("module");
9
9
  const { isAbsolute } = require("path");
10
10
  const { create: createResolver } = require("enhanced-resolve");
11
- const asyncLib = require("neo-async");
12
11
  const { DEFAULTS } = require("./config/defaults");
13
12
  const { collectCjsRequireSpecifiers } = require("./javascript/syntax");
14
13
  const AsyncQueue = require("./util/AsyncQueue");
15
14
  const StackedCacheMap = require("./util/StackedCacheMap");
15
+ const asyncLib = require("./util/async");
16
16
  const createHash = require("./util/createHash");
17
17
  const { dirname, join, lstatReadlinkAbsolute, relative } = require("./util/fs");
18
18
  const makeSerializable = require("./util/makeSerializable");
@@ -1884,10 +1884,13 @@ class FileSystemInfo {
1884
1884
  * Resolves build dependencies.
1885
1885
  * @param {string} context context directory
1886
1886
  * @param {Iterable<string>} deps dependencies
1887
+ * @param {Iterable<string> | undefined} optionalDeps optional dependencies that may be missing
1887
1888
  * @param {(err?: Error | null, resolveBuildDependenciesResult?: ResolveBuildDependenciesResult) => void} callback callback function
1888
1889
  * @returns {void}
1889
1890
  */
1890
- resolveBuildDependencies(context, deps, callback) {
1891
+ resolveBuildDependencies(context, deps, optionalDeps, callback) {
1892
+ /** @type {Set<string>} */
1893
+ const optional = new Set(optionalDeps);
1891
1894
  const { resolveContext, resolveEsm, resolveCjs, resolveCjsAsChild } =
1892
1895
  this._createBuildDependenciesResolvers();
1893
1896
 
@@ -1979,7 +1982,7 @@ class FileSystemInfo {
1979
1982
  type: RBDT_RESOLVE_INITIAL,
1980
1983
  context,
1981
1984
  path: dep,
1982
- expected: undefined,
1985
+ expected: optional.has(dep) ? false : undefined,
1983
1986
  issuer: undefined
1984
1987
  })
1985
1988
  ),
@@ -2005,6 +2008,7 @@ class FileSystemInfo {
2005
2008
  if (err) {
2006
2009
  if (expected === false) {
2007
2010
  resolveResults.set(key, false);
2011
+ resolveMissing.add(path);
2008
2012
  return callback();
2009
2013
  }
2010
2014
  invalidResolveResults.add(key);
@@ -2060,6 +2064,7 @@ class FileSystemInfo {
2060
2064
  if (err) {
2061
2065
  if (expected === false) {
2062
2066
  resolveResults.set(key, false);
2067
+ resolveMissing.add(path);
2063
2068
  return callback();
2064
2069
  }
2065
2070
  invalidResolveResults.add(key);
@@ -2514,20 +2519,18 @@ class FileSystemInfo {
2514
2519
  },
2515
2520
  /**
2516
2521
  * Processes the provided err.
2517
- * @param {Error | typeof INVALID=} err error or invalid flag
2522
+ * @param {(Error | typeof INVALID | null)=} err error or invalid flag
2518
2523
  * @returns {void}
2519
2524
  */
2520
- /** @type {import("neo-async").ErrorCallback<Error | typeof INVALID>} */ (
2521
- (err) => {
2522
- if (err === INVALID) {
2523
- return callback(null, false);
2524
- }
2525
- if (err) {
2526
- return callback(err);
2527
- }
2528
- return callback(null, true);
2525
+ (err) => {
2526
+ if (err === INVALID) {
2527
+ return callback(null, false);
2529
2528
  }
2530
- )
2529
+ if (err) {
2530
+ return callback(err);
2531
+ }
2532
+ return callback(null, true);
2533
+ }
2531
2534
  );
2532
2535
  }
2533
2536
 
@@ -5,8 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const asyncLib = require("neo-async");
9
8
  const Queue = require("./util/Queue");
9
+ const asyncLib = require("./util/async");
10
10
  const { compareModulesByIdentifier } = require("./util/comparators");
11
11
  const createHash = require("./util/createHash");
12
12
 
@@ -30,15 +30,40 @@ const PLUGIN_LOGGER_NAME = `webpack.${PLUGIN_NAME}`;
30
30
  /** @typedef {{ etag: string, data: InstanceType<RestoreProvidedData> }} MemCacheEntry */
31
31
 
32
32
  /**
33
+ * Cache key fragment for what changes provided exports without changing the
34
+ * module's source: still-lazy barrel requests and DefinePlugin value versions.
33
35
  * @param {Module} module the module
34
36
  * @param {LazyBarrelController} lazyBarrelController the compilation's lazy barrel controller
35
37
  * @param {HashFunction} hashFunction hash function for long keys
36
- * @returns {string} the hash
38
+ * @returns {string} etag for provided-exports mem/persistent cache, "" when neither applies
37
39
  */
38
- const getLazyRequestsHash = (module, lazyBarrelController, hashFunction) => {
39
- const lazyKeys = lazyBarrelController.getLazyRequests(module);
40
- if (!lazyKeys) return "";
41
- const joined = [...lazyKeys].join("|");
40
+ const getProvidedExportsEtag = (module, lazyBarrelController, hashFunction) => {
41
+ const lazyRequests = lazyBarrelController.getLazyRequests(module);
42
+ const buildInfo = /** @type {BuildInfo | undefined} */ (module.buildInfo);
43
+ const valueDependencies = buildInfo && buildInfo.valueDependencies;
44
+ const hasValueDependencies =
45
+ valueDependencies !== undefined && valueDependencies.size > 0;
46
+ if (!lazyRequests && !hasValueDependencies) return "";
47
+ /** @type {(string | string[] | undefined)[][]} */
48
+ const valueEntries = [];
49
+ if (hasValueDependencies) {
50
+ const versions =
51
+ /** @type {NonNullable<BuildInfo["valueDependencies"]>} */
52
+ (valueDependencies);
53
+ for (const key of [...versions.keys()].sort()) {
54
+ const value = versions.get(key);
55
+ // An absent version serializes as null, distinct from both other shapes
56
+ valueEntries.push([
57
+ key,
58
+ value instanceof Set ? [...value].sort() : value
59
+ ]);
60
+ }
61
+ }
62
+ // JSON, so a separator inside a request or a version cannot forge another entry
63
+ const joined = JSON.stringify([
64
+ lazyRequests ? [...lazyRequests] : [],
65
+ valueEntries
66
+ ]);
42
67
  if (joined.length < 100) return joined;
43
68
  const hash = createHash(hashFunction);
44
69
  hash.update(joined);
@@ -78,9 +103,7 @@ class FlagDependencyExportsPlugin {
78
103
  // Step 1: Try to restore cached provided export info from cache
79
104
  logger.time("restore cached provided exports");
80
105
  asyncLib.each(
81
- /** @type {import("neo-async").IterableCollection<Module>} */ (
82
- /** @type {unknown} */ (modules)
83
- ),
106
+ modules,
84
107
  (module, callback) => {
85
108
  const exportsInfo = moduleGraph.getExportsInfo(module);
86
109
  // If the module doesn't have an exportsType, it's a module
@@ -109,7 +132,7 @@ class FlagDependencyExportsPlugin {
109
132
  const memCache = moduleMemCaches && moduleMemCaches.get(module);
110
133
  /** @type {MemCacheEntry | undefined} */
111
134
  const memCacheEntry = memCache && memCache.get(this);
112
- const hash = getLazyRequestsHash(
135
+ const etag = getProvidedExportsEtag(
113
136
  module,
114
137
  lazyBarrelController,
115
138
  hashFunction
@@ -118,7 +141,7 @@ class FlagDependencyExportsPlugin {
118
141
  // detection cannot invalidate the mem cache when the un-lazied
119
142
  // connections are unsafe-cached (they are skipped when comparing
120
143
  // references)
121
- if (memCacheEntry !== undefined && memCacheEntry.etag === hash) {
144
+ if (memCacheEntry !== undefined && memCacheEntry.etag === etag) {
122
145
  statRestoredFromMemCache++;
123
146
  exportsInfo.restoreProvided(memCacheEntry.data);
124
147
  return callback();
@@ -128,7 +151,7 @@ class FlagDependencyExportsPlugin {
128
151
  );
129
152
  cache.get(
130
153
  module.identifier(),
131
- hash ? `${buildHash}|${hash}` : buildHash,
154
+ etag ? `${buildHash}|${etag}` : buildHash,
132
155
  (err, result) => {
133
156
  if (err) return callback(err);
134
157
 
@@ -351,12 +374,13 @@ class FlagDependencyExportsPlugin {
351
374
  changed = true;
352
375
  }
353
376
 
354
- if (
355
- inlined !== undefined &&
356
- exportInfo.canInlineProvide === undefined
357
- ) {
358
- exportInfo.canInlineProvide = inlined;
359
- changed = true;
377
+ if (inlined !== undefined) {
378
+ const prev = exportInfo.canInlineProvide;
379
+ // Watch rebuilds keep ExportInfo; refresh when the constant changes
380
+ if (prev === undefined || !prev.equals(inlined)) {
381
+ exportInfo.canInlineProvide = inlined;
382
+ changed = true;
383
+ }
360
384
  }
361
385
 
362
386
  if (terminalBinding && !exportInfo.terminalBinding) {
@@ -513,7 +537,7 @@ class FlagDependencyExportsPlugin {
513
537
  .getRestoreProvidedData();
514
538
  const memCache =
515
539
  moduleMemCaches && moduleMemCaches.get(module);
516
- const hash = getLazyRequestsHash(
540
+ const etag = getProvidedExportsEtag(
517
541
  module,
518
542
  lazyBarrelController,
519
543
  hashFunction
@@ -521,7 +545,7 @@ class FlagDependencyExportsPlugin {
521
545
  if (memCache) {
522
546
  /** @type {MemCacheEntry} */
523
547
  const entry = {
524
- etag: hash,
548
+ etag,
525
549
  data: cachedData
526
550
  };
527
551
  memCache.set(this, entry);
@@ -531,7 +555,7 @@ class FlagDependencyExportsPlugin {
531
555
  );
532
556
  cache.store(
533
557
  module.identifier(),
534
- hash ? `${buildHash}|${hash}` : buildHash,
558
+ etag ? `${buildHash}|${etag}` : buildHash,
535
559
  cachedData,
536
560
  callback
537
561
  );
@@ -345,10 +345,16 @@ class FlagDependencyUsagePlugin {
345
345
  if (oldItem === undefined || Array.isArray(oldItem)) {
346
346
  exportsMap.set(key, item);
347
347
  } else {
348
+ // An unset flag means "allowed", so merge on `!== false`:
349
+ // `undefined && false` reads back as allowed.
348
350
  exportsMap.set(key, {
349
351
  name: item.name,
350
- canMangle: item.canMangle && oldItem.canMangle,
351
- canInline: item.canInline && oldItem.canInline
352
+ canMangle:
353
+ item.canMangle !== false &&
354
+ oldItem.canMangle !== false,
355
+ canInline:
356
+ item.canInline !== false &&
357
+ oldItem.canInline !== false
352
358
  });
353
359
  }
354
360
  }
@@ -17,7 +17,11 @@ const {
17
17
  } = require("./ModuleTypeConstants");
18
18
  const NormalModule = require("./NormalModule");
19
19
  const RuntimeGlobals = require("./RuntimeGlobals");
20
- const { chunkHasCss } = require("./css/CssModulesPlugin");
20
+ const { getPresentKinds } = require("./TemplatedPathPlugin");
21
+ const {
22
+ chunkHasCss,
23
+ getChunkFilenameTemplate: getCssChunkFilenameTemplate
24
+ } = require("./css/CssModulesPlugin");
21
25
  const ConstDependency = require("./dependencies/ConstDependency");
22
26
  const ImportMetaHotAcceptDependency = require("./dependencies/ImportMetaHotAcceptDependency");
23
27
  const ImportMetaHotDeclineDependency = require("./dependencies/ImportMetaHotDeclineDependency");
@@ -72,6 +76,22 @@ const {
72
76
  /** @typedef {{ updatedChunkIds: ChunkIds, removedChunkIds: ChunkIds, removedModules: ModuleSet, forceLoadChunkIds: ChunkIds, filename: string, assetInfo: AssetInfo }} HotUpdateMainContentByRuntimeItem */
73
77
  /** @typedef {Map<string, HotUpdateMainContentByRuntimeItem>} HotUpdateMainContentByRuntime */
74
78
 
79
+ /**
80
+ * Whether a filename template reads any hash, so the name it gives a chunk can move
81
+ * between two builds.
82
+ * @param {string} template the filename template
83
+ * @returns {boolean} true when a hash is part of the name
84
+ */
85
+ const templateReadsHash = (template) => {
86
+ const kinds = getPresentKinds(template);
87
+ return (
88
+ kinds.has("hash") ||
89
+ kinds.has("fullhash") ||
90
+ kinds.has("chunkhash") ||
91
+ kinds.has("contenthash")
92
+ );
93
+ };
94
+
75
95
  const PLUGIN_NAME = "HotModuleReplacementPlugin";
76
96
 
77
97
  class HotModuleReplacementPlugin {
@@ -856,7 +876,7 @@ To fix this, make sure to include [runtime] in the output.hotUpdateMainFilename
856
876
  assetInfo
857
877
  }
858
878
  ] of hotUpdateMainContentByFilename) {
859
- /** @type {{ c: ChunkId[], r: ChunkId[], m: ModuleId[], f?: ChunkId[], css?: { r: ChunkId[] } }} */
879
+ /** @type {{ c: ChunkId[], r: ChunkId[], m: ModuleId[], f?: ChunkId[], css?: { r: ChunkId[], n?: Record<ChunkId, string> } }} */
860
880
  const hotUpdateMainJson = {
861
881
  c: [...updatedChunkIds],
862
882
  r: [...removedChunkIds],
@@ -882,21 +902,47 @@ To fix this, make sure to include [runtime] in the output.hotUpdateMainFilename
882
902
  // Build CSS removed chunks list (chunks in updatedChunkIds that no longer have CSS)
883
903
  /** @type {ChunkId[]} */
884
904
  const cssRemovedChunkIds = [];
905
+ /** @type {Record<ChunkId, string> | undefined} */
906
+ let cssChunkNames;
885
907
  if (compilation.options.experiments.css) {
886
908
  for (const chunkId of updatedChunkIds) {
887
909
  for (const /** @type {Chunk} */ chunk of compilation.chunks) {
888
- if (chunk.id === chunkId) {
889
- if (!chunkHasCss(chunk, chunkGraph)) {
890
- cssRemovedChunkIds.push(chunkId);
891
- }
910
+ if (chunk.id !== chunkId) continue;
911
+ if (!chunkHasCss(chunk, chunkGraph)) {
912
+ cssRemovedChunkIds.push(chunkId);
892
913
  break;
893
914
  }
915
+ // The runtime's name map is refreshed only by the update chunk
916
+ // itself, so a name that moved with the content travels here.
917
+ const template = getCssChunkFilenameTemplate(
918
+ chunk,
919
+ compilation.outputOptions
920
+ );
921
+ if (
922
+ typeof template !== "string" ||
923
+ templateReadsHash(template)
924
+ ) {
925
+ if (cssChunkNames === undefined) cssChunkNames = {};
926
+ cssChunkNames[chunkId] = compilation.getPath(template, {
927
+ hash: compilation.hash,
928
+ runtime: chunk.runtime,
929
+ chunk,
930
+ contentHashType: "css"
931
+ });
932
+ }
933
+ break;
894
934
  }
895
935
  }
896
936
  }
897
937
 
898
- if (cssRemovedChunkIds.length > 0) {
938
+ if (
939
+ cssRemovedChunkIds.length > 0 ||
940
+ cssChunkNames !== undefined
941
+ ) {
899
942
  hotUpdateMainJson.css = { r: cssRemovedChunkIds };
943
+ if (cssChunkNames !== undefined) {
944
+ hotUpdateMainJson.css.n = cssChunkNames;
945
+ }
900
946
  }
901
947
 
902
948
  const source = new RawSource(
@@ -11,6 +11,7 @@ const {
11
11
  JAVASCRIPT_MODULE_TYPE_ESM
12
12
  } = require("./ModuleTypeConstants");
13
13
  const { getInnerGraphUtils } = require("./optimize/InnerGraph");
14
+ const { recordOptimizationBailout } = require("./util/buildDiagnostics");
14
15
 
15
16
  /** @import Compiler from "./Compiler" */
16
17
  /** @import { BuildInfo } from "./Module" */
@@ -73,9 +74,10 @@ class JavascriptMetaInfoPlugin {
73
74
  const wasEnabled = innerGraph.isEnabled(parser.state);
74
75
  innerGraph.bailout(parser.state);
75
76
  if (wasEnabled) {
76
- compilation.moduleGraph
77
- .getOptimizationBailout(parser.state.module)
78
- .push("Inner graph bailout: eval()");
77
+ recordOptimizationBailout(
78
+ buildInfo,
79
+ "Inner graph bailout: eval()"
80
+ );
79
81
  }
80
82
  }
81
83
  });