WebpackOptionsApply.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const APIPlugin = require("./APIPlugin");
  7. const CompatibilityPlugin = require("./CompatibilityPlugin");
  8. const ConstPlugin = require("./ConstPlugin");
  9. const EntryOptionPlugin = require("./EntryOptionPlugin");
  10. const ExportsInfoApiPlugin = require("./ExportsInfoApiPlugin");
  11. const FlagDependencyExportsPlugin = require("./FlagDependencyExportsPlugin");
  12. const JavascriptMetaInfoPlugin = require("./JavascriptMetaInfoPlugin");
  13. const NodeStuffPlugin = require("./NodeStuffPlugin");
  14. const OptionsApply = require("./OptionsApply");
  15. const RecordIdsPlugin = require("./RecordIdsPlugin");
  16. const RuntimePlugin = require("./RuntimePlugin");
  17. const TemplatedPathPlugin = require("./TemplatedPathPlugin");
  18. const UseStrictPlugin = require("./UseStrictPlugin");
  19. const WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin");
  20. const WebpackIsIncludedPlugin = require("./WebpackIsIncludedPlugin");
  21. const AssetModulesPlugin = require("./asset/AssetModulesPlugin");
  22. const InferAsyncModulesPlugin = require("./async-modules/InferAsyncModulesPlugin");
  23. const ResolverCachePlugin = require("./cache/ResolverCachePlugin");
  24. const CommonJsPlugin = require("./dependencies/CommonJsPlugin");
  25. const HarmonyModulesPlugin = require("./dependencies/HarmonyModulesPlugin");
  26. const ImportMetaContextPlugin = require("./dependencies/ImportMetaContextPlugin");
  27. const ImportMetaPlugin = require("./dependencies/ImportMetaPlugin");
  28. const ImportPlugin = require("./dependencies/ImportPlugin");
  29. const LoaderPlugin = require("./dependencies/LoaderPlugin");
  30. const RequireContextPlugin = require("./dependencies/RequireContextPlugin");
  31. const RequireEnsurePlugin = require("./dependencies/RequireEnsurePlugin");
  32. const RequireIncludePlugin = require("./dependencies/RequireIncludePlugin");
  33. const SystemPlugin = require("./dependencies/SystemPlugin");
  34. const URLPlugin = require("./dependencies/URLPlugin");
  35. const WorkerPlugin = require("./dependencies/WorkerPlugin");
  36. const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
  37. const JsonModulesPlugin = require("./json/JsonModulesPlugin");
  38. const ChunkPrefetchPreloadPlugin = require("./prefetch/ChunkPrefetchPreloadPlugin");
  39. const DataUriPlugin = require("./schemes/DataUriPlugin");
  40. const FileUriPlugin = require("./schemes/FileUriPlugin");
  41. const DefaultStatsFactoryPlugin = require("./stats/DefaultStatsFactoryPlugin");
  42. const DefaultStatsPresetPlugin = require("./stats/DefaultStatsPresetPlugin");
  43. const DefaultStatsPrinterPlugin = require("./stats/DefaultStatsPrinterPlugin");
  44. const { cleverMerge } = require("./util/cleverMerge");
  45. /** @typedef {import("../declarations/WebpackOptions").WebpackPluginFunction} WebpackPluginFunction */
  46. /** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
  47. /** @typedef {import("./Compiler")} Compiler */
  48. /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
  49. /** @typedef {import("./util/fs").IntermediateFileSystem} IntermediateFileSystem */
  50. const CLASS_NAME = "WebpackOptionsApply";
  51. class WebpackOptionsApply extends OptionsApply {
  52. constructor() {
  53. super();
  54. }
  55. /**
  56. * @param {WebpackOptions} options options object
  57. * @param {Compiler} compiler compiler object
  58. * @returns {WebpackOptions} options object
  59. */
  60. process(options, compiler) {
  61. compiler.outputPath = options.output.path;
  62. compiler.recordsInputPath = options.recordsInputPath || null;
  63. compiler.recordsOutputPath = options.recordsOutputPath || null;
  64. compiler.name = options.name;
  65. if (options.externals) {
  66. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  67. const ExternalsPlugin = require("./ExternalsPlugin");
  68. new ExternalsPlugin(options.externalsType, options.externals).apply(
  69. compiler
  70. );
  71. }
  72. if (options.externalsPresets.node) {
  73. const NodeTargetPlugin = require("./node/NodeTargetPlugin");
  74. // Some older versions of Node.js don't support all built-in modules via import, only via `require`,
  75. // but it seems like there shouldn't be a warning here since these versions are rarely used in real applications
  76. new NodeTargetPlugin(
  77. options.output.module &&
  78. compiler.platform.node === null &&
  79. compiler.platform.web === null
  80. ? "module-import"
  81. : "node-commonjs"
  82. ).apply(compiler);
  83. // Handle external CSS `@import` and `url()`
  84. if (options.experiments.css) {
  85. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  86. const ExternalsPlugin = require("./ExternalsPlugin");
  87. new ExternalsPlugin(
  88. "module",
  89. ({ request, dependencyType, contextInfo }, callback) => {
  90. if (
  91. /\.css(\?|$)/.test(contextInfo.issuer) &&
  92. /^(\/\/|https?:\/\/|#)/.test(request)
  93. ) {
  94. if (dependencyType === "url") {
  95. return callback(null, `asset ${request}`);
  96. } else if (
  97. (dependencyType === "css-import" ||
  98. dependencyType === "css-import-local-module" ||
  99. dependencyType === "css-import-global-module") &&
  100. options.experiments.css
  101. ) {
  102. return callback(null, `css-import ${request}`);
  103. }
  104. }
  105. callback();
  106. }
  107. ).apply(compiler);
  108. }
  109. }
  110. if (options.externalsPresets.webAsync || options.externalsPresets.web) {
  111. const type = options.externalsPresets.webAsync ? "import" : "module";
  112. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  113. const ExternalsPlugin = require("./ExternalsPlugin");
  114. new ExternalsPlugin(type, ({ request, dependencyType }, callback) => {
  115. if (/^(\/\/|https?:\/\/|#|std:|jsr:|npm:)/.test(request)) {
  116. if (dependencyType === "url") {
  117. return callback(null, `asset ${request}`);
  118. } else if (
  119. (dependencyType === "css-import" ||
  120. dependencyType === "css-import-local-module" ||
  121. dependencyType === "css-import-global-module") &&
  122. options.experiments.css
  123. ) {
  124. return callback(null, `css-import ${request}`);
  125. } else if (/^(\/\/|https?:\/\/|std:|jsr:|npm:)/.test(request)) {
  126. return callback(null, `${type} ${request}`);
  127. }
  128. }
  129. callback();
  130. }).apply(compiler);
  131. }
  132. if (options.externalsPresets.electron) {
  133. if (options.externalsPresets.electronMain) {
  134. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  135. const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
  136. new ElectronTargetPlugin("main").apply(compiler);
  137. }
  138. if (options.externalsPresets.electronPreload) {
  139. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  140. const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
  141. new ElectronTargetPlugin("preload").apply(compiler);
  142. }
  143. if (options.externalsPresets.electronRenderer) {
  144. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  145. const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
  146. new ElectronTargetPlugin("renderer").apply(compiler);
  147. }
  148. if (
  149. !options.externalsPresets.electronMain &&
  150. !options.externalsPresets.electronPreload &&
  151. !options.externalsPresets.electronRenderer
  152. ) {
  153. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  154. const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
  155. new ElectronTargetPlugin().apply(compiler);
  156. }
  157. }
  158. if (options.externalsPresets.nwjs) {
  159. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  160. const ExternalsPlugin = require("./ExternalsPlugin");
  161. new ExternalsPlugin("node-commonjs", "nw.gui").apply(compiler);
  162. }
  163. new ChunkPrefetchPreloadPlugin().apply(compiler);
  164. if (typeof options.output.chunkFormat === "string") {
  165. switch (options.output.chunkFormat) {
  166. case "array-push": {
  167. const ArrayPushCallbackChunkFormatPlugin = require("./javascript/ArrayPushCallbackChunkFormatPlugin");
  168. new ArrayPushCallbackChunkFormatPlugin().apply(compiler);
  169. break;
  170. }
  171. case "commonjs": {
  172. const CommonJsChunkFormatPlugin = require("./javascript/CommonJsChunkFormatPlugin");
  173. new CommonJsChunkFormatPlugin().apply(compiler);
  174. break;
  175. }
  176. case "module": {
  177. const ModuleChunkFormatPlugin = require("./esm/ModuleChunkFormatPlugin");
  178. new ModuleChunkFormatPlugin().apply(compiler);
  179. break;
  180. }
  181. default:
  182. throw new Error(
  183. `Unsupported chunk format '${options.output.chunkFormat}'.`
  184. );
  185. }
  186. }
  187. const enabledChunkLoadingTypes =
  188. /** @type {NonNullable<WebpackOptions["output"]["enabledChunkLoadingTypes"]>} */
  189. (options.output.enabledChunkLoadingTypes);
  190. if (enabledChunkLoadingTypes.length > 0) {
  191. for (const type of enabledChunkLoadingTypes) {
  192. const EnableChunkLoadingPlugin = require("./javascript/EnableChunkLoadingPlugin");
  193. new EnableChunkLoadingPlugin(type).apply(compiler);
  194. }
  195. }
  196. const enabledWasmLoadingTypes =
  197. /** @type {NonNullable<WebpackOptions["output"]["enabledWasmLoadingTypes"]>} */
  198. (options.output.enabledWasmLoadingTypes);
  199. if (enabledWasmLoadingTypes.length > 0) {
  200. for (const type of enabledWasmLoadingTypes) {
  201. const EnableWasmLoadingPlugin = require("./wasm/EnableWasmLoadingPlugin");
  202. new EnableWasmLoadingPlugin(type).apply(compiler);
  203. }
  204. }
  205. const enabledLibraryTypes =
  206. /** @type {NonNullable<WebpackOptions["output"]["enabledLibraryTypes"]>} */
  207. (options.output.enabledLibraryTypes);
  208. if (enabledLibraryTypes.length > 0) {
  209. let once = true;
  210. for (const type of enabledLibraryTypes) {
  211. const EnableLibraryPlugin = require("./library/EnableLibraryPlugin");
  212. new EnableLibraryPlugin(type, {
  213. // eslint-disable-next-line no-loop-func
  214. additionalApply: () => {
  215. if (!once) return;
  216. once = false;
  217. // We rely on `exportInfo` to generate the `export statement` in certain library bundles.
  218. // Therefore, we ignore the disabling of `optimization.providedExport` and continue to apply `FlagDependencyExportsPlugin`.
  219. if (
  220. ["module", "commonjs-static", "modern-module"].includes(type) &&
  221. !options.optimization.providedExports
  222. ) {
  223. new FlagDependencyExportsPlugin().apply(compiler);
  224. }
  225. }
  226. }).apply(compiler);
  227. }
  228. }
  229. if (options.output.pathinfo) {
  230. const ModuleInfoHeaderPlugin = require("./ModuleInfoHeaderPlugin");
  231. new ModuleInfoHeaderPlugin(options.output.pathinfo !== true).apply(
  232. compiler
  233. );
  234. }
  235. if (options.output.clean) {
  236. const CleanPlugin = require("./CleanPlugin");
  237. new CleanPlugin(
  238. options.output.clean === true ? {} : options.output.clean
  239. ).apply(compiler);
  240. }
  241. if (options.dotenv) {
  242. const DotenvPlugin = require("./DotenvPlugin");
  243. new DotenvPlugin(
  244. typeof options.dotenv === "boolean" ? {} : options.dotenv
  245. ).apply(compiler);
  246. }
  247. if (options.devtool) {
  248. if (options.devtool.includes("source-map")) {
  249. const hidden = options.devtool.includes("hidden");
  250. const inline = options.devtool.includes("inline");
  251. const evalWrapped = options.devtool.includes("eval");
  252. const cheap = options.devtool.includes("cheap");
  253. const moduleMaps = options.devtool.includes("module");
  254. const noSources = options.devtool.includes("nosources");
  255. const debugIds = options.devtool.includes("debugids");
  256. const Plugin = evalWrapped
  257. ? require("./EvalSourceMapDevToolPlugin")
  258. : require("./SourceMapDevToolPlugin");
  259. new Plugin({
  260. filename: inline ? null : options.output.sourceMapFilename,
  261. moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate,
  262. fallbackModuleFilenameTemplate:
  263. options.output.devtoolFallbackModuleFilenameTemplate,
  264. append: hidden ? false : undefined,
  265. module: moduleMaps ? true : !cheap,
  266. columns: !cheap,
  267. noSources,
  268. namespace: options.output.devtoolNamespace,
  269. debugIds
  270. }).apply(compiler);
  271. } else if (options.devtool.includes("eval")) {
  272. const EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin");
  273. new EvalDevToolModulePlugin({
  274. moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate,
  275. namespace: options.output.devtoolNamespace
  276. }).apply(compiler);
  277. }
  278. }
  279. new JavascriptModulesPlugin().apply(compiler);
  280. new JsonModulesPlugin().apply(compiler);
  281. new AssetModulesPlugin().apply(compiler);
  282. if (!options.experiments.outputModule) {
  283. if (options.output.module) {
  284. throw new Error(
  285. "'output.module: true' is only allowed when 'experiments.outputModule' is enabled"
  286. );
  287. }
  288. if (options.output.enabledLibraryTypes.includes("module")) {
  289. throw new Error(
  290. "library type \"module\" is only allowed when 'experiments.outputModule' is enabled"
  291. );
  292. }
  293. if (options.output.enabledLibraryTypes.includes("modern-module")) {
  294. throw new Error(
  295. "library type \"modern-module\" is only allowed when 'experiments.outputModule' is enabled"
  296. );
  297. }
  298. if (
  299. options.externalsType === "module" ||
  300. options.externalsType === "module-import"
  301. ) {
  302. throw new Error(
  303. "'externalsType: \"module\"' is only allowed when 'experiments.outputModule' is enabled"
  304. );
  305. }
  306. }
  307. if (options.experiments.syncWebAssembly) {
  308. const WebAssemblyModulesPlugin = require("./wasm-sync/WebAssemblyModulesPlugin");
  309. new WebAssemblyModulesPlugin({
  310. mangleImports: options.optimization.mangleWasmImports
  311. }).apply(compiler);
  312. }
  313. if (options.experiments.asyncWebAssembly) {
  314. const AsyncWebAssemblyModulesPlugin = require("./wasm-async/AsyncWebAssemblyModulesPlugin");
  315. new AsyncWebAssemblyModulesPlugin({
  316. mangleImports: options.optimization.mangleWasmImports
  317. }).apply(compiler);
  318. }
  319. if (options.experiments.css) {
  320. const CssModulesPlugin = require("./css/CssModulesPlugin");
  321. new CssModulesPlugin().apply(compiler);
  322. }
  323. if (options.experiments.lazyCompilation) {
  324. const LazyCompilationPlugin = require("./hmr/LazyCompilationPlugin");
  325. const lazyOptions =
  326. typeof options.experiments.lazyCompilation === "object"
  327. ? options.experiments.lazyCompilation
  328. : {};
  329. const isUniversalTarget =
  330. options.output.module &&
  331. compiler.platform.node === null &&
  332. compiler.platform.web === null;
  333. if (isUniversalTarget) {
  334. const emitter = require.resolve("../hot/emitter-event-target.js");
  335. const NormalModuleReplacementPlugin = require("./NormalModuleReplacementPlugin");
  336. // Override emitter that using `EventEmitter` to `EventTarget`
  337. // TODO webpack6 - migrate to `EventTarget` by default
  338. new NormalModuleReplacementPlugin(/emitter(\.js)?$/, (result) => {
  339. if (
  340. /webpack[/\\]hot|webpack-dev-server[/\\]client|webpack-hot-middleware[/\\]client/.test(
  341. result.context
  342. )
  343. ) {
  344. result.request = emitter;
  345. }
  346. return result;
  347. }).apply(compiler);
  348. }
  349. const backend = require.resolve(
  350. isUniversalTarget
  351. ? "../hot/lazy-compilation-universal.js"
  352. : `../hot/lazy-compilation-${
  353. options.externalsPresets.node ? "node" : "web"
  354. }.js`
  355. );
  356. new LazyCompilationPlugin({
  357. backend:
  358. typeof lazyOptions.backend === "function"
  359. ? lazyOptions.backend
  360. : require("./hmr/lazyCompilationBackend")({
  361. ...lazyOptions.backend,
  362. client:
  363. (lazyOptions.backend && lazyOptions.backend.client) || backend
  364. }),
  365. entries: !lazyOptions || lazyOptions.entries !== false,
  366. imports: !lazyOptions || lazyOptions.imports !== false,
  367. test: (lazyOptions && lazyOptions.test) || undefined
  368. }).apply(compiler);
  369. }
  370. if (options.experiments.buildHttp) {
  371. const HttpUriPlugin = require("./schemes/HttpUriPlugin");
  372. const httpOptions = options.experiments.buildHttp;
  373. new HttpUriPlugin(httpOptions).apply(compiler);
  374. }
  375. if (options.experiments.deferImport) {
  376. const JavascriptParser = require("./javascript/JavascriptParser");
  377. const importPhases = require("acorn-import-phases");
  378. JavascriptParser.extend(importPhases({ source: false }));
  379. }
  380. new EntryOptionPlugin().apply(compiler);
  381. compiler.hooks.entryOption.call(options.context, options.entry);
  382. new RuntimePlugin().apply(compiler);
  383. new InferAsyncModulesPlugin().apply(compiler);
  384. new DataUriPlugin().apply(compiler);
  385. new FileUriPlugin().apply(compiler);
  386. new CompatibilityPlugin().apply(compiler);
  387. new HarmonyModulesPlugin({
  388. deferImport: options.experiments.deferImport
  389. }).apply(compiler);
  390. if (options.amd !== false) {
  391. const AMDPlugin = require("./dependencies/AMDPlugin");
  392. const RequireJsStuffPlugin = require("./RequireJsStuffPlugin");
  393. new AMDPlugin(options.amd || {}).apply(compiler);
  394. new RequireJsStuffPlugin().apply(compiler);
  395. }
  396. new CommonJsPlugin().apply(compiler);
  397. new LoaderPlugin().apply(compiler);
  398. new NodeStuffPlugin({
  399. global: options.node ? options.node.global : false,
  400. __dirname: options.node ? options.node.__dirname : false,
  401. __filename: options.node ? options.node.__filename : false
  402. }).apply(compiler);
  403. new APIPlugin().apply(compiler);
  404. new ExportsInfoApiPlugin().apply(compiler);
  405. new WebpackIsIncludedPlugin().apply(compiler);
  406. new ConstPlugin().apply(compiler);
  407. new UseStrictPlugin().apply(compiler);
  408. new RequireIncludePlugin().apply(compiler);
  409. new RequireEnsurePlugin().apply(compiler);
  410. new RequireContextPlugin().apply(compiler);
  411. new ImportPlugin().apply(compiler);
  412. new ImportMetaContextPlugin().apply(compiler);
  413. new SystemPlugin().apply(compiler);
  414. new ImportMetaPlugin().apply(compiler);
  415. new URLPlugin().apply(compiler);
  416. new WorkerPlugin(
  417. options.output.workerChunkLoading,
  418. options.output.workerWasmLoading,
  419. options.output.module,
  420. options.output.workerPublicPath
  421. ).apply(compiler);
  422. new DefaultStatsFactoryPlugin().apply(compiler);
  423. new DefaultStatsPresetPlugin().apply(compiler);
  424. new DefaultStatsPrinterPlugin().apply(compiler);
  425. new JavascriptMetaInfoPlugin().apply(compiler);
  426. if (typeof options.mode !== "string") {
  427. const WarnNoModeSetPlugin = require("./WarnNoModeSetPlugin");
  428. new WarnNoModeSetPlugin().apply(compiler);
  429. }
  430. const EnsureChunkConditionsPlugin = require("./optimize/EnsureChunkConditionsPlugin");
  431. new EnsureChunkConditionsPlugin().apply(compiler);
  432. if (options.optimization.removeAvailableModules) {
  433. const RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
  434. new RemoveParentModulesPlugin().apply(compiler);
  435. }
  436. if (options.optimization.removeEmptyChunks) {
  437. const RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
  438. new RemoveEmptyChunksPlugin().apply(compiler);
  439. }
  440. if (options.optimization.mergeDuplicateChunks) {
  441. const MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin");
  442. new MergeDuplicateChunksPlugin().apply(compiler);
  443. }
  444. if (options.optimization.flagIncludedChunks) {
  445. const FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin");
  446. new FlagIncludedChunksPlugin().apply(compiler);
  447. }
  448. if (options.optimization.sideEffects) {
  449. const SideEffectsFlagPlugin = require("./optimize/SideEffectsFlagPlugin");
  450. new SideEffectsFlagPlugin(
  451. options.optimization.sideEffects === true
  452. ).apply(compiler);
  453. }
  454. if (options.optimization.providedExports) {
  455. new FlagDependencyExportsPlugin().apply(compiler);
  456. }
  457. if (options.optimization.usedExports) {
  458. const FlagDependencyUsagePlugin = require("./FlagDependencyUsagePlugin");
  459. new FlagDependencyUsagePlugin(
  460. options.optimization.usedExports === "global"
  461. ).apply(compiler);
  462. }
  463. if (options.optimization.innerGraph) {
  464. const InnerGraphPlugin = require("./optimize/InnerGraphPlugin");
  465. new InnerGraphPlugin().apply(compiler);
  466. }
  467. if (options.optimization.mangleExports) {
  468. const MangleExportsPlugin = require("./optimize/MangleExportsPlugin");
  469. new MangleExportsPlugin(
  470. options.optimization.mangleExports !== "size"
  471. ).apply(compiler);
  472. }
  473. if (options.optimization.concatenateModules) {
  474. const ModuleConcatenationPlugin = require("./optimize/ModuleConcatenationPlugin");
  475. new ModuleConcatenationPlugin().apply(compiler);
  476. }
  477. if (options.optimization.splitChunks) {
  478. const SplitChunksPlugin = require("./optimize/SplitChunksPlugin");
  479. new SplitChunksPlugin(options.optimization.splitChunks).apply(compiler);
  480. }
  481. if (options.optimization.runtimeChunk) {
  482. const RuntimeChunkPlugin = require("./optimize/RuntimeChunkPlugin");
  483. new RuntimeChunkPlugin(options.optimization.runtimeChunk).apply(compiler);
  484. }
  485. if (!options.optimization.emitOnErrors) {
  486. const NoEmitOnErrorsPlugin = require("./NoEmitOnErrorsPlugin");
  487. new NoEmitOnErrorsPlugin().apply(compiler);
  488. }
  489. if (options.optimization.realContentHash) {
  490. const RealContentHashPlugin = require("./optimize/RealContentHashPlugin");
  491. new RealContentHashPlugin({
  492. hashFunction:
  493. /** @type {NonNullable<WebpackOptions["output"]["hashFunction"]>} */
  494. (options.output.hashFunction),
  495. hashDigest:
  496. /** @type {NonNullable<WebpackOptions["output"]["hashDigest"]>} */
  497. (options.output.hashDigest)
  498. }).apply(compiler);
  499. }
  500. if (options.optimization.checkWasmTypes) {
  501. const WasmFinalizeExportsPlugin = require("./wasm-sync/WasmFinalizeExportsPlugin");
  502. new WasmFinalizeExportsPlugin().apply(compiler);
  503. }
  504. const moduleIds = options.optimization.moduleIds;
  505. if (moduleIds) {
  506. switch (moduleIds) {
  507. case "natural": {
  508. const NaturalModuleIdsPlugin = require("./ids/NaturalModuleIdsPlugin");
  509. new NaturalModuleIdsPlugin().apply(compiler);
  510. break;
  511. }
  512. case "named": {
  513. const NamedModuleIdsPlugin = require("./ids/NamedModuleIdsPlugin");
  514. new NamedModuleIdsPlugin().apply(compiler);
  515. break;
  516. }
  517. case "hashed": {
  518. const WarnDeprecatedOptionPlugin = require("./WarnDeprecatedOptionPlugin");
  519. const HashedModuleIdsPlugin = require("./ids/HashedModuleIdsPlugin");
  520. new WarnDeprecatedOptionPlugin(
  521. "optimization.moduleIds",
  522. "hashed",
  523. "deterministic"
  524. ).apply(compiler);
  525. new HashedModuleIdsPlugin({
  526. hashFunction: options.output.hashFunction
  527. }).apply(compiler);
  528. break;
  529. }
  530. case "deterministic": {
  531. const DeterministicModuleIdsPlugin = require("./ids/DeterministicModuleIdsPlugin");
  532. new DeterministicModuleIdsPlugin().apply(compiler);
  533. break;
  534. }
  535. case "size": {
  536. const OccurrenceModuleIdsPlugin = require("./ids/OccurrenceModuleIdsPlugin");
  537. new OccurrenceModuleIdsPlugin({
  538. prioritiseInitial: true
  539. }).apply(compiler);
  540. break;
  541. }
  542. default:
  543. throw new Error(
  544. `webpack bug: moduleIds: ${moduleIds} is not implemented`
  545. );
  546. }
  547. }
  548. const chunkIds = options.optimization.chunkIds;
  549. if (chunkIds) {
  550. switch (chunkIds) {
  551. case "natural": {
  552. const NaturalChunkIdsPlugin = require("./ids/NaturalChunkIdsPlugin");
  553. new NaturalChunkIdsPlugin().apply(compiler);
  554. break;
  555. }
  556. case "named": {
  557. const NamedChunkIdsPlugin = require("./ids/NamedChunkIdsPlugin");
  558. new NamedChunkIdsPlugin().apply(compiler);
  559. break;
  560. }
  561. case "deterministic": {
  562. const DeterministicChunkIdsPlugin = require("./ids/DeterministicChunkIdsPlugin");
  563. new DeterministicChunkIdsPlugin().apply(compiler);
  564. break;
  565. }
  566. case "size": {
  567. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  568. const OccurrenceChunkIdsPlugin = require("./ids/OccurrenceChunkIdsPlugin");
  569. new OccurrenceChunkIdsPlugin({
  570. prioritiseInitial: true
  571. }).apply(compiler);
  572. break;
  573. }
  574. case "total-size": {
  575. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  576. const OccurrenceChunkIdsPlugin = require("./ids/OccurrenceChunkIdsPlugin");
  577. new OccurrenceChunkIdsPlugin({
  578. prioritiseInitial: false
  579. }).apply(compiler);
  580. break;
  581. }
  582. default:
  583. throw new Error(
  584. `webpack bug: chunkIds: ${chunkIds} is not implemented`
  585. );
  586. }
  587. }
  588. if (options.optimization.nodeEnv) {
  589. const DefinePlugin = require("./DefinePlugin");
  590. const defValue = JSON.stringify(options.optimization.nodeEnv);
  591. new DefinePlugin({
  592. "process.env.NODE_ENV": defValue,
  593. "import.meta.env.NODE_ENV": defValue
  594. }).apply(compiler);
  595. }
  596. if (options.optimization.minimize) {
  597. for (const minimizer of options.optimization.minimizer) {
  598. if (typeof minimizer === "function") {
  599. /** @type {WebpackPluginFunction} */
  600. (minimizer).call(compiler, compiler);
  601. } else if (minimizer !== "..." && minimizer) {
  602. minimizer.apply(compiler);
  603. }
  604. }
  605. }
  606. if (options.performance) {
  607. const SizeLimitsPlugin = require("./performance/SizeLimitsPlugin");
  608. new SizeLimitsPlugin(options.performance).apply(compiler);
  609. }
  610. new TemplatedPathPlugin().apply(compiler);
  611. new RecordIdsPlugin({
  612. portableIds: options.optimization.portableRecords
  613. }).apply(compiler);
  614. new WarnCaseSensitiveModulesPlugin().apply(compiler);
  615. const AddManagedPathsPlugin = require("./cache/AddManagedPathsPlugin");
  616. new AddManagedPathsPlugin(
  617. /** @type {NonNullable<WebpackOptions["snapshot"]["managedPaths"]>} */
  618. (options.snapshot.managedPaths),
  619. /** @type {NonNullable<WebpackOptions["snapshot"]["managedPaths"]>} */
  620. (options.snapshot.immutablePaths),
  621. /** @type {NonNullable<WebpackOptions["snapshot"]["managedPaths"]>} */
  622. (options.snapshot.unmanagedPaths)
  623. ).apply(compiler);
  624. if (options.cache && typeof options.cache === "object") {
  625. const cacheOptions = options.cache;
  626. switch (cacheOptions.type) {
  627. case "memory": {
  628. if (Number.isFinite(cacheOptions.maxGenerations)) {
  629. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  630. const MemoryWithGcCachePlugin = require("./cache/MemoryWithGcCachePlugin");
  631. new MemoryWithGcCachePlugin({
  632. maxGenerations:
  633. /** @type {number} */
  634. (cacheOptions.maxGenerations)
  635. }).apply(compiler);
  636. } else {
  637. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  638. const MemoryCachePlugin = require("./cache/MemoryCachePlugin");
  639. new MemoryCachePlugin().apply(compiler);
  640. }
  641. if (cacheOptions.cacheUnaffected) {
  642. if (!options.experiments.cacheUnaffected) {
  643. throw new Error(
  644. "'cache.cacheUnaffected: true' is only allowed when 'experiments.cacheUnaffected' is enabled"
  645. );
  646. }
  647. compiler.moduleMemCaches = new Map();
  648. }
  649. break;
  650. }
  651. case "filesystem": {
  652. const AddBuildDependenciesPlugin = require("./cache/AddBuildDependenciesPlugin");
  653. for (const key in cacheOptions.buildDependencies) {
  654. const list = cacheOptions.buildDependencies[key];
  655. new AddBuildDependenciesPlugin(list).apply(compiler);
  656. }
  657. if (!Number.isFinite(cacheOptions.maxMemoryGenerations)) {
  658. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  659. const MemoryCachePlugin = require("./cache/MemoryCachePlugin");
  660. new MemoryCachePlugin().apply(compiler);
  661. } else if (cacheOptions.maxMemoryGenerations !== 0) {
  662. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  663. const MemoryWithGcCachePlugin = require("./cache/MemoryWithGcCachePlugin");
  664. new MemoryWithGcCachePlugin({
  665. maxGenerations:
  666. /** @type {number} */
  667. (cacheOptions.maxMemoryGenerations)
  668. }).apply(compiler);
  669. }
  670. if (cacheOptions.memoryCacheUnaffected) {
  671. if (!options.experiments.cacheUnaffected) {
  672. throw new Error(
  673. "'cache.memoryCacheUnaffected: true' is only allowed when 'experiments.cacheUnaffected' is enabled"
  674. );
  675. }
  676. compiler.moduleMemCaches = new Map();
  677. }
  678. switch (cacheOptions.store) {
  679. case "pack": {
  680. const IdleFileCachePlugin = require("./cache/IdleFileCachePlugin");
  681. const PackFileCacheStrategy = require("./cache/PackFileCacheStrategy");
  682. new IdleFileCachePlugin(
  683. new PackFileCacheStrategy({
  684. compiler,
  685. fs:
  686. /** @type {IntermediateFileSystem} */
  687. (compiler.intermediateFileSystem),
  688. context: options.context,
  689. cacheLocation:
  690. /** @type {string} */
  691. (cacheOptions.cacheLocation),
  692. version: /** @type {string} */ (cacheOptions.version),
  693. logger: compiler.getInfrastructureLogger(
  694. "webpack.cache.PackFileCacheStrategy"
  695. ),
  696. snapshot: options.snapshot,
  697. maxAge: /** @type {number} */ (cacheOptions.maxAge),
  698. profile: cacheOptions.profile,
  699. allowCollectingMemory: cacheOptions.allowCollectingMemory,
  700. compression: cacheOptions.compression,
  701. readonly: cacheOptions.readonly
  702. }),
  703. /** @type {number} */
  704. (cacheOptions.idleTimeout),
  705. /** @type {number} */
  706. (cacheOptions.idleTimeoutForInitialStore),
  707. /** @type {number} */
  708. (cacheOptions.idleTimeoutAfterLargeChanges)
  709. ).apply(compiler);
  710. break;
  711. }
  712. default:
  713. throw new Error("Unhandled value for cache.store");
  714. }
  715. break;
  716. }
  717. default:
  718. // @ts-expect-error Property 'type' does not exist on type 'never'. ts(2339)
  719. throw new Error(`Unknown cache type ${cacheOptions.type}`);
  720. }
  721. }
  722. new ResolverCachePlugin().apply(compiler);
  723. if (options.ignoreWarnings && options.ignoreWarnings.length > 0) {
  724. const IgnoreWarningsPlugin = require("./IgnoreWarningsPlugin");
  725. new IgnoreWarningsPlugin(options.ignoreWarnings).apply(compiler);
  726. }
  727. compiler.hooks.afterPlugins.call(compiler);
  728. if (!compiler.inputFileSystem) {
  729. throw new Error("No input filesystem provided");
  730. }
  731. compiler.resolverFactory.hooks.resolveOptions
  732. .for("normal")
  733. .tap(CLASS_NAME, (resolveOptions) => {
  734. resolveOptions = cleverMerge(options.resolve, resolveOptions);
  735. resolveOptions.fileSystem =
  736. /** @type {InputFileSystem} */
  737. (compiler.inputFileSystem);
  738. return resolveOptions;
  739. });
  740. compiler.resolverFactory.hooks.resolveOptions
  741. .for("context")
  742. .tap(CLASS_NAME, (resolveOptions) => {
  743. resolveOptions = cleverMerge(options.resolve, resolveOptions);
  744. resolveOptions.fileSystem =
  745. /** @type {InputFileSystem} */
  746. (compiler.inputFileSystem);
  747. resolveOptions.resolveToContext = true;
  748. return resolveOptions;
  749. });
  750. compiler.resolverFactory.hooks.resolveOptions
  751. .for("loader")
  752. .tap(CLASS_NAME, (resolveOptions) => {
  753. resolveOptions = cleverMerge(options.resolveLoader, resolveOptions);
  754. resolveOptions.fileSystem =
  755. /** @type {InputFileSystem} */
  756. (compiler.inputFileSystem);
  757. return resolveOptions;
  758. });
  759. compiler.hooks.afterResolvers.call(compiler);
  760. return options;
  761. }
  762. }
  763. module.exports = WebpackOptionsApply;