WebpackOptionsApply.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  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 JavascriptParser = require("./javascript/JavascriptParser");
  38. const JsonModulesPlugin = require("./json/JsonModulesPlugin");
  39. const ChunkPrefetchPreloadPlugin = require("./prefetch/ChunkPrefetchPreloadPlugin");
  40. const DataUriPlugin = require("./schemes/DataUriPlugin");
  41. const FileUriPlugin = require("./schemes/FileUriPlugin");
  42. const DefaultStatsFactoryPlugin = require("./stats/DefaultStatsFactoryPlugin");
  43. const DefaultStatsPresetPlugin = require("./stats/DefaultStatsPresetPlugin");
  44. const DefaultStatsPrinterPlugin = require("./stats/DefaultStatsPrinterPlugin");
  45. const { cleverMerge } = require("./util/cleverMerge");
  46. /** @typedef {import("./webpack").WebpackPluginFunction} WebpackPluginFunction */
  47. /** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
  48. /** @typedef {import("./config/normalization").WebpackOptionsInterception} WebpackOptionsInterception */
  49. /** @typedef {import("./Compiler")} Compiler */
  50. /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
  51. /** @typedef {import("./util/fs").IntermediateFileSystem} IntermediateFileSystem */
  52. const CLASS_NAME = "WebpackOptionsApply";
  53. class WebpackOptionsApply extends OptionsApply {
  54. constructor() {
  55. super();
  56. }
  57. /**
  58. * Returns options object.
  59. * @param {WebpackOptions} options options object
  60. * @param {Compiler} compiler compiler object
  61. * @param {WebpackOptionsInterception=} interception intercepted options
  62. * @returns {WebpackOptions} options object
  63. */
  64. process(options, compiler, interception) {
  65. compiler.outputPath = options.output.path;
  66. compiler.recordsInputPath = options.recordsInputPath || null;
  67. compiler.recordsOutputPath = options.recordsOutputPath || null;
  68. compiler.name = options.name;
  69. if (options.externals) {
  70. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  71. const ExternalsPlugin = require("./ExternalsPlugin");
  72. new ExternalsPlugin(options.externalsType, options.externals).apply(
  73. compiler
  74. );
  75. }
  76. if (options.externalsPresets.node) {
  77. const NodeTargetPlugin = require("./node/NodeTargetPlugin");
  78. // Some older versions of Node.js don't support all built-in modules via import, only via `require`,
  79. // but it seems like there shouldn't be a warning here since these versions are rarely used in real applications
  80. new NodeTargetPlugin(
  81. options.output.module ? "module-import" : "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. let devtool =
  248. interception === undefined ? options.devtool : interception.devtool;
  249. devtool = Array.isArray(devtool)
  250. ? devtool
  251. : typeof devtool === "string"
  252. ? [{ type: "all", use: devtool }]
  253. : [];
  254. for (const item of devtool) {
  255. const { type, use } = item;
  256. if (use) {
  257. if (use.includes("source-map")) {
  258. const hidden = use.includes("hidden");
  259. const inline = use.includes("inline");
  260. const evalWrapped = use.includes("eval");
  261. const cheap = use.includes("cheap");
  262. const moduleMaps = use.includes("module");
  263. const noSources = use.includes("nosources");
  264. const debugIds = use.includes("debugids");
  265. const Plugin = evalWrapped
  266. ? require("./EvalSourceMapDevToolPlugin")
  267. : require("./SourceMapDevToolPlugin");
  268. const assetExt =
  269. type === "javascript"
  270. ? /\.((c|m)?js)($|\?)/i
  271. : type === "css"
  272. ? /\.(css)($|\?)/i
  273. : /\.((c|m)?js|css)($|\?)/i;
  274. new Plugin({
  275. test: evalWrapped ? undefined : assetExt,
  276. filename: inline ? null : options.output.sourceMapFilename,
  277. moduleFilenameTemplate:
  278. options.output.devtoolModuleFilenameTemplate,
  279. fallbackModuleFilenameTemplate:
  280. options.output.devtoolFallbackModuleFilenameTemplate,
  281. append: hidden ? false : undefined,
  282. module: moduleMaps ? true : !cheap,
  283. columns: !cheap,
  284. noSources,
  285. namespace: options.output.devtoolNamespace,
  286. debugIds
  287. }).apply(compiler);
  288. } else if (use.includes("eval")) {
  289. const EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin");
  290. new EvalDevToolModulePlugin({
  291. moduleFilenameTemplate:
  292. options.output.devtoolModuleFilenameTemplate,
  293. namespace: options.output.devtoolNamespace
  294. }).apply(compiler);
  295. }
  296. }
  297. }
  298. new JavascriptModulesPlugin().apply(compiler);
  299. new JsonModulesPlugin().apply(compiler);
  300. new AssetModulesPlugin({
  301. sideEffectFree: options.experiments.futureDefaults
  302. }).apply(compiler);
  303. if (!options.experiments.outputModule) {
  304. if (options.output.module) {
  305. throw new Error(
  306. "'output.module: true' is only allowed when 'experiments.outputModule' is enabled"
  307. );
  308. }
  309. if (options.output.enabledLibraryTypes.includes("module")) {
  310. throw new Error(
  311. "library type \"module\" is only allowed when 'experiments.outputModule' is enabled"
  312. );
  313. }
  314. if (options.output.enabledLibraryTypes.includes("modern-module")) {
  315. throw new Error(
  316. "library type \"modern-module\" is only allowed when 'experiments.outputModule' is enabled"
  317. );
  318. }
  319. if (
  320. options.externalsType === "module" ||
  321. options.externalsType === "module-import"
  322. ) {
  323. throw new Error(
  324. "'externalsType: \"module\"' is only allowed when 'experiments.outputModule' is enabled"
  325. );
  326. }
  327. }
  328. if (options.experiments.syncWebAssembly) {
  329. const WebAssemblyModulesPlugin = require("./wasm-sync/WebAssemblyModulesPlugin");
  330. new WebAssemblyModulesPlugin({
  331. mangleImports: options.optimization.mangleWasmImports
  332. }).apply(compiler);
  333. }
  334. if (options.experiments.asyncWebAssembly) {
  335. const AsyncWebAssemblyModulesPlugin = require("./wasm-async/AsyncWebAssemblyModulesPlugin");
  336. new AsyncWebAssemblyModulesPlugin({
  337. mangleImports: options.optimization.mangleWasmImports
  338. }).apply(compiler);
  339. }
  340. if (options.experiments.css) {
  341. const CssModulesPlugin = require("./css/CssModulesPlugin");
  342. new CssModulesPlugin().apply(compiler);
  343. }
  344. if (options.experiments.lazyCompilation) {
  345. const LazyCompilationPlugin = require("./hmr/LazyCompilationPlugin");
  346. const lazyOptions =
  347. typeof options.experiments.lazyCompilation === "object"
  348. ? options.experiments.lazyCompilation
  349. : {};
  350. const isUniversalTarget =
  351. options.output.module &&
  352. compiler.platform.node === null &&
  353. compiler.platform.web === null;
  354. if (isUniversalTarget) {
  355. const emitter = require.resolve("../hot/emitter-event-target.js");
  356. const NormalModuleReplacementPlugin = require("./NormalModuleReplacementPlugin");
  357. // Override emitter that using `EventEmitter` to `EventTarget`
  358. // TODO webpack 6 - migrate to `EventTarget` by default
  359. new NormalModuleReplacementPlugin(/emitter(\.js)?$/, (result) => {
  360. if (
  361. /webpack[/\\]hot|webpack-dev-server[/\\]client|webpack-hot-middleware[/\\]client/.test(
  362. result.context
  363. )
  364. ) {
  365. result.request = emitter;
  366. }
  367. return result;
  368. }).apply(compiler);
  369. }
  370. const backend = require.resolve(
  371. isUniversalTarget
  372. ? "../hot/lazy-compilation-universal.js"
  373. : `../hot/lazy-compilation-${
  374. options.externalsPresets.node ? "node" : "web"
  375. }.js`
  376. );
  377. new LazyCompilationPlugin({
  378. backend:
  379. typeof lazyOptions.backend === "function"
  380. ? lazyOptions.backend
  381. : require("./hmr/lazyCompilationBackend")({
  382. ...lazyOptions.backend,
  383. client:
  384. (lazyOptions.backend && lazyOptions.backend.client) || backend
  385. }),
  386. entries: !lazyOptions || lazyOptions.entries !== false,
  387. imports: !lazyOptions || lazyOptions.imports !== false,
  388. test: (lazyOptions && lazyOptions.test) || undefined
  389. }).apply(compiler);
  390. }
  391. if (options.experiments.buildHttp) {
  392. const HttpUriPlugin = require("./schemes/HttpUriPlugin");
  393. const httpOptions = options.experiments.buildHttp;
  394. new HttpUriPlugin(httpOptions).apply(compiler);
  395. }
  396. if (
  397. !(
  398. /** @type {typeof JavascriptParser & { __importPhasesExtended?: true }} */
  399. (JavascriptParser).__importPhasesExtended
  400. ) &&
  401. (options.experiments.deferImport || options.experiments.sourceImport)
  402. ) {
  403. const importPhases = require("acorn-import-phases");
  404. JavascriptParser.extend(importPhases({ source: true, defer: true }));
  405. /** @type {typeof JavascriptParser & { __importPhasesExtended?: true }} */
  406. (JavascriptParser).__importPhasesExtended = true;
  407. }
  408. new EntryOptionPlugin().apply(compiler);
  409. compiler.hooks.entryOption.call(options.context, options.entry);
  410. new RuntimePlugin().apply(compiler);
  411. new InferAsyncModulesPlugin().apply(compiler);
  412. new DataUriPlugin().apply(compiler);
  413. new FileUriPlugin().apply(compiler);
  414. new CompatibilityPlugin().apply(compiler);
  415. new HarmonyModulesPlugin({
  416. deferImport: options.experiments.deferImport
  417. }).apply(compiler);
  418. if (options.amd !== false) {
  419. const AMDPlugin = require("./dependencies/AMDPlugin");
  420. const RequireJsStuffPlugin = require("./RequireJsStuffPlugin");
  421. new AMDPlugin(options.amd || {}).apply(compiler);
  422. new RequireJsStuffPlugin().apply(compiler);
  423. }
  424. new CommonJsPlugin().apply(compiler);
  425. new LoaderPlugin().apply(compiler);
  426. new NodeStuffPlugin({
  427. global: options.node ? options.node.global : false,
  428. __dirname: options.node ? options.node.__dirname : false,
  429. __filename: options.node ? options.node.__filename : false
  430. }).apply(compiler);
  431. new APIPlugin().apply(compiler);
  432. new ExportsInfoApiPlugin().apply(compiler);
  433. new WebpackIsIncludedPlugin().apply(compiler);
  434. new ConstPlugin().apply(compiler);
  435. new UseStrictPlugin().apply(compiler);
  436. new RequireIncludePlugin().apply(compiler);
  437. new RequireEnsurePlugin().apply(compiler);
  438. new RequireContextPlugin().apply(compiler);
  439. new ImportPlugin().apply(compiler);
  440. new ImportMetaContextPlugin().apply(compiler);
  441. new SystemPlugin().apply(compiler);
  442. new ImportMetaPlugin().apply(compiler);
  443. new URLPlugin().apply(compiler);
  444. new WorkerPlugin(
  445. options.output.workerChunkLoading,
  446. options.output.workerWasmLoading,
  447. options.output.module,
  448. options.output.workerPublicPath
  449. ).apply(compiler);
  450. new DefaultStatsFactoryPlugin().apply(compiler);
  451. new DefaultStatsPresetPlugin().apply(compiler);
  452. new DefaultStatsPrinterPlugin().apply(compiler);
  453. new JavascriptMetaInfoPlugin().apply(compiler);
  454. if (typeof options.mode !== "string") {
  455. const WarnNoModeSetPlugin = require("./WarnNoModeSetPlugin");
  456. new WarnNoModeSetPlugin().apply(compiler);
  457. }
  458. const EnsureChunkConditionsPlugin = require("./optimize/EnsureChunkConditionsPlugin");
  459. new EnsureChunkConditionsPlugin().apply(compiler);
  460. if (options.optimization.removeAvailableModules) {
  461. const RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
  462. new RemoveParentModulesPlugin().apply(compiler);
  463. }
  464. if (options.optimization.removeEmptyChunks) {
  465. const RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
  466. new RemoveEmptyChunksPlugin().apply(compiler);
  467. }
  468. if (options.optimization.mergeDuplicateChunks) {
  469. const MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin");
  470. new MergeDuplicateChunksPlugin().apply(compiler);
  471. }
  472. if (options.optimization.flagIncludedChunks) {
  473. const FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin");
  474. new FlagIncludedChunksPlugin().apply(compiler);
  475. }
  476. if (options.optimization.sideEffects) {
  477. const SideEffectsFlagPlugin = require("./optimize/SideEffectsFlagPlugin");
  478. new SideEffectsFlagPlugin(
  479. options.optimization.sideEffects === true
  480. ).apply(compiler);
  481. }
  482. if (options.optimization.providedExports) {
  483. new FlagDependencyExportsPlugin().apply(compiler);
  484. }
  485. if (options.optimization.usedExports) {
  486. const FlagDependencyUsagePlugin = require("./FlagDependencyUsagePlugin");
  487. new FlagDependencyUsagePlugin(
  488. options.optimization.usedExports === "global"
  489. ).apply(compiler);
  490. }
  491. if (options.optimization.innerGraph) {
  492. const InnerGraphPlugin = require("./optimize/InnerGraphPlugin");
  493. new InnerGraphPlugin().apply(compiler);
  494. }
  495. if (options.optimization.mangleExports) {
  496. const MangleExportsPlugin = require("./optimize/MangleExportsPlugin");
  497. new MangleExportsPlugin(
  498. options.optimization.mangleExports !== "size"
  499. ).apply(compiler);
  500. }
  501. if (options.optimization.concatenateModules) {
  502. const ModuleConcatenationPlugin = require("./optimize/ModuleConcatenationPlugin");
  503. new ModuleConcatenationPlugin().apply(compiler);
  504. }
  505. if (options.optimization.splitChunks) {
  506. const SplitChunksPlugin = require("./optimize/SplitChunksPlugin");
  507. new SplitChunksPlugin(options.optimization.splitChunks).apply(compiler);
  508. }
  509. if (options.optimization.runtimeChunk) {
  510. const RuntimeChunkPlugin = require("./optimize/RuntimeChunkPlugin");
  511. new RuntimeChunkPlugin(options.optimization.runtimeChunk).apply(compiler);
  512. }
  513. if (!options.optimization.emitOnErrors) {
  514. const NoEmitOnErrorsPlugin = require("./NoEmitOnErrorsPlugin");
  515. new NoEmitOnErrorsPlugin().apply(compiler);
  516. }
  517. if (options.optimization.realContentHash) {
  518. const RealContentHashPlugin = require("./optimize/RealContentHashPlugin");
  519. new RealContentHashPlugin({
  520. hashFunction:
  521. /** @type {NonNullable<WebpackOptions["output"]["hashFunction"]>} */
  522. (options.output.hashFunction),
  523. hashDigest:
  524. /** @type {NonNullable<WebpackOptions["output"]["hashDigest"]>} */
  525. (options.output.hashDigest)
  526. }).apply(compiler);
  527. }
  528. if (options.optimization.checkWasmTypes) {
  529. const WasmFinalizeExportsPlugin = require("./wasm-sync/WasmFinalizeExportsPlugin");
  530. new WasmFinalizeExportsPlugin().apply(compiler);
  531. }
  532. const moduleIds = options.optimization.moduleIds;
  533. if (moduleIds) {
  534. switch (moduleIds) {
  535. case "natural": {
  536. const NaturalModuleIdsPlugin = require("./ids/NaturalModuleIdsPlugin");
  537. new NaturalModuleIdsPlugin().apply(compiler);
  538. break;
  539. }
  540. case "named": {
  541. const NamedModuleIdsPlugin = require("./ids/NamedModuleIdsPlugin");
  542. new NamedModuleIdsPlugin().apply(compiler);
  543. break;
  544. }
  545. case "hashed": {
  546. const WarnDeprecatedOptionPlugin = require("./WarnDeprecatedOptionPlugin");
  547. const HashedModuleIdsPlugin = require("./ids/HashedModuleIdsPlugin");
  548. new WarnDeprecatedOptionPlugin(
  549. "optimization.moduleIds",
  550. "hashed",
  551. "deterministic"
  552. ).apply(compiler);
  553. new HashedModuleIdsPlugin({
  554. hashFunction: options.output.hashFunction
  555. }).apply(compiler);
  556. break;
  557. }
  558. case "deterministic": {
  559. const DeterministicModuleIdsPlugin = require("./ids/DeterministicModuleIdsPlugin");
  560. new DeterministicModuleIdsPlugin().apply(compiler);
  561. break;
  562. }
  563. case "size": {
  564. const OccurrenceModuleIdsPlugin = require("./ids/OccurrenceModuleIdsPlugin");
  565. new OccurrenceModuleIdsPlugin({
  566. prioritiseInitial: true
  567. }).apply(compiler);
  568. break;
  569. }
  570. default:
  571. throw new Error(
  572. `webpack bug: moduleIds: ${moduleIds} is not implemented`
  573. );
  574. }
  575. }
  576. const chunkIds = options.optimization.chunkIds;
  577. if (chunkIds) {
  578. switch (chunkIds) {
  579. case "natural": {
  580. const NaturalChunkIdsPlugin = require("./ids/NaturalChunkIdsPlugin");
  581. new NaturalChunkIdsPlugin().apply(compiler);
  582. break;
  583. }
  584. case "named": {
  585. const NamedChunkIdsPlugin = require("./ids/NamedChunkIdsPlugin");
  586. new NamedChunkIdsPlugin().apply(compiler);
  587. break;
  588. }
  589. case "deterministic": {
  590. const DeterministicChunkIdsPlugin = require("./ids/DeterministicChunkIdsPlugin");
  591. new DeterministicChunkIdsPlugin().apply(compiler);
  592. break;
  593. }
  594. case "size": {
  595. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  596. const OccurrenceChunkIdsPlugin = require("./ids/OccurrenceChunkIdsPlugin");
  597. new OccurrenceChunkIdsPlugin({
  598. prioritiseInitial: true
  599. }).apply(compiler);
  600. break;
  601. }
  602. case "total-size": {
  603. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  604. const OccurrenceChunkIdsPlugin = require("./ids/OccurrenceChunkIdsPlugin");
  605. new OccurrenceChunkIdsPlugin({
  606. prioritiseInitial: false
  607. }).apply(compiler);
  608. break;
  609. }
  610. default:
  611. throw new Error(
  612. `webpack bug: chunkIds: ${chunkIds} is not implemented`
  613. );
  614. }
  615. }
  616. if (options.optimization.nodeEnv) {
  617. const DefinePlugin = require("./DefinePlugin");
  618. const defValue = JSON.stringify(options.optimization.nodeEnv);
  619. new DefinePlugin({
  620. "process.env.NODE_ENV": defValue,
  621. "import.meta.env.NODE_ENV": defValue
  622. }).apply(compiler);
  623. }
  624. if (options.optimization.minimize) {
  625. for (const minimizer of options.optimization.minimizer) {
  626. if (typeof minimizer === "function") {
  627. /** @type {WebpackPluginFunction} */
  628. (minimizer).call(compiler, compiler);
  629. } else if (minimizer !== "..." && minimizer) {
  630. minimizer.apply(compiler);
  631. }
  632. }
  633. }
  634. if (options.performance) {
  635. const SizeLimitsPlugin = require("./performance/SizeLimitsPlugin");
  636. new SizeLimitsPlugin(options.performance).apply(compiler);
  637. }
  638. new TemplatedPathPlugin().apply(compiler);
  639. new RecordIdsPlugin({
  640. portableIds: options.optimization.portableRecords
  641. }).apply(compiler);
  642. new WarnCaseSensitiveModulesPlugin().apply(compiler);
  643. const AddManagedPathsPlugin = require("./cache/AddManagedPathsPlugin");
  644. new AddManagedPathsPlugin(
  645. /** @type {NonNullable<WebpackOptions["snapshot"]["managedPaths"]>} */
  646. (options.snapshot.managedPaths),
  647. /** @type {NonNullable<WebpackOptions["snapshot"]["managedPaths"]>} */
  648. (options.snapshot.immutablePaths),
  649. /** @type {NonNullable<WebpackOptions["snapshot"]["managedPaths"]>} */
  650. (options.snapshot.unmanagedPaths)
  651. ).apply(compiler);
  652. if (options.cache && typeof options.cache === "object") {
  653. const cacheOptions = options.cache;
  654. switch (cacheOptions.type) {
  655. case "memory": {
  656. if (Number.isFinite(cacheOptions.maxGenerations)) {
  657. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  658. const MemoryWithGcCachePlugin = require("./cache/MemoryWithGcCachePlugin");
  659. new MemoryWithGcCachePlugin({
  660. maxGenerations:
  661. /** @type {number} */
  662. (cacheOptions.maxGenerations)
  663. }).apply(compiler);
  664. } else {
  665. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  666. const MemoryCachePlugin = require("./cache/MemoryCachePlugin");
  667. new MemoryCachePlugin().apply(compiler);
  668. }
  669. if (cacheOptions.cacheUnaffected) {
  670. if (!options.experiments.cacheUnaffected) {
  671. throw new Error(
  672. "'cache.cacheUnaffected: true' is only allowed when 'experiments.cacheUnaffected' is enabled"
  673. );
  674. }
  675. compiler.moduleMemCaches = new Map();
  676. }
  677. break;
  678. }
  679. case "filesystem": {
  680. const AddBuildDependenciesPlugin = require("./cache/AddBuildDependenciesPlugin");
  681. for (const key in cacheOptions.buildDependencies) {
  682. const list = cacheOptions.buildDependencies[key];
  683. new AddBuildDependenciesPlugin(list).apply(compiler);
  684. }
  685. if (!Number.isFinite(cacheOptions.maxMemoryGenerations)) {
  686. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  687. const MemoryCachePlugin = require("./cache/MemoryCachePlugin");
  688. new MemoryCachePlugin().apply(compiler);
  689. } else if (cacheOptions.maxMemoryGenerations !== 0) {
  690. // @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
  691. const MemoryWithGcCachePlugin = require("./cache/MemoryWithGcCachePlugin");
  692. new MemoryWithGcCachePlugin({
  693. maxGenerations:
  694. /** @type {number} */
  695. (cacheOptions.maxMemoryGenerations)
  696. }).apply(compiler);
  697. }
  698. if (cacheOptions.memoryCacheUnaffected) {
  699. if (!options.experiments.cacheUnaffected) {
  700. throw new Error(
  701. "'cache.memoryCacheUnaffected: true' is only allowed when 'experiments.cacheUnaffected' is enabled"
  702. );
  703. }
  704. compiler.moduleMemCaches = new Map();
  705. }
  706. switch (cacheOptions.store) {
  707. case "pack": {
  708. const IdleFileCachePlugin = require("./cache/IdleFileCachePlugin");
  709. const PackFileCacheStrategy = require("./cache/PackFileCacheStrategy");
  710. new IdleFileCachePlugin(
  711. new PackFileCacheStrategy({
  712. compiler,
  713. fs:
  714. /** @type {IntermediateFileSystem} */
  715. (compiler.intermediateFileSystem),
  716. context: options.context,
  717. cacheLocation:
  718. /** @type {string} */
  719. (cacheOptions.cacheLocation),
  720. version: /** @type {string} */ (cacheOptions.version),
  721. logger: compiler.getInfrastructureLogger(
  722. "webpack.cache.PackFileCacheStrategy"
  723. ),
  724. snapshot: options.snapshot,
  725. maxAge: /** @type {number} */ (cacheOptions.maxAge),
  726. profile: cacheOptions.profile,
  727. allowCollectingMemory: cacheOptions.allowCollectingMemory,
  728. compression: cacheOptions.compression,
  729. readonly: cacheOptions.readonly
  730. }),
  731. /** @type {number} */
  732. (cacheOptions.idleTimeout),
  733. /** @type {number} */
  734. (cacheOptions.idleTimeoutForInitialStore),
  735. /** @type {number} */
  736. (cacheOptions.idleTimeoutAfterLargeChanges)
  737. ).apply(compiler);
  738. break;
  739. }
  740. default:
  741. throw new Error("Unhandled value for cache.store");
  742. }
  743. break;
  744. }
  745. default:
  746. // @ts-expect-error Property 'type' does not exist on type 'never'. ts(2339)
  747. throw new Error(`Unknown cache type ${cacheOptions.type}`);
  748. }
  749. }
  750. new ResolverCachePlugin().apply(compiler);
  751. if (options.ignoreWarnings && options.ignoreWarnings.length > 0) {
  752. const IgnoreWarningsPlugin = require("./IgnoreWarningsPlugin");
  753. new IgnoreWarningsPlugin(options.ignoreWarnings).apply(compiler);
  754. }
  755. compiler.hooks.afterPlugins.call(compiler);
  756. if (!compiler.inputFileSystem) {
  757. throw new Error("No input filesystem provided");
  758. }
  759. compiler.resolverFactory.hooks.resolveOptions
  760. .for("normal")
  761. .tap(CLASS_NAME, (resolveOptions) => {
  762. resolveOptions = cleverMerge(options.resolve, resolveOptions);
  763. resolveOptions.fileSystem =
  764. /** @type {InputFileSystem} */
  765. (compiler.inputFileSystem);
  766. return resolveOptions;
  767. });
  768. compiler.resolverFactory.hooks.resolveOptions
  769. .for("context")
  770. .tap(CLASS_NAME, (resolveOptions) => {
  771. resolveOptions = cleverMerge(options.resolve, resolveOptions);
  772. resolveOptions.fileSystem =
  773. /** @type {InputFileSystem} */
  774. (compiler.inputFileSystem);
  775. resolveOptions.resolveToContext = true;
  776. return resolveOptions;
  777. });
  778. compiler.resolverFactory.hooks.resolveOptions
  779. .for("loader")
  780. .tap(CLASS_NAME, (resolveOptions) => {
  781. resolveOptions = cleverMerge(options.resolveLoader, resolveOptions);
  782. resolveOptions.fileSystem =
  783. /** @type {InputFileSystem} */
  784. (compiler.inputFileSystem);
  785. return resolveOptions;
  786. });
  787. compiler.hooks.afterResolvers.call(compiler);
  788. return options;
  789. }
  790. }
  791. module.exports = WebpackOptionsApply;