WebpackOptionsApply.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const OptionsApply = require("./OptionsApply");
  7. const JavascriptModulesPlugin = require("./JavascriptModulesPlugin");
  8. const JsonModulesPlugin = require("./JsonModulesPlugin");
  9. const WebAssemblyModulesPlugin = require("./wasm/WebAssemblyModulesPlugin");
  10. const LoaderTargetPlugin = require("./LoaderTargetPlugin");
  11. const FunctionModulePlugin = require("./FunctionModulePlugin");
  12. const EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin");
  13. const SourceMapDevToolPlugin = require("./SourceMapDevToolPlugin");
  14. const EvalSourceMapDevToolPlugin = require("./EvalSourceMapDevToolPlugin");
  15. const EntryOptionPlugin = require("./EntryOptionPlugin");
  16. const RecordIdsPlugin = require("./RecordIdsPlugin");
  17. const APIPlugin = require("./APIPlugin");
  18. const ConstPlugin = require("./ConstPlugin");
  19. const RequireJsStuffPlugin = require("./RequireJsStuffPlugin");
  20. const NodeStuffPlugin = require("./NodeStuffPlugin");
  21. const CompatibilityPlugin = require("./CompatibilityPlugin");
  22. const TemplatedPathPlugin = require("./TemplatedPathPlugin");
  23. const WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin");
  24. const UseStrictPlugin = require("./UseStrictPlugin");
  25. const LoaderPlugin = require("./dependencies/LoaderPlugin");
  26. const CommonJsPlugin = require("./dependencies/CommonJsPlugin");
  27. const HarmonyModulesPlugin = require("./dependencies/HarmonyModulesPlugin");
  28. const SystemPlugin = require("./dependencies/SystemPlugin");
  29. const ImportPlugin = require("./dependencies/ImportPlugin");
  30. const AMDPlugin = require("./dependencies/AMDPlugin");
  31. const RequireContextPlugin = require("./dependencies/RequireContextPlugin");
  32. const RequireEnsurePlugin = require("./dependencies/RequireEnsurePlugin");
  33. const RequireIncludePlugin = require("./dependencies/RequireIncludePlugin");
  34. const WarnNoModeSetPlugin = require("./WarnNoModeSetPlugin");
  35. const EnsureChunkConditionsPlugin = require("./optimize/EnsureChunkConditionsPlugin");
  36. const RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
  37. const RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
  38. const MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin");
  39. const FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin");
  40. const OccurrenceChunkOrderPlugin = require("./optimize/OccurrenceChunkOrderPlugin");
  41. const OccurrenceModuleOrderPlugin = require("./optimize/OccurrenceModuleOrderPlugin");
  42. const NaturalChunkOrderPlugin = require("./optimize/NaturalChunkOrderPlugin");
  43. const SideEffectsFlagPlugin = require("./optimize/SideEffectsFlagPlugin");
  44. const FlagDependencyUsagePlugin = require("./FlagDependencyUsagePlugin");
  45. const FlagDependencyExportsPlugin = require("./FlagDependencyExportsPlugin");
  46. const ModuleConcatenationPlugin = require("./optimize/ModuleConcatenationPlugin");
  47. const SplitChunksPlugin = require("./optimize/SplitChunksPlugin");
  48. const RuntimeChunkPlugin = require("./optimize/RuntimeChunkPlugin");
  49. const NoEmitOnErrorsPlugin = require("./NoEmitOnErrorsPlugin");
  50. const NamedModulesPlugin = require("./NamedModulesPlugin");
  51. const NamedChunksPlugin = require("./NamedChunksPlugin");
  52. const HashedModuleIdsPlugin = require("./HashedModuleIdsPlugin");
  53. const DefinePlugin = require("./DefinePlugin");
  54. const SizeLimitsPlugin = require("./performance/SizeLimitsPlugin");
  55. const WasmFinalizeExportsPlugin = require("./wasm/WasmFinalizeExportsPlugin");
  56. /** @typedef {import("../declarations/WebpackOptions").WebpackOptions} WebpackOptions */
  57. /** @typedef {import("./Compiler")} Compiler */
  58. class WebpackOptionsApply extends OptionsApply {
  59. constructor() {
  60. super();
  61. }
  62. /**
  63. * @param {WebpackOptions} options options object
  64. * @param {Compiler} compiler compiler object
  65. * @returns {WebpackOptions} options object
  66. */
  67. process(options, compiler) {
  68. let ExternalsPlugin;
  69. compiler.outputPath = options.output.path;
  70. compiler.recordsInputPath = options.recordsInputPath || options.recordsPath;
  71. compiler.recordsOutputPath =
  72. options.recordsOutputPath || options.recordsPath;
  73. compiler.name = options.name;
  74. // TODO webpack 5 refactor this to MultiCompiler.setDependencies() with a WeakMap
  75. // @ts-ignore TODO
  76. compiler.dependencies = options.dependencies;
  77. if (typeof options.target === "string") {
  78. let JsonpTemplatePlugin;
  79. let FetchCompileWasmTemplatePlugin;
  80. let ReadFileCompileWasmTemplatePlugin;
  81. let NodeSourcePlugin;
  82. let NodeTargetPlugin;
  83. let NodeTemplatePlugin;
  84. switch (options.target) {
  85. case "web":
  86. JsonpTemplatePlugin = require("./web/JsonpTemplatePlugin");
  87. FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin");
  88. NodeSourcePlugin = require("./node/NodeSourcePlugin");
  89. new JsonpTemplatePlugin().apply(compiler);
  90. new FetchCompileWasmTemplatePlugin({
  91. mangleImports: options.optimization.mangleWasmImports
  92. }).apply(compiler);
  93. new FunctionModulePlugin().apply(compiler);
  94. new NodeSourcePlugin(options.node).apply(compiler);
  95. new LoaderTargetPlugin(options.target).apply(compiler);
  96. break;
  97. case "webworker": {
  98. let WebWorkerTemplatePlugin = require("./webworker/WebWorkerTemplatePlugin");
  99. FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin");
  100. NodeSourcePlugin = require("./node/NodeSourcePlugin");
  101. new WebWorkerTemplatePlugin().apply(compiler);
  102. new FetchCompileWasmTemplatePlugin({
  103. mangleImports: options.optimization.mangleWasmImports
  104. }).apply(compiler);
  105. new FunctionModulePlugin().apply(compiler);
  106. new NodeSourcePlugin(options.node).apply(compiler);
  107. new LoaderTargetPlugin(options.target).apply(compiler);
  108. break;
  109. }
  110. case "node":
  111. case "async-node":
  112. NodeTemplatePlugin = require("./node/NodeTemplatePlugin");
  113. ReadFileCompileWasmTemplatePlugin = require("./node/ReadFileCompileWasmTemplatePlugin");
  114. NodeTargetPlugin = require("./node/NodeTargetPlugin");
  115. new NodeTemplatePlugin({
  116. asyncChunkLoading: options.target === "async-node"
  117. }).apply(compiler);
  118. new ReadFileCompileWasmTemplatePlugin({
  119. mangleImports: options.optimization.mangleWasmImports
  120. }).apply(compiler);
  121. new FunctionModulePlugin().apply(compiler);
  122. new NodeTargetPlugin().apply(compiler);
  123. new LoaderTargetPlugin("node").apply(compiler);
  124. break;
  125. case "node-webkit":
  126. JsonpTemplatePlugin = require("./web/JsonpTemplatePlugin");
  127. NodeTargetPlugin = require("./node/NodeTargetPlugin");
  128. ExternalsPlugin = require("./ExternalsPlugin");
  129. new JsonpTemplatePlugin().apply(compiler);
  130. new FunctionModulePlugin().apply(compiler);
  131. new NodeTargetPlugin().apply(compiler);
  132. new ExternalsPlugin("commonjs", "nw.gui").apply(compiler);
  133. new LoaderTargetPlugin(options.target).apply(compiler);
  134. break;
  135. case "electron-main":
  136. NodeTemplatePlugin = require("./node/NodeTemplatePlugin");
  137. NodeTargetPlugin = require("./node/NodeTargetPlugin");
  138. ExternalsPlugin = require("./ExternalsPlugin");
  139. new NodeTemplatePlugin({
  140. asyncChunkLoading: true
  141. }).apply(compiler);
  142. new FunctionModulePlugin().apply(compiler);
  143. new NodeTargetPlugin().apply(compiler);
  144. new ExternalsPlugin("commonjs", [
  145. "app",
  146. "auto-updater",
  147. "browser-window",
  148. "clipboard",
  149. "content-tracing",
  150. "crash-reporter",
  151. "dialog",
  152. "electron",
  153. "global-shortcut",
  154. "ipc",
  155. "ipc-main",
  156. "menu",
  157. "menu-item",
  158. "native-image",
  159. "original-fs",
  160. "power-monitor",
  161. "power-save-blocker",
  162. "protocol",
  163. "screen",
  164. "session",
  165. "shell",
  166. "tray",
  167. "web-contents"
  168. ]).apply(compiler);
  169. new LoaderTargetPlugin(options.target).apply(compiler);
  170. break;
  171. case "electron-renderer":
  172. JsonpTemplatePlugin = require("./web/JsonpTemplatePlugin");
  173. FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin");
  174. NodeTargetPlugin = require("./node/NodeTargetPlugin");
  175. ExternalsPlugin = require("./ExternalsPlugin");
  176. new JsonpTemplatePlugin().apply(compiler);
  177. new FetchCompileWasmTemplatePlugin({
  178. mangleImports: options.optimization.mangleWasmImports
  179. }).apply(compiler);
  180. new FunctionModulePlugin().apply(compiler);
  181. new NodeTargetPlugin().apply(compiler);
  182. new ExternalsPlugin("commonjs", [
  183. "clipboard",
  184. "crash-reporter",
  185. "desktop-capturer",
  186. "electron",
  187. "ipc",
  188. "ipc-renderer",
  189. "native-image",
  190. "original-fs",
  191. "remote",
  192. "screen",
  193. "shell",
  194. "web-frame"
  195. ]).apply(compiler);
  196. new LoaderTargetPlugin(options.target).apply(compiler);
  197. break;
  198. default:
  199. throw new Error("Unsupported target '" + options.target + "'.");
  200. }
  201. }
  202. // @ts-ignore This is always true, which is good this way
  203. else if (options.target !== false) {
  204. options.target(compiler);
  205. } else {
  206. throw new Error("Unsupported target '" + options.target + "'.");
  207. }
  208. if (options.output.library || options.output.libraryTarget !== "var") {
  209. const LibraryTemplatePlugin = require("./LibraryTemplatePlugin");
  210. new LibraryTemplatePlugin(
  211. options.output.library,
  212. options.output.libraryTarget,
  213. options.output.umdNamedDefine,
  214. options.output.auxiliaryComment || "",
  215. options.output.libraryExport
  216. ).apply(compiler);
  217. }
  218. if (options.externals) {
  219. ExternalsPlugin = require("./ExternalsPlugin");
  220. new ExternalsPlugin(
  221. options.output.libraryTarget,
  222. options.externals
  223. ).apply(compiler);
  224. }
  225. let noSources;
  226. let legacy;
  227. let modern;
  228. let comment;
  229. if (
  230. options.devtool &&
  231. (options.devtool.includes("sourcemap") ||
  232. options.devtool.includes("source-map"))
  233. ) {
  234. const hidden = options.devtool.includes("hidden");
  235. const inline = options.devtool.includes("inline");
  236. const evalWrapped = options.devtool.includes("eval");
  237. const cheap = options.devtool.includes("cheap");
  238. const moduleMaps = options.devtool.includes("module");
  239. noSources = options.devtool.includes("nosources");
  240. legacy = options.devtool.includes("@");
  241. modern = options.devtool.includes("#");
  242. comment =
  243. legacy && modern
  244. ? "\n/*\n//@ source" +
  245. "MappingURL=[url]\n//# source" +
  246. "MappingURL=[url]\n*/"
  247. : legacy
  248. ? "\n/*\n//@ source" + "MappingURL=[url]\n*/"
  249. : modern
  250. ? "\n//# source" + "MappingURL=[url]"
  251. : null;
  252. const Plugin = evalWrapped
  253. ? EvalSourceMapDevToolPlugin
  254. : SourceMapDevToolPlugin;
  255. new Plugin({
  256. filename: inline ? null : options.output.sourceMapFilename,
  257. moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate,
  258. fallbackModuleFilenameTemplate:
  259. options.output.devtoolFallbackModuleFilenameTemplate,
  260. append: hidden ? false : comment,
  261. module: moduleMaps ? true : cheap ? false : true,
  262. columns: cheap ? false : true,
  263. lineToLine: options.output.devtoolLineToLine,
  264. noSources: noSources,
  265. namespace: options.output.devtoolNamespace
  266. }).apply(compiler);
  267. } else if (options.devtool && options.devtool.includes("eval")) {
  268. legacy = options.devtool.includes("@");
  269. modern = options.devtool.includes("#");
  270. comment =
  271. legacy && modern
  272. ? "\n//@ sourceURL=[url]\n//# sourceURL=[url]"
  273. : legacy
  274. ? "\n//@ sourceURL=[url]"
  275. : modern
  276. ? "\n//# sourceURL=[url]"
  277. : null;
  278. new EvalDevToolModulePlugin({
  279. sourceUrlComment: comment,
  280. moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate,
  281. namespace: options.output.devtoolNamespace
  282. }).apply(compiler);
  283. }
  284. new JavascriptModulesPlugin().apply(compiler);
  285. new JsonModulesPlugin().apply(compiler);
  286. new WebAssemblyModulesPlugin({
  287. mangleImports: options.optimization.mangleWasmImports
  288. }).apply(compiler);
  289. new EntryOptionPlugin().apply(compiler);
  290. compiler.hooks.entryOption.call(options.context, options.entry);
  291. new CompatibilityPlugin().apply(compiler);
  292. new HarmonyModulesPlugin(options.module).apply(compiler);
  293. new AMDPlugin(options.module, options.amd || {}).apply(compiler);
  294. new CommonJsPlugin(options.module).apply(compiler);
  295. new LoaderPlugin().apply(compiler);
  296. new NodeStuffPlugin(options.node).apply(compiler);
  297. new RequireJsStuffPlugin().apply(compiler);
  298. new APIPlugin().apply(compiler);
  299. new ConstPlugin().apply(compiler);
  300. new UseStrictPlugin().apply(compiler);
  301. new RequireIncludePlugin().apply(compiler);
  302. new RequireEnsurePlugin().apply(compiler);
  303. new RequireContextPlugin(
  304. options.resolve.modules,
  305. options.resolve.extensions,
  306. options.resolve.mainFiles
  307. ).apply(compiler);
  308. new ImportPlugin(options.module).apply(compiler);
  309. new SystemPlugin(options.module).apply(compiler);
  310. if (typeof options.mode !== "string") {
  311. new WarnNoModeSetPlugin().apply(compiler);
  312. }
  313. new EnsureChunkConditionsPlugin().apply(compiler);
  314. if (options.optimization.removeAvailableModules) {
  315. new RemoveParentModulesPlugin().apply(compiler);
  316. }
  317. if (options.optimization.removeEmptyChunks) {
  318. new RemoveEmptyChunksPlugin().apply(compiler);
  319. }
  320. if (options.optimization.mergeDuplicateChunks) {
  321. new MergeDuplicateChunksPlugin().apply(compiler);
  322. }
  323. if (options.optimization.flagIncludedChunks) {
  324. new FlagIncludedChunksPlugin().apply(compiler);
  325. }
  326. if (options.optimization.sideEffects) {
  327. new SideEffectsFlagPlugin().apply(compiler);
  328. }
  329. if (options.optimization.providedExports) {
  330. new FlagDependencyExportsPlugin().apply(compiler);
  331. }
  332. if (options.optimization.usedExports) {
  333. new FlagDependencyUsagePlugin().apply(compiler);
  334. }
  335. if (options.optimization.concatenateModules) {
  336. new ModuleConcatenationPlugin().apply(compiler);
  337. }
  338. if (options.optimization.splitChunks) {
  339. new SplitChunksPlugin(options.optimization.splitChunks).apply(compiler);
  340. }
  341. if (options.optimization.runtimeChunk) {
  342. new RuntimeChunkPlugin(options.optimization.runtimeChunk).apply(compiler);
  343. }
  344. if (options.optimization.noEmitOnErrors) {
  345. new NoEmitOnErrorsPlugin().apply(compiler);
  346. }
  347. if (options.optimization.checkWasmTypes) {
  348. new WasmFinalizeExportsPlugin().apply(compiler);
  349. }
  350. let moduleIds = options.optimization.moduleIds;
  351. if (moduleIds === undefined) {
  352. // TODO webpack 5 remove all these options
  353. if (options.optimization.occurrenceOrder) {
  354. moduleIds = "size";
  355. }
  356. if (options.optimization.namedModules) {
  357. moduleIds = "named";
  358. }
  359. if (options.optimization.hashedModuleIds) {
  360. moduleIds = "hashed";
  361. }
  362. if (moduleIds === undefined) {
  363. moduleIds = "natural";
  364. }
  365. }
  366. if (moduleIds) {
  367. switch (moduleIds) {
  368. case "natural":
  369. // TODO webpack 5: see hint in Compilation.sortModules
  370. break;
  371. case "named":
  372. new NamedModulesPlugin().apply(compiler);
  373. break;
  374. case "hashed":
  375. new HashedModuleIdsPlugin().apply(compiler);
  376. break;
  377. case "size":
  378. new OccurrenceModuleOrderPlugin({
  379. prioritiseInitial: true
  380. }).apply(compiler);
  381. break;
  382. case "total-size":
  383. new OccurrenceModuleOrderPlugin({
  384. prioritiseInitial: false
  385. }).apply(compiler);
  386. break;
  387. default:
  388. throw new Error(
  389. `webpack bug: moduleIds: ${moduleIds} is not implemented`
  390. );
  391. }
  392. }
  393. let chunkIds = options.optimization.chunkIds;
  394. if (chunkIds === undefined) {
  395. // TODO webpack 5 remove all these options
  396. if (options.optimization.occurrenceOrder) {
  397. // This looks weird but it's for backward-compat
  398. // This bug already existed before adding this feature
  399. chunkIds = "total-size";
  400. }
  401. if (options.optimization.namedChunks) {
  402. chunkIds = "named";
  403. }
  404. if (chunkIds === undefined) {
  405. chunkIds = "natural";
  406. }
  407. }
  408. if (chunkIds) {
  409. switch (chunkIds) {
  410. case "natural":
  411. new NaturalChunkOrderPlugin().apply(compiler);
  412. break;
  413. case "named":
  414. // TODO webapck 5: for backward-compat this need to have OccurrenceChunkOrderPlugin too
  415. // The NamedChunksPlugin doesn't give every chunk a name
  416. // This should be fixed, and the OccurrenceChunkOrderPlugin should be removed here.
  417. new OccurrenceChunkOrderPlugin({
  418. prioritiseInitial: false
  419. }).apply(compiler);
  420. new NamedChunksPlugin().apply(compiler);
  421. break;
  422. case "size":
  423. new OccurrenceChunkOrderPlugin({
  424. prioritiseInitial: true
  425. }).apply(compiler);
  426. break;
  427. case "total-size":
  428. new OccurrenceChunkOrderPlugin({
  429. prioritiseInitial: false
  430. }).apply(compiler);
  431. break;
  432. default:
  433. throw new Error(
  434. `webpack bug: chunkIds: ${chunkIds} is not implemented`
  435. );
  436. }
  437. }
  438. if (options.optimization.nodeEnv) {
  439. new DefinePlugin({
  440. "process.env.NODE_ENV": JSON.stringify(options.optimization.nodeEnv)
  441. }).apply(compiler);
  442. }
  443. if (options.optimization.minimize) {
  444. for (const minimizer of options.optimization.minimizer) {
  445. if (typeof minimizer === "function") {
  446. minimizer.call(compiler, compiler);
  447. } else {
  448. minimizer.apply(compiler);
  449. }
  450. }
  451. }
  452. if (options.performance) {
  453. new SizeLimitsPlugin(options.performance).apply(compiler);
  454. }
  455. new TemplatedPathPlugin().apply(compiler);
  456. new RecordIdsPlugin({
  457. portableIds: options.optimization.portableRecords
  458. }).apply(compiler);
  459. new WarnCaseSensitiveModulesPlugin().apply(compiler);
  460. if (options.cache) {
  461. const CachePlugin = require("./CachePlugin");
  462. new CachePlugin(
  463. typeof options.cache === "object" ? options.cache : null
  464. ).apply(compiler);
  465. }
  466. compiler.hooks.afterPlugins.call(compiler);
  467. if (!compiler.inputFileSystem) {
  468. throw new Error("No input filesystem provided");
  469. }
  470. compiler.resolverFactory.hooks.resolveOptions
  471. .for("normal")
  472. .tap("WebpackOptionsApply", resolveOptions => {
  473. return Object.assign(
  474. {
  475. fileSystem: compiler.inputFileSystem
  476. },
  477. options.resolve,
  478. resolveOptions
  479. );
  480. });
  481. compiler.resolverFactory.hooks.resolveOptions
  482. .for("context")
  483. .tap("WebpackOptionsApply", resolveOptions => {
  484. return Object.assign(
  485. {
  486. fileSystem: compiler.inputFileSystem,
  487. resolveToContext: true
  488. },
  489. options.resolve,
  490. resolveOptions
  491. );
  492. });
  493. compiler.resolverFactory.hooks.resolveOptions
  494. .for("loader")
  495. .tap("WebpackOptionsApply", resolveOptions => {
  496. return Object.assign(
  497. {
  498. fileSystem: compiler.inputFileSystem
  499. },
  500. options.resolveLoader,
  501. resolveOptions
  502. );
  503. });
  504. compiler.hooks.afterResolvers.call(compiler);
  505. return options;
  506. }
  507. }
  508. module.exports = WebpackOptionsApply;