webpack 5.102.1 → 5.104.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 (220) hide show
  1. package/README.md +121 -134
  2. package/hot/dev-server.js +18 -3
  3. package/hot/emitter-event-target.js +7 -0
  4. package/hot/lazy-compilation-node.js +45 -29
  5. package/hot/lazy-compilation-universal.js +18 -0
  6. package/hot/lazy-compilation-web.js +15 -5
  7. package/hot/load-http.js +7 -0
  8. package/hot/only-dev-server.js +19 -4
  9. package/lib/APIPlugin.js +6 -0
  10. package/lib/Chunk.js +1 -1
  11. package/lib/ChunkGraph.js +9 -7
  12. package/lib/ChunkGroup.js +8 -5
  13. package/lib/CleanPlugin.js +6 -3
  14. package/lib/CodeGenerationResults.js +2 -1
  15. package/lib/CompatibilityPlugin.js +28 -2
  16. package/lib/Compilation.js +58 -21
  17. package/lib/Compiler.js +3 -3
  18. package/lib/ConcatenationScope.js +0 -15
  19. package/lib/ContextModule.js +6 -3
  20. package/lib/ContextModuleFactory.js +6 -4
  21. package/lib/CssModule.js +6 -1
  22. package/lib/DefinePlugin.js +45 -14
  23. package/lib/DelegatedModule.js +7 -4
  24. package/lib/Dependency.js +8 -1
  25. package/lib/DependencyTemplate.js +1 -0
  26. package/lib/DllModule.js +6 -3
  27. package/lib/DotenvPlugin.js +462 -0
  28. package/lib/EnvironmentPlugin.js +19 -16
  29. package/lib/EvalSourceMapDevToolPlugin.js +16 -0
  30. package/lib/ExportsInfo.js +6 -2
  31. package/lib/ExternalModule.js +28 -35
  32. package/lib/ExternalModuleFactoryPlugin.js +11 -9
  33. package/lib/ExternalsPlugin.js +2 -1
  34. package/lib/FileSystemInfo.js +1 -1
  35. package/lib/Generator.js +10 -7
  36. package/lib/HookWebpackError.js +33 -4
  37. package/lib/HotModuleReplacementPlugin.js +22 -0
  38. package/lib/ManifestPlugin.js +235 -0
  39. package/lib/Module.js +27 -15
  40. package/lib/ModuleBuildError.js +1 -1
  41. package/lib/ModuleError.js +1 -1
  42. package/lib/ModuleFilenameHelpers.js +1 -1
  43. package/lib/ModuleGraph.js +29 -13
  44. package/lib/ModuleGraphConnection.js +2 -2
  45. package/lib/ModuleSourceTypeConstants.js +189 -0
  46. package/lib/ModuleTypeConstants.js +1 -4
  47. package/lib/ModuleWarning.js +1 -1
  48. package/lib/MultiCompiler.js +1 -1
  49. package/lib/NodeStuffPlugin.js +424 -116
  50. package/lib/NormalModule.js +23 -20
  51. package/lib/NormalModuleFactory.js +7 -10
  52. package/lib/Parser.js +1 -1
  53. package/lib/RawModule.js +7 -4
  54. package/lib/RuntimeGlobals.js +22 -4
  55. package/lib/RuntimeModule.js +1 -1
  56. package/lib/RuntimePlugin.js +27 -6
  57. package/lib/RuntimeTemplate.js +120 -57
  58. package/lib/SourceMapDevToolPlugin.js +26 -1
  59. package/lib/Template.js +17 -6
  60. package/lib/TemplatedPathPlugin.js +5 -6
  61. package/lib/WebpackError.js +0 -1
  62. package/lib/WebpackOptionsApply.js +67 -15
  63. package/lib/asset/AssetBytesGenerator.js +16 -12
  64. package/lib/asset/AssetGenerator.js +31 -26
  65. package/lib/asset/AssetSourceGenerator.js +16 -12
  66. package/lib/asset/RawDataUrlModule.js +6 -3
  67. package/lib/buildChunkGraph.js +4 -2
  68. package/lib/cache/PackFileCacheStrategy.js +6 -5
  69. package/lib/cli.js +2 -43
  70. package/lib/config/browserslistTargetHandler.js +24 -0
  71. package/lib/config/defaults.js +226 -61
  72. package/lib/config/normalization.js +4 -3
  73. package/lib/config/target.js +11 -0
  74. package/lib/container/ContainerEntryModule.js +6 -3
  75. package/lib/container/FallbackModule.js +6 -3
  76. package/lib/container/RemoteModule.js +1 -3
  77. package/lib/css/CssGenerator.js +304 -76
  78. package/lib/css/CssLoadingRuntimeModule.js +14 -4
  79. package/lib/css/CssMergeStyleSheetsRuntimeModule.js +56 -0
  80. package/lib/css/CssModulesPlugin.js +72 -67
  81. package/lib/css/CssParser.js +1726 -732
  82. package/lib/css/walkCssTokens.js +128 -11
  83. package/lib/dependencies/CachedConstDependency.js +24 -10
  84. package/lib/dependencies/CommonJsImportsParserPlugin.js +0 -9
  85. package/lib/dependencies/CommonJsPlugin.js +12 -0
  86. package/lib/dependencies/CommonJsRequireContextDependency.js +1 -1
  87. package/lib/dependencies/ContextDependencyHelpers.js +2 -2
  88. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +3 -1
  89. package/lib/dependencies/CssIcssExportDependency.js +389 -12
  90. package/lib/dependencies/CssIcssImportDependency.js +114 -51
  91. package/lib/dependencies/CssIcssSymbolDependency.js +31 -33
  92. package/lib/dependencies/CssImportDependency.js +17 -6
  93. package/lib/dependencies/CssUrlDependency.js +3 -2
  94. package/lib/dependencies/DynamicExports.js +7 -7
  95. package/lib/dependencies/ExternalModuleDependency.js +7 -4
  96. package/lib/dependencies/ExternalModuleInitFragment.js +3 -2
  97. package/lib/dependencies/ExternalModuleInitFragmentDependency.js +96 -0
  98. package/lib/dependencies/HarmonyAcceptDependency.js +6 -1
  99. package/lib/dependencies/HarmonyAcceptImportDependency.js +2 -1
  100. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +12 -1
  101. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +35 -23
  102. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +13 -9
  103. package/lib/dependencies/HarmonyExports.js +4 -4
  104. package/lib/dependencies/HarmonyImportDependency.js +28 -27
  105. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +28 -69
  106. package/lib/dependencies/HarmonyImportSideEffectDependency.js +4 -3
  107. package/lib/dependencies/HarmonyImportSpecifierDependency.js +10 -8
  108. package/lib/dependencies/ImportDependency.js +8 -2
  109. package/lib/dependencies/ImportEagerDependency.js +6 -3
  110. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
  111. package/lib/dependencies/ImportMetaPlugin.js +154 -9
  112. package/lib/dependencies/ImportParserPlugin.js +21 -23
  113. package/lib/dependencies/ImportPhase.js +121 -0
  114. package/lib/dependencies/ImportWeakDependency.js +6 -3
  115. package/lib/dependencies/LocalModulesHelpers.js +3 -3
  116. package/lib/dependencies/ModuleDependency.js +5 -1
  117. package/lib/dependencies/ModuleHotAcceptDependency.js +1 -1
  118. package/lib/dependencies/WorkerPlugin.js +2 -2
  119. package/lib/dependencies/getFunctionExpression.js +1 -1
  120. package/lib/esm/ExportWebpackRequireRuntimeModule.js +1 -8
  121. package/lib/esm/ModuleChunkFormatPlugin.js +5 -4
  122. package/lib/hmr/HotModuleReplacement.runtime.js +2 -1
  123. package/lib/hmr/LazyCompilationPlugin.js +5 -3
  124. package/lib/ids/IdHelpers.js +20 -8
  125. package/lib/index.js +6 -0
  126. package/lib/javascript/ChunkHelpers.js +16 -5
  127. package/lib/javascript/JavascriptGenerator.js +105 -104
  128. package/lib/javascript/JavascriptModulesPlugin.js +80 -37
  129. package/lib/javascript/JavascriptParser.js +161 -44
  130. package/lib/json/JsonGenerator.js +5 -4
  131. package/lib/json/JsonParser.js +9 -2
  132. package/lib/library/AbstractLibraryPlugin.js +1 -1
  133. package/lib/library/AmdLibraryPlugin.js +4 -1
  134. package/lib/library/ExportPropertyLibraryPlugin.js +4 -1
  135. package/lib/library/ModuleLibraryPlugin.js +41 -23
  136. package/lib/library/SystemLibraryPlugin.js +8 -1
  137. package/lib/library/UmdLibraryPlugin.js +2 -2
  138. package/lib/logging/Logger.js +5 -4
  139. package/lib/logging/createConsoleLogger.js +2 -2
  140. package/lib/node/NodeTargetPlugin.js +9 -1
  141. package/lib/node/ReadFileCompileWasmPlugin.js +0 -2
  142. package/lib/optimize/ConcatenatedModule.js +208 -167
  143. package/lib/optimize/ModuleConcatenationPlugin.js +5 -4
  144. package/lib/optimize/SideEffectsFlagPlugin.js +3 -2
  145. package/lib/optimize/SplitChunksPlugin.js +60 -46
  146. package/lib/rules/RuleSetCompiler.js +1 -1
  147. package/lib/runtime/AsyncModuleRuntimeModule.js +28 -18
  148. package/lib/runtime/AutoPublicPathRuntimeModule.js +8 -3
  149. package/lib/runtime/GetChunkFilenameRuntimeModule.js +3 -2
  150. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +89 -55
  151. package/lib/schemes/HttpUriPlugin.js +78 -7
  152. package/lib/serialization/AggregateErrorSerializer.js +1 -2
  153. package/lib/serialization/ObjectMiddleware.js +0 -2
  154. package/lib/serialization/SingleItemMiddleware.js +1 -1
  155. package/lib/sharing/ConsumeSharedModule.js +1 -1
  156. package/lib/sharing/ConsumeSharedPlugin.js +5 -3
  157. package/lib/sharing/ProvideSharedModule.js +1 -1
  158. package/lib/sharing/resolveMatchedConfigs.js +15 -9
  159. package/lib/sharing/utils.js +1 -1
  160. package/lib/stats/DefaultStatsFactoryPlugin.js +8 -5
  161. package/lib/stats/DefaultStatsPresetPlugin.js +1 -1
  162. package/lib/stats/DefaultStatsPrinterPlugin.js +1 -1
  163. package/lib/util/StringXor.js +1 -1
  164. package/lib/util/URLAbsoluteSpecifier.js +2 -2
  165. package/lib/util/binarySearchBounds.js +2 -2
  166. package/lib/util/comparators.js +54 -76
  167. package/lib/util/compileBooleanMatcher.js +78 -6
  168. package/lib/util/createHash.js +20 -199
  169. package/lib/util/deprecation.js +1 -1
  170. package/lib/util/deterministicGrouping.js +6 -3
  171. package/lib/util/fs.js +75 -75
  172. package/lib/util/hash/BatchedHash.js +10 -9
  173. package/lib/util/hash/BulkUpdateHash.js +138 -0
  174. package/lib/util/hash/DebugHash.js +75 -0
  175. package/lib/util/hash/hash-digest.js +216 -0
  176. package/lib/util/identifier.js +82 -17
  177. package/lib/util/internalSerializables.js +2 -6
  178. package/lib/util/runtime.js +3 -3
  179. package/lib/util/source.js +2 -2
  180. package/lib/wasm/EnableWasmLoadingPlugin.js +10 -4
  181. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +3 -2
  182. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +11 -7
  183. package/lib/wasm-sync/WebAssemblyGenerator.js +9 -6
  184. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +11 -6
  185. package/lib/wasm-sync/WebAssemblyModulesPlugin.js +6 -2
  186. package/lib/web/FetchCompileWasmPlugin.js +0 -2
  187. package/lib/webpack.js +85 -82
  188. package/module.d.ts +5 -0
  189. package/package.json +34 -28
  190. package/schemas/WebpackOptions.check.js +1 -1
  191. package/schemas/WebpackOptions.json +160 -101
  192. package/schemas/plugins/{css/CssAutoParserOptions.check.d.ts → ManifestPlugin.check.d.ts} +1 -1
  193. package/schemas/plugins/ManifestPlugin.check.js +6 -0
  194. package/schemas/plugins/ManifestPlugin.json +98 -0
  195. package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
  196. package/schemas/plugins/SourceMapDevToolPlugin.json +16 -3
  197. package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
  198. package/schemas/plugins/container/ContainerReferencePlugin.json +4 -1
  199. package/schemas/plugins/container/ExternalsType.check.js +1 -1
  200. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  201. package/schemas/plugins/container/ModuleFederationPlugin.json +4 -1
  202. package/schemas/plugins/css/CssModuleGeneratorOptions.check.js +1 -1
  203. package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
  204. package/schemas/plugins/css/CssParserOptions.check.js +1 -1
  205. package/schemas/plugins/json/JsonModulesPluginParser.check.js +1 -1
  206. package/types.d.ts +771 -436
  207. package/lib/ModuleSourceTypesConstants.js +0 -123
  208. package/lib/dependencies/CssLocalIdentifierDependency.js +0 -250
  209. package/lib/dependencies/CssSelfLocalIdentifierDependency.js +0 -112
  210. package/schemas/plugins/css/CssAutoGeneratorOptions.check.d.ts +0 -7
  211. package/schemas/plugins/css/CssAutoGeneratorOptions.check.js +0 -6
  212. package/schemas/plugins/css/CssAutoGeneratorOptions.json +0 -3
  213. package/schemas/plugins/css/CssAutoParserOptions.check.js +0 -6
  214. package/schemas/plugins/css/CssAutoParserOptions.json +0 -3
  215. package/schemas/plugins/css/CssGlobalGeneratorOptions.check.d.ts +0 -7
  216. package/schemas/plugins/css/CssGlobalGeneratorOptions.check.js +0 -6
  217. package/schemas/plugins/css/CssGlobalGeneratorOptions.json +0 -3
  218. package/schemas/plugins/css/CssGlobalParserOptions.check.d.ts +0 -7
  219. package/schemas/plugins/css/CssGlobalParserOptions.check.js +0 -6
  220. package/schemas/plugins/css/CssGlobalParserOptions.json +0 -3
