webpack 5.110.3 → 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 (208) hide show
  1. package/README.md +5 -0
  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/CircularModulesPlugin.js +157 -55
  7. package/lib/CleanPlugin.js +2 -2
  8. package/lib/Compilation.js +320 -302
  9. package/lib/Compiler.js +209 -46
  10. package/lib/ContextModule.js +17 -81
  11. package/lib/ContextModuleFactory.js +1 -1
  12. package/lib/CopyPlugin.js +1054 -0
  13. package/lib/DefinePlugin.js +24 -8
  14. package/lib/ExternalModule.js +41 -14
  15. package/lib/FileSystemInfo.js +17 -14
  16. package/lib/FlagDependencyExportsPlugin.js +45 -21
  17. package/lib/HotModuleReplacementPlugin.js +53 -7
  18. package/lib/JavascriptMetaInfoPlugin.js +5 -3
  19. package/lib/MainTemplate.js +5 -1
  20. package/lib/Module.js +16 -7
  21. package/lib/MultiCompiler.js +1 -1
  22. package/lib/MultiWatching.js +1 -1
  23. package/lib/NormalModule.js +45 -12
  24. package/lib/NormalModuleFactory.js +1 -1
  25. package/lib/RuntimeGlobals.js +21 -7
  26. package/lib/RuntimeModule.js +28 -12
  27. package/lib/RuntimePlugin.js +30 -3
  28. package/lib/RuntimeTemplate.js +780 -475
  29. package/lib/SourceMapDevToolPlugin.js +1 -1
  30. package/lib/Watching.js +9 -0
  31. package/lib/WebpackOptionsApply.js +84 -91
  32. package/lib/asset/AssetGenerator.js +25 -8
  33. package/lib/asset/AssetModule.js +3 -0
  34. package/lib/asset/WebManifestParser.js +7 -5
  35. package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
  36. package/lib/cache/IdleFileCachePlugin.js +2 -2
  37. package/lib/cache/PackFileCacheStrategy.js +14 -1
  38. package/lib/config/browserslistTargetHandler.js +19 -0
  39. package/lib/config/defaults.js +86 -50
  40. package/lib/config/normalization.js +82 -12
  41. package/lib/config/target.js +10 -0
  42. package/lib/container/ContainerReferencePlugin.js +6 -0
  43. package/lib/container/RemoteRuntimeModule.js +9 -0
  44. package/lib/container/declaredRemotes.js +39 -0
  45. package/lib/css/CssGenerator.js +8 -0
  46. package/lib/css/CssInjectStyleRuntimeModule.js +9 -0
  47. package/lib/css/CssLoadingRuntimeModule.js +94 -36
  48. package/lib/css/CssModule.js +1 -1
  49. package/lib/css/CssModulesPlugin.js +7 -6
  50. package/lib/css/CssParser.js +144 -11
  51. package/lib/css/CssServerStylesRuntimeModule.js +9 -0
  52. package/lib/css/cssMinify.js +11 -3
  53. package/lib/css/data.js +2814 -678
  54. package/lib/css/syntax.js +4082 -248
  55. package/lib/debug/ProfilingPlugin.js +4 -0
  56. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
  57. package/lib/dependencies/AMDRuntimeModules.js +18 -0
  58. package/lib/dependencies/CommonJsExportRequireDependency.js +3 -1
  59. package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
  60. package/lib/dependencies/CommonJsImportsParserPlugin.js +1 -0
  61. package/lib/dependencies/CommonJsPlugin.js +19 -3
  62. package/lib/dependencies/CommonJsRequireDependency.js +14 -5
  63. package/lib/dependencies/CssIcssExportDependency.js +7 -1
  64. package/lib/dependencies/HarmonyCompatibilityDependency.js +58 -4
  65. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +8 -3
  66. package/lib/dependencies/HarmonyExportExpressionDependency.js +44 -29
  67. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +71 -13
  68. package/lib/dependencies/HarmonyExportInitFragment.js +99 -19
  69. package/lib/dependencies/HarmonyExportSpecifierDependency.js +18 -30
  70. package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
  71. package/lib/dependencies/HarmonyImportDependency.js +6 -1
  72. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +8 -1
  73. package/lib/dependencies/HarmonyImportSpecifierDependency.js +24 -1
  74. package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
  75. package/lib/dependencies/HtmlEntryDependency.js +50 -0
  76. package/lib/dependencies/ImportMetaMainDependency.js +104 -0
  77. package/lib/dependencies/ImportMetaPlugin.js +59 -15
  78. package/lib/dependencies/SystemRuntimeModule.js +9 -0
  79. package/lib/dependencies/WorkerDependency.js +1 -2
  80. package/lib/dependencies/WorkletDependency.js +1 -2
  81. package/lib/dll/DelegatedModule.js +18 -1
  82. package/lib/dll/DllReferencePlugin.js +11 -8
  83. package/lib/dll/LibManifestPlugin.js +1 -1
  84. package/lib/errors/AnalyzableBailoutsWarning.js +41 -0
  85. package/lib/errors/DuplicateModulesWarning.js +12 -7
  86. package/lib/errors/EmptyCopyPatternWarning.js +26 -0
  87. package/lib/errors/ExternalStarReexportError.js +44 -0
  88. package/lib/errors/MissingSourceMapsWarning.js +36 -0
  89. package/lib/errors/ModuleParseError.js +2 -1
  90. package/lib/errors/UnusedAssetsWarning.js +36 -0
  91. package/lib/errors/UnusedFederationWarning.js +35 -0
  92. package/lib/errors/UnusedModulesWarning.js +38 -0
  93. package/lib/esm/ExportWebpackRequireRuntimeModule.js +9 -0
  94. package/lib/esm/ModuleChunkFormatPlugin.js +28 -3
  95. package/lib/esm/ModuleChunkLoadingPlugin.js +30 -11
  96. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +92 -60
  97. package/lib/hmr/HotModuleReplacement.runtime.js +8 -2
  98. package/lib/hmr/HotModuleReplacementRuntimeModule.js +9 -0
  99. package/lib/html/HtmlGenerator.js +11 -5
  100. package/lib/html/HtmlModulesPlugin.js +331 -62
  101. package/lib/html/HtmlParser.js +13 -6
  102. package/lib/html/builtinEmbeddedRenderer.js +107 -0
  103. package/lib/html/data.js +121 -7
  104. package/lib/html/htmlMinify.js +84 -113
  105. package/lib/html/syntax.js +763 -426
  106. package/lib/ids/HashedModuleIdsPlugin.js +2 -1
  107. package/lib/index.js +3 -0
  108. package/lib/javascript/JavascriptModule.js +1 -0
  109. package/lib/javascript/JavascriptModulesPlugin.js +52 -24
  110. package/lib/javascript/JavascriptParser.js +1255 -728
  111. package/lib/javascript/StartupHelpers.js +27 -3
  112. package/lib/javascript/data.js +172 -0
  113. package/lib/javascript/grammar.js +5546 -0
  114. package/lib/javascript/parser.js +1494 -0
  115. package/lib/javascript/regexp.js +1762 -0
  116. package/lib/javascript/regexpData.js +51 -0
  117. package/lib/javascript/syntax.js +8696 -5225
  118. package/lib/library/ModuleLibraryPlugin.js +116 -5
  119. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
  120. package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
  121. package/lib/optimize/ConcatenatedModule.js +97 -20
  122. package/lib/optimize/ConstExportsPlugin.js +50 -39
  123. package/lib/optimize/InlineExports.js +20 -123
  124. package/lib/optimize/MangleExportsPlugin.js +10 -0
  125. package/lib/optimize/ModuleConcatenationPlugin.js +24 -1
  126. package/lib/optimize/RealContentHashPlugin.js +68 -9
  127. package/lib/optimize/SideEffectsFlagPlugin.js +17 -9
  128. package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
  129. package/lib/performance/CacheEffectivenessPlugin.js +4 -3
  130. package/lib/performance/DuplicateModulesPlugin.js +57 -13
  131. package/lib/performance/EvalUsagePlugin.js +5 -2
  132. package/lib/performance/MissingSourceMapsPlugin.js +115 -0
  133. package/lib/performance/PureAnnotationsPlugin.js +6 -3
  134. package/lib/performance/TopLevelThisPlugin.js +5 -4
  135. package/lib/performance/UnusedAssetsPlugin.js +109 -0
  136. package/lib/performance/UnusedFederationPlugin.js +147 -0
  137. package/lib/performance/UnusedModulesPlugin.js +141 -0
  138. package/lib/performance/UnusedReexportsPlugin.js +1 -55
  139. package/lib/performance/isOnlyReexported.js +65 -0
  140. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +25 -5
  141. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +2 -0
  142. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +9 -0
  143. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +9 -0
  144. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +9 -0
  145. package/lib/prefetch/ResourceHintPlugin.js +1 -2
  146. package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
  147. package/lib/prefetch/StartupAssetHintRuntimeModule.js +9 -0
  148. package/lib/rules/RuleSetCompiler.js +211 -4
  149. package/lib/runtime/AsyncModuleRuntimeModule.js +100 -66
  150. package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -0
  151. package/lib/runtime/BaseUriRuntimeModule.js +9 -0
  152. package/lib/runtime/ChunkNameRuntimeModule.js +9 -0
  153. package/lib/runtime/EnsureChunkRuntimeModule.js +35 -16
  154. package/lib/runtime/GetChunkFilenameRuntimeModule.js +9 -0
  155. package/lib/runtime/GetFullHashRuntimeModule.js +9 -0
  156. package/lib/runtime/GetMainFilenameRuntimeModule.js +9 -0
  157. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +9 -0
  158. package/lib/runtime/GlobalRuntimeModule.js +9 -0
  159. package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
  160. package/lib/runtime/HelperRuntimeModule.js +10 -0
  161. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +330 -219
  162. package/lib/runtime/NonceRuntimeModule.js +9 -0
  163. package/lib/runtime/OnChunksLoadedRuntimeModule.js +67 -20
  164. package/lib/runtime/PublicPathRuntimeModule.js +9 -0
  165. package/lib/runtime/RuntimeIdRuntimeModule.js +9 -0
  166. package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +90 -0
  167. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +9 -0
  168. package/lib/runtime/StartupEntrypointRuntimeModule.js +9 -0
  169. package/lib/runtime/SystemContextRuntimeModule.js +9 -0
  170. package/lib/runtime/ToBinaryRuntimeModule.js +9 -0
  171. package/lib/serialization/ObjectMiddleware.js +138 -106
  172. package/lib/sharing/ConsumeSharedPlugin.js +12 -0
  173. package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -0
  174. package/lib/sharing/ShareRuntimeModule.js +9 -0
  175. package/lib/sharing/declaredShared.js +47 -0
  176. package/lib/stats/DefaultStatsFactoryPlugin.js +3 -1
  177. package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
  178. package/lib/util/SourceProcessor.js +76 -69
  179. package/lib/util/async.js +292 -0
  180. package/lib/util/buildDiagnostics.js +69 -0
  181. package/lib/util/fs.js +27 -1
  182. package/lib/util/handlerKeys.js +40 -0
  183. package/lib/util/identifier.js +20 -0
  184. package/lib/util/internalSerializables.js +4 -0
  185. package/lib/util/registerExternalSerializer.js +6 -45
  186. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +9 -0
  187. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -0
  188. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +9 -0
  189. package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
  190. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
  191. package/package.json +22 -16
  192. package/schemas/WebpackOptions.check.js +1 -1
  193. package/schemas/WebpackOptions.json +379 -66
  194. package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
  195. package/schemas/plugins/ManifestPlugin.check.js +1 -1
  196. package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
  197. package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
  198. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
  199. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  200. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  201. package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
  202. package/schemas/plugins/dll/DllReferencePlugin.check.js +1 -1
  203. package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -1
  204. package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
  205. package/types.d.ts +1414 -314
  206. package/lib/dependencies/ExportBindingInitFragment.js +0 -191
  207. package/lib/errors/EntrypointOverlapWarning.js +0 -45
  208. package/lib/performance/EntrypointOverlapPlugin.js +0 -122
