UNPKG

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