UNPKG

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