WebpackOptionsApply.js 18 KB

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