package/lib/CssModule.js CHANGED
@@ -30,9 +30,13 @@ class CssModule extends NormalModule {
30
30
  super(options);
31
31
 
32
32
  // Avoid override `layer` for `Module` class, because it is a feature to run module in specific layer
33
+ /** @type {CSSModuleCreateData['cssLayer']} */
33
34
  this.cssLayer = options.cssLayer;
35
+ /** @type {CSSModuleCreateData['supports']} */
34
36
  this.supports = options.supports;
37
+ /** @type {CSSModuleCreateData['media']} */
35
38
  this.media = options.media;
39
+ /** @type {CSSModuleCreateData['inheritance']} */
36
40
  this.inheritance = options.inheritance;
37
41
  }
38
42
 
@@ -150,7 +154,8 @@ class CssModule extends NormalModule {
150
154
  cssLayer: /** @type {EXPECTED_ANY} */ (null),
151
155
  supports: /** @type {EXPECTED_ANY} */ (null),
152
156
  media: /** @type {EXPECTED_ANY} */ (null),
153
- inheritance: /** @type {EXPECTED_ANY} */ (null)
157
+ inheritance: /** @type {EXPECTED_ANY} */ (null),
158
+ extractSourceMap: /** @type {EXPECTED_ANY} */ (null)
154
159
  });