@@ -0,0 +1,115 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Alexander Akait @alexander-akait
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const { SourceMapSource } = require("webpack-sources");
9
+ const NormalModule = require("../NormalModule");
10
+ const MissingSourceMapsWarning = require("../errors/MissingSourceMapsWarning");
11
+ const { compareStrings } = require("../util/comparators");
12
+ const getSourceModules = require("./getSourceModules");
13
+
14
+ /** @import { PerformanceOptions } from "../../declarations/WebpackOptions" */
15
+ /** @import Compiler from "../Compiler" */
16
+ /** @import Module from "../Module" */
17
+ /** @import RequestShortener from "../RequestShortener" */
18
+ /** @import { MissingSourceMapDetails } from "../errors/MissingSourceMapsWarning" */
19
+
20
+ const PLUGIN_NAME = "MissingSourceMapsPlugin";
21
+
22
+ // Enough to name the offenders without listing every module a loader touched.
23
+ const MAX_REPORTED_MODULES = 5;
24
+
25
+ /**
26
+ * The loaders that ran on a module, shortened for reading.
27
+ * @param {NormalModule} module the module
28
+ * @param {RequestShortener} requestShortener the request shortener
29
+ * @returns {string[]} what to call them
30
+ */
31
+ const loaderNames = (module, requestShortener) =>
32
+ module.loaders.map((it) => requestShortener.shorten(it.loader) || it.loader);
33
+
34
+ class MissingSourceMapsPlugin {
35
+ /**
36
+ * Creates an instance of MissingSourceMapsPlugin.
37
+ * @param {PerformanceOptions} options the plugin options
38
+ */
39
+ constructor(options) {
40
+ /** @type {PerformanceOptions["hints"]} */
41
+ this.hints = options.hints;
42
+ }
43
+
44
+ /**
45
+ * Applies the plugin by registering its hooks on the compiler.
46
+ * @param {Compiler} compiler the compiler instance
47
+ * @returns {void}
48
+ */
49
+ apply(compiler) {
50
+ const hints = this.hints;
51
+
52
+ if (!hints) return;
53
+
54
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
55
+ // `afterSeal` is past the hash, which folds every message into it — a
56
+ // hint reported earlier would change the build's identity.
57
+ compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => {
58
+ const { requestShortener } = compilation;
59
+ /** @type {MissingSourceMapDetails[]} */
60
+ const found = [];
61
+
62
+ // A module can be reached both on its own and inside a
63
+ // concatenation, so it is only counted the first time.
64
+ /** @type {Set<Module>} */
65
+ const seen = new Set();
66
+
67
+ for (const parent of compilation.modules) {
68
+ // Scope hoisting makes several modules into one, and each of them
69
+ // kept the source its own loaders produced.
70
+ for (const module of getSourceModules(parent)) {
71
+ if (seen.has(module)) continue;
72
+
73
+ seen.add(module);
74
+
75
+ if (!(module instanceof NormalModule)) continue;
76
+
77
+ // Only where a real map was asked for: the cheap devtools map to
78
+ // the loader output by design, so nothing is lost there.
79
+ if (!module.useSourceMap) continue;
80
+ if (module.loaders.length === 0) continue;
81
+
82
+ // A loader that returned a map produces a `SourceMapSource`;
83
+ // falling back to any other source is the map being dropped.
84
+ if (module.originalSource() instanceof SourceMapSource) continue;
85
+
86
+ found.push({
87
+ name: module.readableIdentifier(requestShortener),
88
+ loaders: loaderNames(module, requestShortener)
89
+ });
90
+ }
91
+ }
92
+
93
+ if (found.length === 0) return;
94
+
95
+ // By name: module order is not stable across runs.
96
+ found.sort((a, b) => compareStrings(a.name, b.name));
97
+
98
+ const warning = new MissingSourceMapsWarning(
99
+ found.slice(0, MAX_REPORTED_MODULES),
100
+ found.length
101
+ );
102
+
103
+ if (hints === "error") {
104
+ compilation.errors.push(warning);
105
+ } else if (hints === "stats") {
106
+ compilation.hints.push(warning);
107
+ } else {
108
+ compilation.warnings.push(warning);
109
+ }
110
+ });
111
+ });
112
+ }
113
+ }
114
+
115
+ module.exports = MissingSourceMapsPlugin;
@@ -11,6 +11,7 @@ const {
11
11
  JAVASCRIPT_MODULE_TYPE_ESM
12
12
  } = require("../ModuleTypeConstants");
