WebpackOptionsApply.js 30 KB

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