WebpackOptionsApply.js 31 KB

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