155
160
  obj.deserialize(context);
156
161
  return obj;
@@ -5,6 +5,7 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const { SyncWaterfallHook } = require("tapable");
8
9
  const {
9
10
  JAVASCRIPT_MODULE_TYPE_AUTO,
10
11
  JAVASCRIPT_MODULE_TYPE_DYNAMIC,
@@ -32,6 +33,7 @@ const createHash = require("./util/createHash");
32
33
  /** @typedef {import("./javascript/JavascriptParser").DestructuringAssignmentProperties} DestructuringAssignmentProperties */
33
34
  /** @typedef {import("./javascript/JavascriptParser").Range} Range */
34
35
  /** @typedef {import("./logging/Logger").Logger} Logger */
36
+ /** @typedef {import("./Compilation")} Compilation */
35
37
 
36
38
  /** @typedef {null | undefined | RegExp | EXPECTED_FUNCTION | string | number | boolean | bigint | undefined} CodeValuePrimitive */
37
39
  /** @typedef {RecursiveArrayOrRecord<CodeValuePrimitive | RuntimeValue>} CodeValue */
@@ -42,7 +44,7 @@ const createHash = require("./util/createHash");
42
44
  * @property {string[]=} contextDependencies
43
45
  * @property {string[]=} missingDependencies
44
46
  * @property {string[]=} buildDependencies
45
- * @property {string| (() => string)=} version
47
+ * @property {string | (() => string)=} version
46
48
  */
47
49
 
48
50
  /** @typedef {(value: { module: NormalModule, key: string, readonly version: ValueCacheVersion }) => CodeValuePrimitive} GeneratorFn */
@@ -180,7 +182,7 @@ const stringifyObj = (
180
182
  code = `{${keys
181
183
  .map((key) => {
182
184
  const code = obj[key];
183
- return `${JSON.stringify(key)}:${toCode(
185
+ return `${key === "__proto__" ? '["__proto__"]' : JSON.stringify(key)}:${toCode(
184
186
  code,
185
187
  parser,
186
188
  valueCacheVersions,
@@ -330,7 +332,30 @@ const WEBPACK_REQUIRE_FUNCTION_REGEXP = new RegExp(
330
332
  );
331
333
  const WEBPACK_REQUIRE_IDENTIFIER_REGEXP = new RegExp(RuntimeGlobals.require);
332
334
 
335
+ /**
336
+ * @typedef {object} DefinePluginHooks
337
+ * @property {SyncWaterfallHook<[Record<string, CodeValue>]>} definitions
338
+ */
339
+
340
+ /** @type {WeakMap<Compilation, DefinePluginHooks>} */
341
+ const compilationHooksMap = new WeakMap();
342
+
333
343
  class DefinePlugin {
344
+ /**
345
+ * @param {Compilation} compilation the compilation
346
+ * @returns {DefinePluginHooks} the attached hooks
347
+ */
348
+ static getCompilationHooks(compilation) {
349
+ let hooks = compilationHooksMap.get(compilation);
350
+ if (hooks === undefined) {
351
+ hooks = {
352
+ definitions: new SyncWaterfallHook(["definitions"])
353
+ };
354
+ compilationHooksMap.set(compilation, hooks);
355
+ }
356
+ return hooks;
357
+ }
358
+
334
359
  /**
335
360
  * Create a new define plugin
336
361
  * @param {Record<string, CodeValue>} definitions A map of global object definitions
@@ -354,20 +379,26 @@ class DefinePlugin {
354
379
  * @returns {void}
355
380
  */
356
381
  apply(compiler) {
357
- const definitions = this.definitions;
358
-
359
- /**
360
- * @type {Map<string, Set<string>>}
361
- */
362
- const finalByNestedKey = new Map();
363
- /**
364
- * @type {Map<string, Set<string>>}
365
- */
366
- const nestedByFinalKey = new Map();
367
-
368
382
  compiler.hooks.compilation.tap(
369
383
  PLUGIN_NAME,
370
384
  (compilation, { normalModuleFactory }) => {
385
+ const definitions = this.definitions;
386
+ const hooks = DefinePlugin.getCompilationHooks(compilation);
387
+
388
+ hooks.definitions.tap(PLUGIN_NAME, (previousDefinitions) => ({
389
+ ...previousDefinitions,
390
+ ...definitions
391
+ }));
392
+
393
+ /**
394
+ * @type {Map<string, Set<string>>}
395
+ */
396
+ const finalByNestedKey = new Map();
397
+ /**
398
+ * @type {Map<string, Set<string>>}
399
+ */
400
+ const nestedByFinalKey = new Map();
401
+
371
402
  const logger = compilation.getLogger("webpack.DefinePlugin");
372
403
  compilation.dependencyTemplates.set(
373
404
  ConstDependency,
@@ -505,7 +536,7 @@ class DefinePlugin {
505
536
  return;
506
537
  }
507
538
  /** @type {Record<string, CodeValue>} */
508
- const obj = {};
539
+ const obj = Object.create(null);
509
540
  const finalSet = finalByNestedKey.get(nested);
510
541
  for (const { id } of destructed) {
511
542
  const fullKey = `${nested}.${id}`;
@@ -7,7 +7,10 @@
7
7
 
8
8
  const { OriginalSource, RawSource } = require("webpack-sources");
9
9
  const Module = require("./Module");
10
- const { JS_TYPES } = require("./ModuleSourceTypesConstants");
10
+ const {
11
+ JAVASCRIPT_TYPE,
12
+ JAVASCRIPT_TYPES
13
+ } = require("./ModuleSourceTypeConstants");
11
14
  const { JAVASCRIPT_MODULE_TYPE_DYNAMIC } = require("./ModuleTypeConstants");
12
15
  const RuntimeGlobals = require("./RuntimeGlobals");
13
16
  const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency");
@@ -80,7 +83,7 @@ class DelegatedModule extends Module {
80
83
  * @returns {SourceTypes} types available (do not mutate)
81
84
  */
82
85
  getSourceTypes() {
83
- return JS_TYPES;
86
+ return JAVASCRIPT_TYPES;
84
87
  }
85
88
 
86
89
  /**
@@ -177,9 +180,9 @@ class DelegatedModule extends Module {
177
180
 
178
181
  const sources = new Map();
179
182
  if (this.useSourceMap || this.useSimpleSourceMap) {
180
- sources.set("javascript", new OriginalSource(str, this.identifier()));
183
+ sources.set(JAVASCRIPT_TYPE, new OriginalSource(str, this.identifier()));
181
184
  } else {
182
- sources.set("javascript", new RawSource(str));
185
+ sources.set(JAVASCRIPT_TYPE, new RawSource(str));
183
186
  }
184
187
 
185
188
  return {
package/lib/Dependency.js CHANGED
@@ -19,7 +19,7 @@ const memoize = require("./util/memoize");
19
19
  /** @typedef {import("./serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
20
20
  /** @typedef {import("./util/Hash")} Hash */
21
21
  /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
22
-
22
+ /** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
23
23
  /**
24
24
  * @typedef {object} UpdateHashContext
25
25
  * @property {ChunkGraph} chunkGraph
@@ -360,6 +360,13 @@ Object.defineProperty(Dependency.prototype, "module", {
360
360
  }
361
361
  });
362
362
 
363
+ /**
364
+ * @param {Dependency} dependency dep
365
+ * @returns {boolean} true if the dependency is a low priority dependency
366
+ */
367
+ Dependency.isLowPriorityDependency = (dependency) =>
368
+ /** @type {ModuleDependency} */ (dependency).sourceOrder === Infinity;
369
+
363
370
  // TODO remove in webpack 6
364
371
  Object.defineProperty(Dependency.prototype, "disconnect", {
365
372
  /**
@@ -41,6 +41,7 @@
41
41
  /**
42
42
  * @typedef {object} CssDependencyTemplateContextExtras
43
43
  * @property {CssData} cssData the css exports data
44
+ * @property {string} type the css exports data
44
45
  */
45
46
 
46
47
  /**
package/lib/DllModule.js CHANGED
@@ -7,7 +7,10 @@
7
7
 
8
8
  const { RawSource } = require("webpack-sources");
9
9
  const Module = require("./Module");
10
- const { JS_TYPES } = require("./ModuleSourceTypesConstants");
10
+ const {
11
+ JAVASCRIPT_TYPE,
12
+ JAVASCRIPT_TYPES
13
+ } = require("./ModuleSourceTypeConstants");
11
14
  const { JAVASCRIPT_MODULE_TYPE_DYNAMIC } = require("./ModuleTypeConstants");
12
15
  const RuntimeGlobals = require("./RuntimeGlobals");
13
16
  const makeSerializable = require("./util/makeSerializable");
@@ -53,7 +56,7 @@ class DllModule extends Module {
53
56
  * @returns {SourceTypes} types available (do not mutate)
54
57
  */
55
58
  getSourceTypes() {
56
- return JS_TYPES;
59
+ return JAVASCRIPT_TYPES;
57
60
  }
58
61
 
59
62
  /**
@@ -92,7 +95,7 @@ class DllModule extends Module {
92
95
  codeGeneration(context) {
93
96
  const sources = new Map();
94
97
  sources.set(
95
- "javascript",
98
+ JAVASCRIPT_TYPE,
96
99
  new RawSource(`module.exports = ${RuntimeGlobals.require};`)
97
100
  );
98
101
  return {
@@ -0,0 +1,462 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Natsu @xiaoxiaojx
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const FileSystemInfo = require("./FileSystemInfo");
9
+ const createSchemaValidation = require("./util/create-schema-validation");
10
+ const { join } = require("./util/fs");
11
+
12
+ /** @typedef {import("../declarations/WebpackOptions").DotenvPluginOptions} DotenvPluginOptions */
13
+ /** @typedef {import("./Compiler")} Compiler */
14
+ /** @typedef {import("./CacheFacade").ItemCacheFacade} ItemCacheFacade */
15
+ /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
16
+ /** @typedef {import("./FileSystemInfo").Snapshot} Snapshot */
17
+
18
+ /** @typedef {Exclude<DotenvPluginOptions["prefix"], string | undefined>} Prefix */
19
+ /** @typedef {Record<string, string>} Env */
20
+
21
+ /** @type {DotenvPluginOptions} */
22
+ const DEFAULT_OPTIONS = {
23
+ prefix: "WEBPACK_",
24
+ template: [".env", ".env.local", ".env.[mode]", ".env.[mode].local"]
25
+ };
26
+
27
+ // Regex for parsing .env files
28
+ // ported from https://github.com/motdotla/dotenv/blob/master/lib/main.js#L32
29
+ const LINE =
30
+ /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
31
+
32
+ const PLUGIN_NAME = "DotenvPlugin";
33
+
34
+ const validate = createSchemaValidation(
35
+ undefined,
36
+ () => {
37
+ const { definitions } = require("../schemas/WebpackOptions.json");
38
+
39
+ return {
40
+ definitions,
41
+ oneOf: [{ $ref: "#/definitions/DotenvPluginOptions" }]
42
+ };
43
+ },
44
+ {
45
+ name: "Dotenv Plugin",
46
+ baseDataPath: "options"
47
+ }
48
+ );
49
+
50
+ /**
51
+ * Parse .env file content
52
+ * ported from https://github.com/motdotla/dotenv/blob/master/lib/main.js#L49
53
+ * @param {string | Buffer} src the source content to parse
54
+ * @returns {Env} parsed environment variables object
55
+ */
56
+ function parse(src) {
57
+ const obj = /** @type {Env} */ (Object.create(null));
58
+
59
+ // Convert buffer to string
60
+ let lines = src.toString();
61
+
62
+ // Convert line breaks to same format
63
+ lines = lines.replace(/\r\n?/gm, "\n");
64
+
65
+ let match;
66
+ while ((match = LINE.exec(lines)) !== null) {
67
+ const key = match[1];
68
+
69
+ // Default undefined or null to empty string
70
+ let value = match[2] || "";
71
+
72
+ // Remove whitespace
73
+ value = value.trim();
74
+
75
+ // Check if double quoted
76
+ const maybeQuote = value[0];
77
+
78
+ // Remove surrounding quotes
79
+ value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
80
+
81
+ // Expand newlines if double quoted
82
+ if (maybeQuote === '"') {
83
+ value = value.replace(/\\n/g, "\n");
84
+ value = value.replace(/\\r/g, "\r");
85
+ }
86
+
87
+ // Add to object
88
+ obj[key] = value;
89
+ }
90
+
91
+ return obj;
92
+ }
93
+
94
+ /**
95
+ * Resolve escape sequences
96
+ * ported from https://github.com/motdotla/dotenv-expand
97
+ * @param {string} value value to resolve
98
+ * @returns {string} resolved value
99
+ */
100
+ function _resolveEscapeSequences(value) {
101
+ return value.replace(/\\\$/g, "$");
102
+ }
103
+
104
+ /**
105
+ * Expand environment variable value
106
+ * ported from https://github.com/motdotla/dotenv-expand
107
+ * @param {string} value value to expand
108
+ * @param {Record<string, string | undefined>} processEnv process.env object
109
+ * @param {Env} runningParsed running parsed object
110
+ * @returns {string} expanded value
111
+ */
112
+ function expandValue(value, processEnv, runningParsed) {
113
+ const env = { ...runningParsed, ...processEnv }; // process.env wins
114
+
115
+ const regex = /(?<!\\)\$\{([^{}]+)\}|(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)/g;
116
+
117
+ let result = value;
118
+ let match;
119
+ const seen = new Set(); // self-referential checker
120
+
121
+ while ((match = regex.exec(result)) !== null) {
122
+ seen.add(result);
123
+
124
+ const [template, bracedExpression, unbracedExpression] = match;
125
+ const expression = bracedExpression || unbracedExpression;
126
+
127
+ // match the operators `:+`, `+`, `:-`, and `-`
128
+ const opRegex = /(:\+|\+|:-|-)/;
129
+ // find first match
130
+ const opMatch = expression.match(opRegex);
131
+ const splitter = opMatch ? opMatch[0] : null;
132
+
133
+ const r = expression.split(/** @type {string} */ (splitter));
134
+ // const r = splitter ? expression.split(splitter) : [expression];
135
+
136
+ let defaultValue;
137
+ let value;
138
+
139
+ const key = r.shift();
140
+
141
+ if ([":+", "+"].includes(splitter || "")) {
142
+ defaultValue = env[key || ""] ? r.join(splitter || "") : "";
143
+ value = null;
144
+ } else {
145
+ defaultValue = r.join(splitter || "");
146
+ value = env[key || ""];
147
+ }
148
+
149
+ if (value) {
150
+ // self-referential check
151
+ result = seen.has(value)
152
+ ? result.replace(template, defaultValue)
153
+ : result.replace(template, value);
154
+ } else {
155
+ result = result.replace(template, defaultValue);
156
+ }
157
+
158
+ // if the result equaled what was in process.env and runningParsed then stop expanding
159
+ if (result === runningParsed[key || ""]) {
160
+ break;
161
+ }
162
+
163
+ regex.lastIndex = 0; // reset regex search position to re-evaluate after each replacement
164
+ }
165
+
166
+ return result;
167
+ }
168
+
169
+ /**
170
+ * Expand environment variables in parsed object
171
+ * ported from https://github.com/motdotla/dotenv-expand
172
+ * @param {{ parsed: Env, processEnv: Record<string, string | undefined> }} options expand options
173
+ * @returns {{ parsed: Env }} expanded options
174
+ */
175
+ function expand(options) {
176
+ // for use with progressive expansion
177
+ const runningParsed = /** @type {Env} */ (Object.create(null));
178
+ const processEnv = options.processEnv;
179
+
180
+ // dotenv.config() ran before this so the assumption is process.env has already been set
181
+ for (const key in options.parsed) {
182
+ let value = options.parsed[key];
183
+
184
+ // short-circuit scenario: process.env was already set prior to the file value
185
+ value =
186
+ Object.prototype.hasOwnProperty.call(processEnv, key) &&
187
+ processEnv[key] !== value
188
+ ? /** @type {string} */ (processEnv[key])
189
+ : expandValue(value, processEnv, runningParsed);
190
+
191
+ const resolvedValue = _resolveEscapeSequences(value);
192
+
193
+ options.parsed[key] = resolvedValue;
194
+ // for use with progressive expansion
195
+ runningParsed[key] = resolvedValue;
196
+ }
197
+
198
+ // Part of `dotenv-expand` code, but we don't need it because of we don't modify `process.env`
199
+ // for (const processKey in options.parsed) {
200
+ // if (processEnv) {
201
+ // processEnv[processKey] = options.parsed[processKey];
202
+ // }
203
+ // }
204
+
205
+ return options;
206
+ }
207
+
208
+ /**
209
+ * Format environment variables as DefinePlugin definitions
210
+ * @param {Env} env environment variables
211
+ * @returns {Record<string, string>} formatted definitions
212
+ */
213
+ const envToDefinitions = (env) => {
214
+ const definitions = /** @type {Record<string, string>} */ ({});
215
+
216
+ for (const [key, value] of Object.entries(env)) {
217
+ const defValue = JSON.stringify(value);
218
+ definitions[`process.env.${key}`] = defValue;
219
+ definitions[`import.meta.env.${key}`] = defValue;
220
+ }
221
+
222
+ return definitions;
223
+ };
224
+
225
+ class DotenvPlugin {
226
+ /**
227
+ * @param {DotenvPluginOptions=} options options object
228
+ */
229
+ constructor(options = {}) {
230
+ validate(options);
231
+ this.options = { ...DEFAULT_OPTIONS, ...options };
232
+ }
233
+
234
+ /**
235
+ * @param {Compiler} compiler the compiler instance
236
+ * @returns {void}
237
+ */
238
+ apply(compiler) {
239
+ const definePlugin = new compiler.webpack.DefinePlugin({});
240
+ const prefixes = Array.isArray(this.options.prefix)
241
+ ? this.options.prefix
242
+ : [this.options.prefix || "WEBPACK_"];
243
+ /** @type {string | false} */
244
+ const dir =
245
+ typeof this.options.dir === "string"
246
+ ? this.options.dir
247
+ : typeof this.options.dir === "undefined"
248
+ ? compiler.context
249
+ : this.options.dir;
250
+
251
+ /** @type {undefined | Snapshot} */
252
+ let snapshot;
253
+
254
+ const cache = compiler.getCache(PLUGIN_NAME);
255
+ const identifier = JSON.stringify(this.options.template);
256
+ const itemCache = cache.getItemCache(identifier, null);
257
+
258
+ compiler.hooks.beforeCompile.tapPromise(PLUGIN_NAME, async () => {
259
+ const { parsed, snapshot: newSnapshot } = dir
260
+ ? await this._loadEnv(compiler, itemCache, dir)
261
+ : { parsed: {} };
262
+ const env = this._getEnv(prefixes, parsed);
263
+
264
+ definePlugin.definitions = envToDefinitions(env || {});
265
+ snapshot = newSnapshot;
266
+ });
267
+
268
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
269
+ if (snapshot) {
270
+ compilation.fileDependencies.addAll(snapshot.getFileIterable());
271
+ compilation.missingDependencies.addAll(snapshot.getMissingIterable());
272
+ }
273
+ });
274
+
275
+ definePlugin.apply(compiler);
276
+ }
277
+
278
+ /**
279
+ * Get list of env files to load based on mode and template
280
+ * Similar to Vite's getEnvFilesForMode
281
+ * @private
282
+ * @param {InputFileSystem} inputFileSystem the input file system
283
+ * @param {string | false} dir the directory containing .env files
284
+ * @param {string | undefined} mode the mode (e.g., 'production', 'development')
285
+ * @returns {string[]} array of file paths to load
286
+ */
287
+ _getEnvFilesForMode(inputFileSystem, dir, mode) {
288
+ if (!dir) {
289
+ return [];
290
+ }
291
+
292
+ const { template } = /** @type {DotenvPluginOptions} */ (this.options);
293
+ const templates = template || [];
294
+
295
+ return templates
296
+ .map((pattern) => pattern.replace(/\[mode\]/g, mode || "development"))
297
+ .map((file) => join(inputFileSystem, dir, file));
298
+ }
299
+
300
+ /**
301
+ * Get parsed env variables from `.env` files
302
+ * @private
303
+ * @param {InputFileSystem} fs input file system
304
+ * @param {string} dir dir to load `.env` files
305
+ * @param {string} mode mode
306
+ * @returns {Promise<{parsed: Env, fileDependencies: string[], missingDependencies: string[]}>} parsed env variables and dependencies
307
+ */
308
+ async _getParsed(fs, dir, mode) {
309
+ /** @type {string[]} */
310
+ const fileDependencies = [];
311
+ /** @type {string[]} */
312
+ const missingDependencies = [];
313
+
314
+ // Get env files to load
315
+ const envFiles = this._getEnvFilesForMode(fs, dir, mode);
316
+
317
+ // Read all files
318
+ const contents = await Promise.all(
319
+ envFiles.map((filePath) =>
320
+ this._loadFile(fs, filePath).then(
321
+ (content) => {
322
+ fileDependencies.push(filePath);
323
+ return content;
324
+ },
325
+ () => {
326
+ // File doesn't exist, add to missingDependencies (this is normal)
327
+ missingDependencies.push(filePath);
328
+ return "";
329
+ }
330
+ )
331
+ )
332
+ );
333
+
334
+ // Parse all files and merge (later files override earlier ones)
335
+ // Similar to Vite's implementation
336
+ const parsed = /** @type {Env} */ (Object.create(null));
337
+
338
+ for (const content of contents) {
339
+ if (!content) continue;
340
+ const entries = parse(content);
341
+ for (const key in entries) {
342
+ parsed[key] = entries[key];
343
+ }
344
+ }
345
+
346
+ return { parsed, fileDependencies, missingDependencies };
347
+ }
348
+
349
+ /**
350
+ * @private
351
+ * @param {Compiler} compiler compiler
352
+ * @param {ItemCacheFacade} itemCache item cache facade
353
+ * @param {string} dir directory to read
354
+ * @returns {Promise<{ parsed: Env, snapshot: Snapshot }>} parsed result and snapshot
355
+ */
356
+ async _loadEnv(compiler, itemCache, dir) {
357
+ const fs = /** @type {InputFileSystem} */ (compiler.inputFileSystem);
358
+ const fileSystemInfo = new FileSystemInfo(fs, {
359
+ unmanagedPaths: compiler.unmanagedPaths,
360
+ managedPaths: compiler.managedPaths,
361
+ immutablePaths: compiler.immutablePaths,
362
+ hashFunction: compiler.options.output.hashFunction
363
+ });
364
+
365
+ const result = await itemCache.getPromise();
366
+
367
+ if (result) {
368
+ const isSnapshotValid = await new Promise((resolve, reject) => {
369
+ fileSystemInfo.checkSnapshotValid(result.snapshot, (error, isValid) => {
370
+ if (error) {
371
+ reject(error);
372
+
373
+ return;
374
+ }
375
+
376
+ resolve(isValid);
377
+ });
378
+ });
379
+
380
+ if (isSnapshotValid) {
381
+ return { parsed: result.parsed, snapshot: result.snapshot };
382
+ }
383
+ }
384
+
385
+ const { parsed, fileDependencies, missingDependencies } =
386
+ await this._getParsed(
387
+ fs,
388
+ dir,
389
+ /** @type {string} */
390
+ (compiler.options.mode)
391
+ );
392
+
393
+ const startTime = Date.now();
394
+ const newSnapshot = await new Promise((resolve, reject) => {
395
+ fileSystemInfo.createSnapshot(
396
+ startTime,
397
+ fileDependencies,
398
+ null,
399
+ missingDependencies,
400
+ // `.env` files are build dependencies
401
+ compiler.options.snapshot.buildDependencies,
402
+ (err, snapshot) => {
403
+ if (err) return reject(err);
404
+ resolve(snapshot);
405
+ }
406
+ );
407
+ });
408
+
409
+ await itemCache.storePromise({ parsed, snapshot: newSnapshot });
410
+
411
+ return { parsed, snapshot: newSnapshot };
412
+ }
413
+
414
+ /**
415
+ * Generate env variables
416
+ * @private
417
+ * @param {Prefix} prefixes expose only environment variables that start with these prefixes
418
+ * @param {Env} parsed parsed env variables
419
+ * @returns {Env} env variables
420
+ */
421
+ _getEnv(prefixes, parsed) {
422
+ // Always expand environment variables (like Vite does)
423
+ // Make a copy of process.env so that dotenv-expand doesn't modify global process.env
424
+ const processEnv = { ...process.env };
425
+ expand({ parsed, processEnv });
426
+ const env = /** @type {Env} */ (Object.create(null));
427
+
428
+ // Get all keys from parser and process.env
429
+ const keys = [...Object.keys(parsed), ...Object.keys(process.env)];
430
+
431
+ // Prioritize actual env variables from `process.env`, fallback to parsed
432
+ for (const key of keys) {
433
+ if (prefixes.some((prefix) => key.startsWith(prefix))) {
434
+ env[key] =
435
+ Object.prototype.hasOwnProperty.call(process.env, key) &&
436
+ process.env[key]
437
+ ? process.env[key]
438
+ : parsed[key];
439
+ }
440
+ }
441
+
442
+ return env;
443
+ }
444
+
445
+ /**
446
+ * Load a file with proper path resolution
447
+ * @private
448
+ * @param {InputFileSystem} fs the input file system
449
+ * @param {string} file the file to load
450
+ * @returns {Promise<string>} the content of the file
451
+ */
452
+ _loadFile(fs, file) {
453
+ return new Promise((resolve, reject) => {
454
+ fs.readFile(file, (err, content) => {
455
+ if (err) reject(err);
456
+ else resolve(/** @type {Buffer} */ (content).toString() || "");
457
+ });
458
+ });
459
+ }
460
+ }
461
+
462
+ module.exports = DotenvPlugin;