提交学习笔记专用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

859 lines
28 KiB

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