13
13
  const PureAnnotationsWarning = require("../errors/PureAnnotationsWarning");
14
+ const { getBuildDiagnostics } = require("../util/buildDiagnostics");
14
15
  const { compareStrings } = require("../util/comparators");
15
16
  const { CompilerHintNotationRegExp } = require("../util/magicComment");
16
17
 
@@ -154,7 +155,7 @@ class PureAnnotationsPlugin {
154
155
  parser.state.module.buildInfo
155
156
  );
156
157
 
157
- buildInfo.ineffectivePureAnnotations = wasted;
158
+ getBuildDiagnostics(buildInfo).ineffectivePureAnnotations = wasted;
158
159
  });
159
160
  };
160
161
 
@@ -180,9 +181,11 @@ class PureAnnotationsPlugin {
180
181
  // Every built module carries one, so only the field is in question.
181
182
  const buildInfo = /** @type {BuildInfo} */ (module.buildInfo);
182
183
 
183
- if (!buildInfo.ineffectivePureAnnotations) continue;
184
+ const count =
185
+ buildInfo.diagnostics &&
186
+ buildInfo.diagnostics.ineffectivePureAnnotations;
184
187
 
185
- const count = buildInfo.ineffectivePureAnnotations;
188
+ if (!count) continue;
186
189
 
187
190
  total += count;
188
191
  wasteful.push({
@@ -11,14 +11,14 @@ const {
11
11
  JAVASCRIPT_MODULE_TYPE_ESM
12
12
  } = require("../ModuleTypeConstants");
13
13
  const TopLevelThisWarning = require("../errors/TopLevelThisWarning");
14
+ const { getBuildDiagnostics } = require("../util/buildDiagnostics");
14
15
  const { compareStrings } = require("../util/comparators");
15
16
  const getSourceModules = require("./getSourceModules");
16
17
 
17
18
  /** @import { Program } from "estree" */
18
19
  /** @import { PerformanceOptions } from "../../declarations/WebpackOptions" */
19
20
  /** @import Compiler from "../Compiler" */
20
- /** @import Module from "../Module" */
21
- /** @import { BuildInfo } from "../Module" */
21
+ /** @import Module, { BuildInfo } from "../Module" */
22
22
  /** @import JavascriptParser from "../javascript/JavascriptParser" */
23
23
  /** @import { TopLevelThisDetails } from "../errors/TopLevelThisWarning" */
24
24
 
@@ -133,7 +133,7 @@ class TopLevelThisPlugin {
133
133
  /** @type {BuildInfo} */
134
134
  (parser.state.module.buildInfo);
135
135
 
136
- buildInfo.topLevelThis = count;
136
+ getBuildDiagnostics(buildInfo).topLevelThis = count;
137
137
  });
138
138
  };
139
139
 
@@ -168,7 +168,8 @@ class TopLevelThisPlugin {
168
168
  seen.add(module);
169
169
 
170
170
  const buildInfo = /** @type {BuildInfo} */ (module.buildInfo);
171
- const count = buildInfo.topLevelThis;
171
+ const count =
172
+ buildInfo.diagnostics && buildInfo.diagnostics.topLevelThis;
172
173
 
173
174
  if (!count) continue;
174
175
 
@@ -0,0 +1,109 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Alexander Akait @alexander-akait
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const { ASSET_TYPE } = require("../ModuleSourceTypeConstants");
9
+ const HarmonyImportBareSideEffectDependency = require("../dependencies/HarmonyImportBareSideEffectDependency");
10
+ const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency");
11
+ const UnusedAssetsWarning = require("../errors/UnusedAssetsWarning");
12
+ const { compareStrings } = require("../util/comparators");
13
+ const getModuleSize = require("./getModuleSize");
14
+
15
+ /** @import { PerformanceOptions } from "../../declarations/WebpackOptions" */
16
+ /** @import Compiler from "../Compiler" */
17
+ /** @import { UnusedAssetDetails } from "../errors/UnusedAssetsWarning" */
18
+
19
+ const PLUGIN_NAME = "UnusedAssetsPlugin";
20
+
21
+ // Enough to name the offenders without listing every asset in the build.
22
+ const MAX_REPORTED_ASSETS = 5;
23
+
24
+ class UnusedAssetsPlugin {
25
+ /**
26
+ * Creates an instance of UnusedAssetsPlugin.
27
+ * @param {PerformanceOptions} options the plugin options
28
+ */
29
+ constructor(options) {
30
+ /** @type {PerformanceOptions["hints"]} */
31
+ this.hints = options.hints;
32
+ }
33
+
34
+ /**
35
+ * Applies the plugin by registering its hooks on the compiler.
36
+ * @param {Compiler} compiler the compiler instance
37
+ * @returns {void}
38
+ */
39
+ apply(compiler) {
40
+ const hints = this.hints;
41
+
42
+ if (!hints) return;
43
+
44
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
45
+ // `afterSeal` is past the hash, which folds every message into it — a
46
+ // hint reported earlier would change the build's identity.
47
+ compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => {
48
+ const { moduleGraph, requestShortener } = compilation;
49
+ /** @type {UnusedAssetDetails[]} */
50
+ const found = [];
51
+ let total = 0;
52
+
53
+ for (const module of compilation.modules) {
54
+ // An inlined one carries no asset type: it is a data url in the
55
+ // importer, whose bytes `inlinedAssets` is the check for.
56
+ if (!module.getSourceTypes().has(ASSET_TYPE)) continue;
57
+
58
+ let onlyUnread = false;
59
+
60
+ for (const connection of moduleGraph.getIncomingConnections(module)) {
61
+ const dependency = connection.dependency;
62
+
63
+ // Anything else — a `url()`, a `new URL()`, an html `src` — reads
64
+ // the file, and a bare import asks for it on purpose.
65
+ if (
66
+ !(dependency instanceof HarmonyImportSideEffectDependency) ||
67
+ dependency instanceof HarmonyImportBareSideEffectDependency
68
+ ) {
69
+ onlyUnread = false;
70
+ break;
71
+ }
72
+
73
+ onlyUnread = true;
74
+ }
75
+
76
+ if (!onlyUnread) continue;
77
+
78
+ const size = Math.round(getModuleSize(module));
79
+
80
+ total += size;
81
+ found.push({
82
+ name: module.readableIdentifier(requestShortener),
83
+ size
84
+ });
85
+ }
86
+
87
+ if (found.length === 0) return;
88
+
89
+ // Largest first; ties break by name, module order is not stable.
90
+ found.sort((a, b) => b.size - a.size || compareStrings(a.name, b.name));
91
+
92
+ const warning = new UnusedAssetsWarning(
93
+ found.slice(0, MAX_REPORTED_ASSETS),
94
+ total
95
+ );
96
+
97
+ if (hints === "error") {
98
+ compilation.errors.push(warning);
99
+ } else if (hints === "stats") {
100
+ compilation.hints.push(warning);
101
+ } else {
102
+ compilation.warnings.push(warning);
103
+ }
104
+ });
105
+ });
106
+ }
107
+ }
108
+
109
+ module.exports = UnusedAssetsPlugin;
@@ -0,0 +1,147 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Alexander Akait @alexander-akait
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const RemoteModule = require("../container/RemoteModule");
9
+ const { getDeclaredRemotes } = require("../container/declaredRemotes");
10
+ const UnusedFederationWarning = require("../errors/UnusedFederationWarning");
11
+ const ConsumeSharedModule = require("../sharing/ConsumeSharedModule");
12
+ const { getDeclaredShared } = require("../sharing/declaredShared");
13
+ const { compareStrings } = require("../util/comparators");
14
+
15
+ /** @import { PerformanceOptions } from "../../declarations/WebpackOptions" */
16
+ /** @import Compiler from "../Compiler" */
17
+ /** @import { UnusedFederationDetails } from "../errors/UnusedFederationWarning" */
18
+
19
+ const PLUGIN_NAME = "UnusedFederationPlugin";
20
+
21
+ /**
22
+ * @param {Set<string>} used the share keys modules were created for
23
+ * @param {string} shareKey the declared share key
24
+ * @returns {boolean} whether anything under the share key was used
25
+ */
26
+ const someUsedStartsWith = (used, shareKey) => {
27
+ for (const usedKey of used) {
28
+ if (usedKey.startsWith(shareKey)) return true;
29
+ }
30
+
31
+ return false;
32
+ };
33
+
34
+ /**
35
+ * Applies the rule `ContainerReferencePlugin` factorizes by, so that a remote
36
+ * name holding slashes is told apart from an exposed path holding them too.
37
+ * @param {string} request the request a remote module was created for
38
+ * @param {string} name the declared remote name
39
+ * @returns {boolean} whether the request names this remote
40
+ */
41
+ const isRequestFor = (request, name) =>
42
+ request.startsWith(name) &&
43
+ (request.length === name.length || request[name.length] === "/");
44
+
45
+ class UnusedFederationPlugin {
46
+ /**
47
+ * Creates an instance of UnusedFederationPlugin.
48
+ * @param {PerformanceOptions} options the plugin options
49
+ */
50
+ constructor(options) {
51
+ /** @type {PerformanceOptions["hints"]} */
52
+ this.hints = options.hints;
53
+ }
54
+
55
+ /**
56
+ * Applies the plugin by registering its hooks on the compiler.
57
+ * @param {Compiler} compiler the compiler instance
58
+ * @returns {void}
59
+ */
60
+ apply(compiler) {
61
+ const hints = this.hints;
62
+
63
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
64
+ // Reported past the hash, which folds every message into it, so a hint
65
+ // pushed earlier would change the build's identity.
66
+ compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => {
67
+ const declaredShared = getDeclaredShared(compilation);
68
+ const declaredRemotes = getDeclaredRemotes(compilation);
69
+
70
+ if (declaredShared === undefined && declaredRemotes === undefined) {
71
+ return;
72
+ }
73
+
74
+ // Nothing was factorized, so no shared or remote module could exist.
75
+ if (compilation.modules.size === 0) return;
76
+
77
+ /** @type {Set<string>} */
78
+ const usedShared = new Set();
79
+ /** @type {Set<string>} */
80
+ const remoteRequests = new Set();
81
+
82
+ for (const module of compilation.modules) {
83
+ if (module instanceof ConsumeSharedModule) {
84
+ usedShared.add(module.options.shareKey);
85
+ } else if (module instanceof RemoteModule) {
86
+ remoteRequests.add(module.request);
87
+ }
88
+ }
89
+
90
+ /** @type {UnusedFederationDetails[]} */
91
+ const unused = [];
92
+
93
+ if (declaredShared !== undefined) {
94
+ // Matched on the share key, since that is what the module carries,
95
+ // but reported by the config key, which is what the config spells.
96
+ for (const { name, shareKey, prefix } of declaredShared) {
97
+ const used = prefix
98
+ ? someUsedStartsWith(usedShared, shareKey)
99
+ : usedShared.has(shareKey);
100
+
101
+ if (!used) unused.push({ name, kind: "shared" });
102
+ }
103
+ }
104
+
105
+ if (declaredRemotes !== undefined) {
106
+ /** @type {Set<string>} */
107
+ const usedRemotes = new Set();
108
+
109
+ // Declaration order is precedence: `factorize` takes the first
110
+ // name a request matches, so a later one it also matches is dead.
111
+ for (const request of remoteRequests) {
112
+ for (const name of declaredRemotes) {
113
+ if (isRequestFor(request, name)) {
114
+ usedRemotes.add(name);
115
+ break;
116
+ }
117
+ }
118
+ }
119
+
120
+ for (const name of declaredRemotes) {
121
+ if (!usedRemotes.has(name)) unused.push({ name, kind: "remote" });
122
+ }
123
+ }
124
+
125
+ if (unused.length === 0) return;
126
+
127
+ // Ties break by name: declaration order is not worth preserving here.
128
+ unused.sort(
129
+ (a, b) =>
130
+ compareStrings(a.kind, b.kind) || compareStrings(a.name, b.name)
131
+ );
132
+
133
+ const warning = new UnusedFederationWarning(unused);
134
+
135
+ if (hints === "error") {
136
+ compilation.errors.push(warning);
137
+ } else if (hints === "stats") {
138
+ compilation.hints.push(warning);
139
+ } else {
140
+ compilation.warnings.push(warning);
141
+ }
142
+ });
143
+ });
144
+ }
145
+ }
146
+
147
+ module.exports = UnusedFederationPlugin;
@@ -0,0 +1,141 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Alexander Akait @alexander-akait
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const HarmonyImportBareSideEffectDependency = require("../dependencies/HarmonyImportBareSideEffectDependency");
9
+ const UnusedModulesWarning = require("../errors/UnusedModulesWarning");
10
+ const { compareStrings } = require("../util/comparators");
11
+ const getModuleSize = require("./getModuleSize");
12
+ const hasOnlyUnusedExports = require("./hasOnlyUnusedExports");
13
+ const isOnlyReexported = require("./isOnlyReexported");
14
+
15
+ /** @import { PerformanceOptions } from "../../declarations/WebpackOptions" */
16
+ /** @import Compiler from "../Compiler" */
17
+ /** @import Module, { BuildInfo } from "../Module" */
18
+ /** @import ModuleGraph from "../ModuleGraph" */
19
+ /** @import { UnusedModuleDetails } from "../errors/UnusedModulesWarning" */
20
+
21
+ const PLUGIN_NAME = "UnusedModulesPlugin";
22
+
23
+ // Enough to name the offenders without listing every module kept this way.
24
+ const MAX_REPORTED_MODULES = 5;
25
+
26
+ /**
27
+ * Whether some importer bound a name from this module. A bare `import "..."`
28
+ * binds nothing, so it can only have been written for what importing does —
29
+ * that is deliberate, and not what this hint is about.
30
+ * @param {Module} module the module to look up
31
+ * @param {ModuleGraph} moduleGraph the module graph
32
+ * @returns {boolean} true when every importer bound something
33
+ */
34
+ const everyImportBinds = (module, moduleGraph) => {
35
+ for (const connection of moduleGraph.getIncomingConnections(module)) {
36
+ if (
37
+ connection.dependency instanceof HarmonyImportBareSideEffectDependency
38
+ ) {
39
+ return false;
40
+ }
41
+ }
42
+
43
+ return true;
44
+ };
45
+
46
+ class UnusedModulesPlugin {
47
+ /**
48
+ * Creates an instance of UnusedModulesPlugin.
49
+ * @param {PerformanceOptions} options the plugin options
50
+ */
51
+ constructor(options) {
52
+ /** @type {PerformanceOptions["hints"]} */
53
+ this.hints = options.hints;
54
+ }
55
+
56
+ /**
57
+ * Applies the plugin by registering its hooks on the compiler.
58
+ * @param {Compiler} compiler the compiler instance
59
+ * @returns {void}
60
+ */
61
+ apply(compiler) {
62
+ const hints = this.hints;
63
+
64
+ if (!hints) return;
65
+
66
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
67
+ /** @type {UnusedModulesWarning | undefined} */
68
+ let warning;
69
+
70
+ // Usage is final here, and concatenation has not merged the modules
71
+ // away yet, so each one can still be measured and attributed.
72
+ compilation.hooks.optimizeModules.tap(PLUGIN_NAME, (modules) => {
73
+ const { chunkGraph, moduleGraph, requestShortener } = compilation;
74
+ /** @type {UnusedModuleDetails[]} */
75
+ const found = [];
76
+ let size = 0;
77
+
78
+ for (const module of modules) {
79
+ // One webpack already left out costs nothing — and with no chunk it
80
+ // has no runtime, which is all `hasOnlyUnusedExports` reads usage in.
81
+ if (chunkGraph.getNumberOfModuleChunks(module) === 0) continue;
82
+ if (!hasOnlyUnusedExports(module, moduleGraph, chunkGraph)) continue;
83
+
84
+ // A barrel's leftover is the same finding with a different cause,
85
+ // and `UnusedReexportsPlugin` states it with the re-export named.
86
+ if (isOnlyReexported(module, moduleGraph)) continue;
87
+
88
+ if (!everyImportBinds(module, moduleGraph)) continue;
89
+
90
+ // Recorded while parsing, so a module restored from the cache still has it.
91
+ // Absent means the module is kept for a reason this hint cannot name.
92
+ const diagnostics =
93
+ /** @type {BuildInfo} */
94
+ (module.buildInfo).diagnostics;
95
+ const statement =
96
+ diagnostics === undefined
97
+ ? undefined
98
+ : diagnostics.sideEffectStatement;
99
+
100
+ if (statement === undefined) continue;
101
+
102
+ const bytes = Math.round(getModuleSize(module));
103
+
104
+ size += bytes;
105
+ found.push({
106
+ name: module.readableIdentifier(requestShortener),
107
+ size: bytes,
108
+ statement
109
+ });
110
+ }
111
+
112
+ if (found.length === 0) return;
113
+
114
+ // Largest first; ties break by name, module order is not stable.
115
+ found.sort((a, b) => b.size - a.size || compareStrings(a.name, b.name));
116
+
117
+ warning = new UnusedModulesWarning(
118
+ found.slice(0, MAX_REPORTED_MODULES),
119
+ found.length,
120
+ size
121
+ );
122
+ });
123
+
124
+ // Reported past the hash: `createHash` folds every message into it, so
125
+ // a hint pushed earlier would change the build's identity.
126
+ compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => {
127
+ if (warning === undefined) return;
128
+
129
+ if (hints === "error") {
130
+ compilation.errors.push(warning);
131
+ } else if (hints === "stats") {
132
+ compilation.hints.push(warning);
133
+ } else {
134
+ compilation.warnings.push(warning);
135
+ }
136
+ });
137
+ });
138
+ }
139
+ }
140
+
141
+ module.exports = UnusedModulesPlugin;
@@ -5,17 +5,14 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency");
9
- const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
10
8
  const UnusedReexportsWarning = require("../errors/UnusedReexportsWarning");
11
9
  const { compareStrings } = require("../util/comparators");
12
10
  const getModuleSize = require("./getModuleSize");
13
11
  const hasOnlyUnusedExports = require("./hasOnlyUnusedExports");
12
+ const isOnlyReexported = require("./isOnlyReexported");
14
13
 
15
14
  /** @import { PerformanceOptions } from "../../declarations/WebpackOptions" */
16
15
  /** @import Compiler from "../Compiler" */
17
- /** @import Module from "../Module" */
18
- /** @import ModuleGraph from "../ModuleGraph" */
19
16
  /** @import { UnusedReexportDetails } from "../errors/UnusedReexportsWarning" */
20
17
 
21
18
  const PLUGIN_NAME = "UnusedReexportsPlugin";
@@ -23,57 +20,6 @@ const PLUGIN_NAME = "UnusedReexportsPlugin";
23
20
  // Enough to name the offenders without listing the barrel.
24
21
  const MAX_REPORTED_MODULES = 5;
25
22
 
26
- /**
27
- * Tells whether every module pulling this one in does so by re-exporting it.
28
- * One an importer wants for its side effects alone is deliberate, not a
29
- * barrel's leftover.
30
- * @param {Module} module the module to look up
31
- * @param {ModuleGraph} moduleGraph the module graph
32
- * @returns {boolean} true when only re-exports pull it in
33
- */
34
- const isOnlyReexported = (module, moduleGraph) => {
35
- // A re-export emits a side-effect edge of its own, so edges are grouped by
36
- // the statement they come from — `sourceOrder` — rather than by their type.
37
- /** @type {Map<Module, Set<number | undefined>>} */
38
- const reexportedStatements = new Map();
39
- /** @type {[Module, number | undefined][]} */
40
- const edges = [];
41
-
42
- for (const connection of moduleGraph.getIncomingConnections(module)) {
43
- const origin = connection.originModule;
44
-
45
- // An entry has no origin: it is in the build because it was asked for.
46
- if (!origin) return false;
47
-
48
- const dependency = connection.dependency;
49
-
50
- // Only an ESM import statement can carry a re-export.
51
- if (!(dependency instanceof HarmonyImportDependency)) return false;
52
-
53
- if (dependency instanceof HarmonyExportImportedSpecifierDependency) {
54
- const statements = reexportedStatements.get(origin);
55
-
56
- if (statements === undefined) {
57
- reexportedStatements.set(origin, new Set([dependency.sourceOrder]));
58
- } else {
59
- statements.add(dependency.sourceOrder);
60
- }
61
- }
62
-
63
- edges.push([origin, dependency.sourceOrder]);
64
- }
65
-
66
- if (edges.length === 0) return false;
67
-
68
- for (const [origin, sourceOrder] of edges) {
69
- const statements = reexportedStatements.get(origin);
70
-
71
- if (statements === undefined || !statements.has(sourceOrder)) return false;
72
- }
73
-
74
- return true;
75
- };
76
-
77
23
  class UnusedReexportsPlugin {
78
24
  /**
79
25
  * Creates an instance of UnusedReexportsPlugin.