UNPKG

36 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const fs = require("fs");
9const path = require("path");
10const Template = require("../Template");
11const { cleverMerge } = require("../util/cleverMerge");
12const {
13 getTargetsProperties,
14 getTargetProperties,
15 getDefaultTarget
16} = require("./target");
17
18/** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptions */
19/** @typedef {import("../../declarations/WebpackOptions").EntryDescription} EntryDescription */
20/** @typedef {import("../../declarations/WebpackOptions").EntryNormalized} Entry */
21/** @typedef {import("../../declarations/WebpackOptions").Experiments} Experiments */
22/** @typedef {import("../../declarations/WebpackOptions").ExperimentsNormalized} ExperimentsNormalized */
23/** @typedef {import("../../declarations/WebpackOptions").ExternalsPresets} ExternalsPresets */
24/** @typedef {import("../../declarations/WebpackOptions").ExternalsType} ExternalsType */
25/** @typedef {import("../../declarations/WebpackOptions").InfrastructureLogging} InfrastructureLogging */
26/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
27/** @typedef {import("../../declarations/WebpackOptions").Library} Library */
28/** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */
29/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
30/** @typedef {import("../../declarations/WebpackOptions").Loader} Loader */
31/** @typedef {import("../../declarations/WebpackOptions").Mode} Mode */
32/** @typedef {import("../../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */
33/** @typedef {import("../../declarations/WebpackOptions").Node} WebpackNode */
34/** @typedef {import("../../declarations/WebpackOptions").Optimization} Optimization */
35/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */
36/** @typedef {import("../../declarations/WebpackOptions").Performance} Performance */
37/** @typedef {import("../../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
38/** @typedef {import("../../declarations/WebpackOptions").RuleSetRules} RuleSetRules */
39/** @typedef {import("../../declarations/WebpackOptions").SnapshotOptions} SnapshotOptions */
40/** @typedef {import("../../declarations/WebpackOptions").Target} Target */
41/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
42/** @typedef {import("./target").TargetProperties} TargetProperties */
43
44const NODE_MODULES_REGEXP = /[\\/]node_modules[\\/]/i;
45
46/**
47 * Sets a constant default value when undefined
48 * @template T
49 * @template {keyof T} P
50 * @param {T} obj an object
51 * @param {P} prop a property of this object
52 * @param {T[P]} value a default value of the property
53 * @returns {void}
54 */
55const D = (obj, prop, value) => {
56 if (obj[prop] === undefined) {
57 obj[prop] = value;
58 }
59};
60
61/**
62 * Sets a dynamic default value when undefined, by calling the factory function
63 * @template T
64 * @template {keyof T} P
65 * @param {T} obj an object
66 * @param {P} prop a property of this object
67 * @param {function(): T[P]} factory a default value factory for the property
68 * @returns {void}
69 */
70const F = (obj, prop, factory) => {
71 if (obj[prop] === undefined) {
72 obj[prop] = factory();
73 }
74};
75
76/**
77 * Sets a dynamic default value when undefined, by calling the factory function.
78 * factory must return an array or undefined
79 * When the current value is already an array an contains "..." it's replaced with
80 * the result of the factory function
81 * @template T
82 * @template {keyof T} P
83 * @param {T} obj an object
84 * @param {P} prop a property of this object
85 * @param {function(): T[P]} factory a default value factory for the property
86 * @returns {void}
87 */
88const A = (obj, prop, factory) => {
89 const value = obj[prop];
90 if (value === undefined) {
91 obj[prop] = factory();
92 } else if (Array.isArray(value)) {
93 /** @type {any[]} */
94 let newArray = undefined;
95 for (let i = 0; i < value.length; i++) {
96 const item = value[i];
97 if (item === "...") {
98 if (newArray === undefined) {
99 newArray = value.slice(0, i);
100 obj[prop] = /** @type {T[P]} */ (/** @type {unknown} */ (newArray));
101 }
102 const items = /** @type {any[]} */ (/** @type {unknown} */ (factory()));
103 if (items !== undefined) {
104 for (const item of items) {
105 newArray.push(item);
106 }
107 }
108 } else if (newArray !== undefined) {
109 newArray.push(item);
110 }
111 }
112 }
113};
114
115/**
116 * @param {WebpackOptions} options options to be modified
117 * @returns {void}
118 */
119const applyWebpackOptionsBaseDefaults = options => {
120 F(options, "context", () => process.cwd());
121 applyInfrastructureLoggingDefaults(options.infrastructureLogging);
122};
123
124/**
125 * @param {WebpackOptions} options options to be modified
126 * @returns {void}
127 */
128const applyWebpackOptionsDefaults = options => {
129 F(options, "context", () => process.cwd());
130 F(options, "target", () => {
131 return getDefaultTarget(options.context);
132 });
133
134 const { mode, name, target } = options;
135
136 let targetProperties =
137 target === false
138 ? /** @type {false} */ (false)
139 : typeof target === "string"
140 ? getTargetProperties(target, options.context)
141 : getTargetsProperties(target, options.context);
142
143 const development = mode === "development";
144 const production = mode === "production" || !mode;
145
146 if (typeof options.entry !== "function") {
147 for (const key of Object.keys(options.entry)) {
148 F(
149 options.entry[key],
150 "import",
151 () => /** @type {[string]} */ (["./src"])
152 );
153 }
154 }
155
156 F(options, "devtool", () => (development ? "eval" : false));
157 D(options, "watch", false);
158 D(options, "profile", false);
159 D(options, "parallelism", 100);
160 D(options, "recordsInputPath", false);
161 D(options, "recordsOutputPath", false);
162
163 applyExperimentsDefaults(options.experiments, { production, development });
164
165 const futureDefaults = options.experiments.futureDefaults;
166
167 F(options, "cache", () =>
168 development ? { type: /** @type {"memory"} */ ("memory") } : false
169 );
170 applyCacheDefaults(options.cache, {
171 name: name || "default",
172 mode: mode || "production",
173 development,
174 cacheUnaffected: options.experiments.cacheUnaffected
175 });
176 const cache = !!options.cache;
177
178 applySnapshotDefaults(options.snapshot, {
179 production,
180 futureDefaults
181 });
182
183 applyModuleDefaults(options.module, {
184 cache,
185 syncWebAssembly: options.experiments.syncWebAssembly,
186 asyncWebAssembly: options.experiments.asyncWebAssembly
187 });
188
189 applyOutputDefaults(options.output, {
190 context: options.context,
191 targetProperties,
192 isAffectedByBrowserslist:
193 target === undefined ||
194 (typeof target === "string" && target.startsWith("browserslist")) ||
195 (Array.isArray(target) &&
196 target.some(target => target.startsWith("browserslist"))),
197 outputModule: options.experiments.outputModule,
198 development,
199 entry: options.entry,
200 module: options.module,
201 futureDefaults
202 });
203
204 applyExternalsPresetsDefaults(options.externalsPresets, {
205 targetProperties,
206 buildHttp: !!options.experiments.buildHttp
207 });
208
209 applyLoaderDefaults(options.loader, { targetProperties });
210
211 F(options, "externalsType", () => {
212 const validExternalTypes = require("../../schemas/WebpackOptions.json")
213 .definitions.ExternalsType.enum;
214 return options.output.library &&
215 validExternalTypes.includes(options.output.library.type)
216 ? /** @type {ExternalsType} */ (options.output.library.type)
217 : options.output.module
218 ? "module"
219 : "var";
220 });
221
222 applyNodeDefaults(options.node, {
223 futureDefaults: options.experiments.futureDefaults,
224 targetProperties
225 });
226
227 F(options, "performance", () =>
228 production &&
229 targetProperties &&
230 (targetProperties.browser || targetProperties.browser === null)
231 ? {}
232 : false
233 );
234 applyPerformanceDefaults(options.performance, {
235 production
236 });
237
238 applyOptimizationDefaults(options.optimization, {
239 development,
240 production,
241 records: !!(options.recordsInputPath || options.recordsOutputPath)
242 });
243
244 options.resolve = cleverMerge(
245 getResolveDefaults({
246 cache,
247 context: options.context,
248 targetProperties,
249 mode: options.mode
250 }),
251 options.resolve
252 );
253
254 options.resolveLoader = cleverMerge(
255 getResolveLoaderDefaults({ cache }),
256 options.resolveLoader
257 );
258};
259
260/**
261 * @param {ExperimentsNormalized} experiments options
262 * @param {Object} options options
263 * @param {boolean} options.production is production
264 * @param {boolean} options.development is development mode
265 * @returns {void}
266 */
267const applyExperimentsDefaults = (experiments, { production, development }) => {
268 D(experiments, "futureDefaults", false);
269 D(experiments, "backCompat", !experiments.futureDefaults);
270 D(experiments, "topLevelAwait", experiments.futureDefaults);
271 D(experiments, "syncWebAssembly", false);
272 D(experiments, "asyncWebAssembly", experiments.futureDefaults);
273 D(experiments, "outputModule", false);
274 D(experiments, "layers", false);
275 D(experiments, "lazyCompilation", undefined);
276 D(experiments, "buildHttp", undefined);
277 D(experiments, "cacheUnaffected", experiments.futureDefaults);
278
279 if (typeof experiments.buildHttp === "object") {
280 D(experiments.buildHttp, "frozen", production);
281 D(experiments.buildHttp, "upgrade", false);
282 }
283};
284
285/**
286 * @param {CacheOptions} cache options
287 * @param {Object} options options
288 * @param {string} options.name name
289 * @param {string} options.mode mode
290 * @param {boolean} options.development is development mode
291 * @param {boolean} options.cacheUnaffected the cacheUnaffected experiment is enabled
292 * @returns {void}
293 */
294const applyCacheDefaults = (
295 cache,
296 { name, mode, development, cacheUnaffected }
297) => {
298 if (cache === false) return;
299 switch (cache.type) {
300 case "filesystem":
301 F(cache, "name", () => name + "-" + mode);
302 D(cache, "version", "");
303 F(cache, "cacheDirectory", () => {
304 const cwd = process.cwd();
305 let dir = cwd;
306 for (;;) {
307 try {
308 if (fs.statSync(path.join(dir, "package.json")).isFile()) break;
309 // eslint-disable-next-line no-empty
310 } catch (e) {}
311 const parent = path.dirname(dir);
312 if (dir === parent) {
313 dir = undefined;
314 break;
315 }
316 dir = parent;
317 }
318 if (!dir) {
319 return path.resolve(cwd, ".cache/webpack");
320 } else if (process.versions.pnp === "1") {
321 return path.resolve(dir, ".pnp/.cache/webpack");
322 } else if (process.versions.pnp === "3") {
323 return path.resolve(dir, ".yarn/.cache/webpack");
324 } else {
325 return path.resolve(dir, "node_modules/.cache/webpack");
326 }
327 });
328 F(cache, "cacheLocation", () =>
329 path.resolve(cache.cacheDirectory, cache.name)
330 );
331 D(cache, "hashAlgorithm", "md4");
332 D(cache, "store", "pack");
333 D(cache, "compression", false);
334 D(cache, "profile", false);
335 D(cache, "idleTimeout", 60000);
336 D(cache, "idleTimeoutForInitialStore", 5000);
337 D(cache, "idleTimeoutAfterLargeChanges", 1000);
338 D(cache, "maxMemoryGenerations", development ? 5 : Infinity);
339 D(cache, "maxAge", 1000 * 60 * 60 * 24 * 60); // 1 month
340 D(cache, "allowCollectingMemory", development);
341 D(cache, "memoryCacheUnaffected", development && cacheUnaffected);
342 D(cache.buildDependencies, "defaultWebpack", [
343 path.resolve(__dirname, "..") + path.sep
344 ]);
345 break;
346 case "memory":
347 D(cache, "maxGenerations", Infinity);
348 D(cache, "cacheUnaffected", development && cacheUnaffected);
349 break;
350 }
351};
352
353/**
354 * @param {SnapshotOptions} snapshot options
355 * @param {Object} options options
356 * @param {boolean} options.production is production
357 * @param {boolean} options.futureDefaults is future defaults enabled
358 * @returns {void}
359 */
360const applySnapshotDefaults = (snapshot, { production, futureDefaults }) => {
361 if (futureDefaults) {
362 F(snapshot, "managedPaths", () =>
363 process.versions.pnp === "3"
364 ? [
365 /^(.+?(?:[\\/]\.yarn[\\/]unplugged[\\/][^\\/]+)?[\\/]node_modules[\\/])/
366 ]
367 : [/^(.+?[\\/]node_modules[\\/])/]
368 );
369 F(snapshot, "immutablePaths", () =>
370 process.versions.pnp === "3"
371 ? [/^(.+?[\\/]cache[\\/][^\\/]+\.zip[\\/]node_modules[\\/])/]
372 : []
373 );
374 } else {
375 A(snapshot, "managedPaths", () => {
376 if (process.versions.pnp === "3") {
377 const match =
378 /^(.+?)[\\/]cache[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec(
379 require.resolve("watchpack")
380 );
381 if (match) {
382 return [path.resolve(match[1], "unplugged")];
383 }
384 } else {
385 const match = /^(.+?[\\/]node_modules)[\\/]/.exec(
386 // eslint-disable-next-line node/no-extraneous-require
387 require.resolve("watchpack")
388 );
389 if (match) {
390 return [match[1]];
391 }
392 }
393 return [];
394 });
395 A(snapshot, "immutablePaths", () => {
396 if (process.versions.pnp === "1") {
397 const match =
398 /^(.+?[\\/]v4)[\\/]npm-watchpack-[^\\/]+-[\da-f]{40}[\\/]node_modules[\\/]/.exec(
399 require.resolve("watchpack")
400 );
401 if (match) {
402 return [match[1]];
403 }
404 } else if (process.versions.pnp === "3") {
405 const match =
406 /^(.+?)[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec(
407 require.resolve("watchpack")
408 );
409 if (match) {
410 return [match[1]];
411 }
412 }
413 return [];
414 });
415 }
416 F(snapshot, "resolveBuildDependencies", () => ({
417 timestamp: true,
418 hash: true
419 }));
420 F(snapshot, "buildDependencies", () => ({ timestamp: true, hash: true }));
421 F(snapshot, "module", () =>
422 production ? { timestamp: true, hash: true } : { timestamp: true }
423 );
424 F(snapshot, "resolve", () =>
425 production ? { timestamp: true, hash: true } : { timestamp: true }
426 );
427};
428
429/**
430 * @param {JavascriptParserOptions} parserOptions parser options
431 * @returns {void}
432 */
433const applyJavascriptParserOptionsDefaults = parserOptions => {
434 D(parserOptions, "unknownContextRequest", ".");
435 D(parserOptions, "unknownContextRegExp", false);
436 D(parserOptions, "unknownContextRecursive", true);
437 D(parserOptions, "unknownContextCritical", true);
438 D(parserOptions, "exprContextRequest", ".");
439 D(parserOptions, "exprContextRegExp", false);
440 D(parserOptions, "exprContextRecursive", true);
441 D(parserOptions, "exprContextCritical", true);
442 D(parserOptions, "wrappedContextRegExp", /.*/);
443 D(parserOptions, "wrappedContextRecursive", true);
444 D(parserOptions, "wrappedContextCritical", false);
445 D(parserOptions, "strictThisContextOnImports", false);
446};
447
448/**
449 * @param {ModuleOptions} module options
450 * @param {Object} options options
451 * @param {boolean} options.cache is caching enabled
452 * @param {boolean} options.syncWebAssembly is syncWebAssembly enabled
453 * @param {boolean} options.asyncWebAssembly is asyncWebAssembly enabled
454 * @returns {void}
455 */
456const applyModuleDefaults = (
457 module,
458 { cache, syncWebAssembly, asyncWebAssembly }
459) => {
460 if (cache) {
461 D(module, "unsafeCache", module => {
462 const name = module.nameForCondition();
463 return name && NODE_MODULES_REGEXP.test(name);
464 });
465 } else {
466 D(module, "unsafeCache", false);
467 }
468
469 F(module.parser, "asset", () => ({}));
470 F(module.parser.asset, "dataUrlCondition", () => ({}));
471 if (typeof module.parser.asset.dataUrlCondition === "object") {
472 D(module.parser.asset.dataUrlCondition, "maxSize", 8096);
473 }
474
475 F(module.parser, "javascript", () => ({}));
476 applyJavascriptParserOptionsDefaults(module.parser.javascript);
477
478 A(module, "defaultRules", () => {
479 const esm = {
480 type: "javascript/esm",
481 resolve: {
482 byDependency: {
483 esm: {
484 fullySpecified: true
485 }
486 }
487 }
488 };
489 const commonjs = {
490 type: "javascript/dynamic"
491 };
492 /** @type {RuleSetRules} */
493 const rules = [
494 {
495 mimetype: "application/node",
496 type: "javascript/auto"
497 },
498 {
499 test: /\.json$/i,
500 type: "json"
501 },
502 {
503 mimetype: "application/json",
504 type: "json"
505 },
506 {
507 test: /\.mjs$/i,
508 ...esm
509 },
510 {
511 test: /\.js$/i,
512 descriptionData: {
513 type: "module"
514 },
515 ...esm
516 },
517 {
518 test: /\.cjs$/i,
519 ...commonjs
520 },
521 {
522 test: /\.js$/i,
523 descriptionData: {
524 type: "commonjs"
525 },
526 ...commonjs
527 },
528 {
529 mimetype: {
530 or: ["text/javascript", "application/javascript"]
531 },
532 ...esm
533 }
534 ];
535 if (asyncWebAssembly) {
536 const wasm = {
537 type: "webassembly/async",
538 rules: [
539 {
540 descriptionData: {
541 type: "module"
542 },
543 resolve: {
544 fullySpecified: true
545 }
546 }
547 ]
548 };
549 rules.push({
550 test: /\.wasm$/i,
551 ...wasm
552 });
553 rules.push({
554 mimetype: "application/wasm",
555 ...wasm
556 });
557 } else if (syncWebAssembly) {
558 const wasm = {
559 type: "webassembly/sync",
560 rules: [
561 {
562 descriptionData: {
563 type: "module"
564 },
565 resolve: {
566 fullySpecified: true
567 }
568 }
569 ]
570 };
571 rules.push({
572 test: /\.wasm$/i,
573 ...wasm
574 });
575 rules.push({
576 mimetype: "application/wasm",
577 ...wasm
578 });
579 }
580 rules.push(
581 {
582 dependency: "url",
583 oneOf: [
584 {
585 scheme: /^data$/,
586 type: "asset/inline"
587 },
588 {
589 type: "asset/resource"
590 }
591 ]
592 },
593 {
594 assert: { type: "json" },
595 type: "json"
596 }
597 );
598 return rules;
599 });
600};
601
602/**
603 * @param {Output} output options
604 * @param {Object} options options
605 * @param {string} options.context context
606 * @param {TargetProperties | false} options.targetProperties target properties
607 * @param {boolean} options.isAffectedByBrowserslist is affected by browserslist
608 * @param {boolean} options.outputModule is outputModule experiment enabled
609 * @param {boolean} options.development is development mode
610 * @param {Entry} options.entry entry option
611 * @param {ModuleOptions} options.module module option
612 * @param {boolean} options.futureDefaults is future defaults enabled
613 * @returns {void}
614 */
615const applyOutputDefaults = (
616 output,
617 {
618 context,
619 targetProperties: tp,
620 isAffectedByBrowserslist,
621 outputModule,
622 development,
623 entry,
624 module,
625 futureDefaults
626 }
627) => {
628 /**
629 * @param {Library=} library the library option
630 * @returns {string} a readable library name
631 */
632 const getLibraryName = library => {
633 const libraryName =
634 typeof library === "object" &&
635 library &&
636 !Array.isArray(library) &&
637 "type" in library
638 ? library.name
639 : /** @type {LibraryName=} */ (library);
640 if (Array.isArray(libraryName)) {
641 return libraryName.join(".");
642 } else if (typeof libraryName === "object") {
643 return getLibraryName(libraryName.root);
644 } else if (typeof libraryName === "string") {
645 return libraryName;
646 }
647 return "";
648 };
649
650 F(output, "uniqueName", () => {
651 const libraryName = getLibraryName(output.library);
652 if (libraryName) return libraryName;
653 const pkgPath = path.resolve(context, "package.json");
654 try {
655 const packageInfo = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
656 return packageInfo.name || "";
657 } catch (e) {
658 if (e.code !== "ENOENT") {
659 e.message += `\nwhile determining default 'output.uniqueName' from 'name' in ${pkgPath}`;
660 throw e;
661 }
662 return "";
663 }
664 });
665
666 F(output, "module", () => !!outputModule);
667 D(output, "filename", output.module ? "[name].mjs" : "[name].js");
668 F(output, "iife", () => !output.module);
669 D(output, "importFunctionName", "import");
670 D(output, "importMetaName", "import.meta");
671 F(output, "chunkFilename", () => {
672 const filename = output.filename;
673 if (typeof filename !== "function") {
674 const hasName = filename.includes("[name]");
675 const hasId = filename.includes("[id]");
676 const hasChunkHash = filename.includes("[chunkhash]");
677 const hasContentHash = filename.includes("[contenthash]");
678 // Anything changing depending on chunk is fine
679 if (hasChunkHash || hasContentHash || hasName || hasId) return filename;
680 // Otherwise prefix "[id]." in front of the basename to make it changing
681 return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
682 }
683 return output.module ? "[id].mjs" : "[id].js";
684 });
685 D(output, "assetModuleFilename", "[hash][ext][query]");
686 D(output, "webassemblyModuleFilename", "[hash].module.wasm");
687 D(output, "compareBeforeEmit", true);
688 D(output, "charset", true);
689 F(output, "hotUpdateGlobal", () =>
690 Template.toIdentifier(
691 "webpackHotUpdate" + Template.toIdentifier(output.uniqueName)
692 )
693 );
694 F(output, "chunkLoadingGlobal", () =>
695 Template.toIdentifier(
696 "webpackChunk" + Template.toIdentifier(output.uniqueName)
697 )
698 );
699 F(output, "globalObject", () => {
700 if (tp) {
701 if (tp.global) return "global";
702 if (tp.globalThis) return "globalThis";
703 }
704 return "self";
705 });
706 F(output, "chunkFormat", () => {
707 if (tp) {
708 const helpMessage = isAffectedByBrowserslist
709 ? "Make sure that your 'browserslist' includes only platforms that support these features or select an appropriate 'target' to allow selecting a chunk format by default. Alternatively specify the 'output.chunkFormat' directly."
710 : "Select an appropriate 'target' to allow selecting one by default, or specify the 'output.chunkFormat' directly.";
711 if (output.module) {
712 if (tp.dynamicImport) return "module";
713 if (tp.document) return "array-push";
714 throw new Error(
715 "For the selected environment is no default ESM chunk format available:\n" +
716 "ESM exports can be chosen when 'import()' is available.\n" +
717 "JSONP Array push can be chosen when 'document' is available.\n" +
718 helpMessage
719 );
720 } else {
721 if (tp.document) return "array-push";
722 if (tp.require) return "commonjs";
723 if (tp.nodeBuiltins) return "commonjs";
724 if (tp.importScripts) return "array-push";
725 throw new Error(
726 "For the selected environment is no default script chunk format available:\n" +
727 "JSONP Array push can be chosen when 'document' or 'importScripts' is available.\n" +
728 "CommonJs exports can be chosen when 'require' or node builtins are available.\n" +
729 helpMessage
730 );
731 }
732 }
733 throw new Error(
734 "Chunk format can't be selected by default when no target is specified"
735 );
736 });
737 F(output, "chunkLoading", () => {
738 if (tp) {
739 switch (output.chunkFormat) {
740 case "array-push":
741 if (tp.document) return "jsonp";
742 if (tp.importScripts) return "import-scripts";
743 break;
744 case "commonjs":
745 if (tp.require) return "require";
746 if (tp.nodeBuiltins) return "async-node";
747 break;
748 case "module":
749 if (tp.dynamicImport) return "import";
750 break;
751 }
752 if (
753 tp.require === null ||
754 tp.nodeBuiltins === null ||
755 tp.document === null ||
756 tp.importScripts === null
757 ) {
758 return "universal";
759 }
760 }
761 return false;
762 });
763 F(output, "workerChunkLoading", () => {
764 if (tp) {
765 switch (output.chunkFormat) {
766 case "array-push":
767 if (tp.importScriptsInWorker) return "import-scripts";
768 break;
769 case "commonjs":
770 if (tp.require) return "require";
771 if (tp.nodeBuiltins) return "async-node";
772 break;
773 case "module":
774 if (tp.dynamicImportInWorker) return "import";
775 break;
776 }
777 if (
778 tp.require === null ||
779 tp.nodeBuiltins === null ||
780 tp.importScriptsInWorker === null
781 ) {
782 return "universal";
783 }
784 }
785 return false;
786 });
787 F(output, "wasmLoading", () => {
788 if (tp) {
789 if (tp.fetchWasm) return "fetch";
790 if (tp.nodeBuiltins)
791 return output.module ? "async-node-module" : "async-node";
792 if (tp.nodeBuiltins === null || tp.fetchWasm === null) {
793 return "universal";
794 }
795 }
796 return false;
797 });
798 F(output, "workerWasmLoading", () => output.wasmLoading);
799 F(output, "devtoolNamespace", () => output.uniqueName);
800 if (output.library) {
801 F(output.library, "type", () => (output.module ? "module" : "var"));
802 }
803 F(output, "path", () => path.join(process.cwd(), "dist"));
804 F(output, "pathinfo", () => development);
805 D(output, "sourceMapFilename", "[file].map[query]");
806 D(
807 output,
808 "hotUpdateChunkFilename",
809 `[id].[fullhash].hot-update.${output.module ? "mjs" : "js"}`
810 );
811 D(output, "hotUpdateMainFilename", "[runtime].[fullhash].hot-update.json");
812 D(output, "crossOriginLoading", false);
813 F(output, "scriptType", () => (output.module ? "module" : false));
814 D(
815 output,
816 "publicPath",
817 (tp && (tp.document || tp.importScripts)) || output.scriptType === "module"
818 ? "auto"
819 : ""
820 );
821 D(output, "chunkLoadTimeout", 120000);
822 D(output, "hashFunction", futureDefaults ? "xxhash64" : "md4");
823 D(output, "hashDigest", "hex");
824 D(output, "hashDigestLength", 20);
825 D(output, "strictModuleExceptionHandling", false);
826
827 const optimistic = v => v || v === undefined;
828 F(
829 output.environment,
830 "arrowFunction",
831 () => tp && optimistic(tp.arrowFunction)
832 );
833 F(output.environment, "const", () => tp && optimistic(tp.const));
834 F(
835 output.environment,
836 "destructuring",
837 () => tp && optimistic(tp.destructuring)
838 );
839 F(output.environment, "forOf", () => tp && optimistic(tp.forOf));
840 F(output.environment, "bigIntLiteral", () => tp && tp.bigIntLiteral);
841 F(output.environment, "dynamicImport", () => tp && tp.dynamicImport);
842 F(output.environment, "module", () => tp && tp.module);
843
844 const { trustedTypes } = output;
845 if (trustedTypes) {
846 F(
847 trustedTypes,
848 "policyName",
849 () =>
850 output.uniqueName.replace(/[^a-zA-Z0-9\-#=_/@.%]+/g, "_") || "webpack"
851 );
852 }
853
854 /**
855 * @param {function(EntryDescription): void} fn iterator
856 * @returns {void}
857 */
858 const forEachEntry = fn => {
859 for (const name of Object.keys(entry)) {
860 fn(entry[name]);
861 }
862 };
863 A(output, "enabledLibraryTypes", () => {
864 const enabledLibraryTypes = [];
865 if (output.library) {
866 enabledLibraryTypes.push(output.library.type);
867 }
868 forEachEntry(desc => {
869 if (desc.library) {
870 enabledLibraryTypes.push(desc.library.type);
871 }
872 });
873 return enabledLibraryTypes;
874 });
875
876 A(output, "enabledChunkLoadingTypes", () => {
877 const enabledChunkLoadingTypes = new Set();
878 if (output.chunkLoading) {
879 enabledChunkLoadingTypes.add(output.chunkLoading);
880 }
881 if (output.workerChunkLoading) {
882 enabledChunkLoadingTypes.add(output.workerChunkLoading);
883 }
884 forEachEntry(desc => {
885 if (desc.chunkLoading) {
886 enabledChunkLoadingTypes.add(desc.chunkLoading);
887 }
888 });
889 return Array.from(enabledChunkLoadingTypes);
890 });
891
892 A(output, "enabledWasmLoadingTypes", () => {
893 const enabledWasmLoadingTypes = new Set();
894 if (output.wasmLoading) {
895 enabledWasmLoadingTypes.add(output.wasmLoading);
896 }
897 if (output.workerWasmLoading) {
898 enabledWasmLoadingTypes.add(output.workerWasmLoading);
899 }
900 forEachEntry(desc => {
901 if (desc.wasmLoading) {
902 enabledWasmLoadingTypes.add(desc.wasmLoading);
903 }
904 });
905 return Array.from(enabledWasmLoadingTypes);
906 });
907};
908
909/**
910 * @param {ExternalsPresets} externalsPresets options
911 * @param {Object} options options
912 * @param {TargetProperties | false} options.targetProperties target properties
913 * @param {boolean} options.buildHttp buildHttp experiment enabled
914 * @returns {void}
915 */
916const applyExternalsPresetsDefaults = (
917 externalsPresets,
918 { targetProperties, buildHttp }
919) => {
920 D(
921 externalsPresets,
922 "web",
923 !buildHttp && targetProperties && targetProperties.web
924 );
925 D(externalsPresets, "node", targetProperties && targetProperties.node);
926 D(externalsPresets, "nwjs", targetProperties && targetProperties.nwjs);
927 D(
928 externalsPresets,
929 "electron",
930 targetProperties && targetProperties.electron
931 );
932 D(
933 externalsPresets,
934 "electronMain",
935 targetProperties &&
936 targetProperties.electron &&
937 targetProperties.electronMain
938 );
939 D(
940 externalsPresets,
941 "electronPreload",
942 targetProperties &&
943 targetProperties.electron &&
944 targetProperties.electronPreload
945 );
946 D(
947 externalsPresets,
948 "electronRenderer",
949 targetProperties &&
950 targetProperties.electron &&
951 targetProperties.electronRenderer
952 );
953};
954
955/**
956 * @param {Loader} loader options
957 * @param {Object} options options
958 * @param {TargetProperties | false} options.targetProperties target properties
959 * @returns {void}
960 */
961const applyLoaderDefaults = (loader, { targetProperties }) => {
962 F(loader, "target", () => {
963 if (targetProperties) {
964 if (targetProperties.electron) {
965 if (targetProperties.electronMain) return "electron-main";
966 if (targetProperties.electronPreload) return "electron-preload";
967 if (targetProperties.electronRenderer) return "electron-renderer";
968 return "electron";
969 }
970 if (targetProperties.nwjs) return "nwjs";
971 if (targetProperties.node) return "node";
972 if (targetProperties.web) return "web";
973 }
974 });
975};
976
977/**
978 * @param {WebpackNode} node options
979 * @param {Object} options options
980 * @param {TargetProperties | false} options.targetProperties target properties
981 * @param {boolean} options.futureDefaults is future defaults enabled
982 * @returns {void}
983 */
984const applyNodeDefaults = (node, { futureDefaults, targetProperties }) => {
985 if (node === false) return;
986
987 F(node, "global", () => {
988 if (targetProperties && targetProperties.global) return false;
989 // TODO webpack 6 should always default to false
990 return futureDefaults ? "warn" : true;
991 });
992 F(node, "__filename", () => {
993 if (targetProperties && targetProperties.node) return "eval-only";
994 // TODO webpack 6 should always default to false
995 return futureDefaults ? "warn-mock" : "mock";
996 });
997 F(node, "__dirname", () => {
998 if (targetProperties && targetProperties.node) return "eval-only";
999 // TODO webpack 6 should always default to false
1000 return futureDefaults ? "warn-mock" : "mock";
1001 });
1002};
1003
1004/**
1005 * @param {Performance} performance options
1006 * @param {Object} options options
1007 * @param {boolean} options.production is production
1008 * @returns {void}
1009 */
1010const applyPerformanceDefaults = (performance, { production }) => {
1011 if (performance === false) return;
1012 D(performance, "maxAssetSize", 250000);
1013 D(performance, "maxEntrypointSize", 250000);
1014 F(performance, "hints", () => (production ? "warning" : false));
1015};
1016
1017/**
1018 * @param {Optimization} optimization options
1019 * @param {Object} options options
1020 * @param {boolean} options.production is production
1021 * @param {boolean} options.development is development
1022 * @param {boolean} options.records using records
1023 * @returns {void}
1024 */
1025const applyOptimizationDefaults = (
1026 optimization,
1027 { production, development, records }
1028) => {
1029 D(optimization, "removeAvailableModules", false);
1030 D(optimization, "removeEmptyChunks", true);
1031 D(optimization, "mergeDuplicateChunks", true);
1032 D(optimization, "flagIncludedChunks", production);
1033 F(optimization, "moduleIds", () => {
1034 if (production) return "deterministic";
1035 if (development) return "named";
1036 return "natural";
1037 });
1038 F(optimization, "chunkIds", () => {
1039 if (production) return "deterministic";
1040 if (development) return "named";
1041 return "natural";
1042 });
1043 F(optimization, "sideEffects", () => (production ? true : "flag"));
1044 D(optimization, "providedExports", true);
1045 D(optimization, "usedExports", production);
1046 D(optimization, "innerGraph", production);
1047 D(optimization, "mangleExports", production);
1048 D(optimization, "concatenateModules", production);
1049 D(optimization, "runtimeChunk", false);
1050 D(optimization, "emitOnErrors", !production);
1051 D(optimization, "checkWasmTypes", production);
1052 D(optimization, "mangleWasmImports", false);
1053 D(optimization, "portableRecords", records);
1054 D(optimization, "realContentHash", production);
1055 D(optimization, "minimize", production);
1056 A(optimization, "minimizer", () => [
1057 {
1058 apply: compiler => {
1059 // Lazy load the Terser plugin
1060 const TerserPlugin = require("terser-webpack-plugin");
1061 new TerserPlugin({
1062 terserOptions: {
1063 compress: {
1064 passes: 2
1065 }
1066 }
1067 }).apply(compiler);
1068 }
1069 }
1070 ]);
1071 F(optimization, "nodeEnv", () => {
1072 if (production) return "production";
1073 if (development) return "development";
1074 return false;
1075 });
1076 const { splitChunks } = optimization;
1077 if (splitChunks) {
1078 A(splitChunks, "defaultSizeTypes", () => ["javascript", "unknown"]);
1079 D(splitChunks, "hidePathInfo", production);
1080 D(splitChunks, "chunks", "async");
1081 D(splitChunks, "usedExports", optimization.usedExports === true);
1082 D(splitChunks, "minChunks", 1);
1083 F(splitChunks, "minSize", () => (production ? 20000 : 10000));
1084 F(splitChunks, "minRemainingSize", () => (development ? 0 : undefined));
1085 F(splitChunks, "enforceSizeThreshold", () => (production ? 50000 : 30000));
1086 F(splitChunks, "maxAsyncRequests", () => (production ? 30 : Infinity));
1087 F(splitChunks, "maxInitialRequests", () => (production ? 30 : Infinity));
1088 D(splitChunks, "automaticNameDelimiter", "-");
1089 const { cacheGroups } = splitChunks;
1090 F(cacheGroups, "default", () => ({
1091 idHint: "",
1092 reuseExistingChunk: true,
1093 minChunks: 2,
1094 priority: -20
1095 }));
1096 F(cacheGroups, "defaultVendors", () => ({
1097 idHint: "vendors",
1098 reuseExistingChunk: true,
1099 test: NODE_MODULES_REGEXP,
1100 priority: -10
1101 }));
1102 }
1103};
1104
1105/**
1106 * @param {Object} options options
1107 * @param {boolean} options.cache is cache enable
1108 * @param {string} options.context build context
1109 * @param {TargetProperties | false} options.targetProperties target properties
1110 * @param {Mode} options.mode mode
1111 * @returns {ResolveOptions} resolve options
1112 */
1113const getResolveDefaults = ({ cache, context, targetProperties, mode }) => {
1114 /** @type {string[]} */
1115 const conditions = ["webpack"];
1116
1117 conditions.push(mode === "development" ? "development" : "production");
1118
1119 if (targetProperties) {
1120 if (targetProperties.webworker) conditions.push("worker");
1121 if (targetProperties.node) conditions.push("node");
1122 if (targetProperties.web) conditions.push("browser");
1123 if (targetProperties.electron) conditions.push("electron");
1124 if (targetProperties.nwjs) conditions.push("nwjs");
1125 }
1126
1127 const jsExtensions = [".js", ".json", ".wasm"];
1128
1129 const tp = targetProperties;
1130 const browserField =
1131 tp && tp.web && (!tp.node || (tp.electron && tp.electronRenderer));
1132
1133 /** @type {function(): ResolveOptions} */
1134 const cjsDeps = () => ({
1135 aliasFields: browserField ? ["browser"] : [],
1136 mainFields: browserField ? ["browser", "module", "..."] : ["module", "..."],
1137 conditionNames: ["require", "module", "..."],
1138 extensions: [...jsExtensions]
1139 });
1140 /** @type {function(): ResolveOptions} */
1141 const esmDeps = () => ({
1142 aliasFields: browserField ? ["browser"] : [],
1143 mainFields: browserField ? ["browser", "module", "..."] : ["module", "..."],
1144 conditionNames: ["import", "module", "..."],
1145 extensions: [...jsExtensions]
1146 });
1147
1148 /** @type {ResolveOptions} */
1149 const resolveOptions = {
1150 cache,
1151 modules: ["node_modules"],
1152 conditionNames: conditions,
1153 mainFiles: ["index"],
1154 extensions: [],
1155 aliasFields: [],
1156 exportsFields: ["exports"],
1157 roots: [context],
1158 mainFields: ["main"],
1159 byDependency: {
1160 wasm: esmDeps(),
1161 esm: esmDeps(),
1162 loaderImport: esmDeps(),
1163 url: {
1164 preferRelative: true
1165 },
1166 worker: {
1167 ...esmDeps(),
1168 preferRelative: true
1169 },
1170 commonjs: cjsDeps(),
1171 amd: cjsDeps(),
1172 // for backward-compat: loadModule
1173 loader: cjsDeps(),
1174 // for backward-compat: Custom Dependency
1175 unknown: cjsDeps(),
1176 // for backward-compat: getResolve without dependencyType
1177 undefined: cjsDeps()
1178 }
1179 };
1180
1181 return resolveOptions;
1182};
1183
1184/**
1185 * @param {Object} options options
1186 * @param {boolean} options.cache is cache enable
1187 * @returns {ResolveOptions} resolve options
1188 */
1189const getResolveLoaderDefaults = ({ cache }) => {
1190 /** @type {ResolveOptions} */
1191 const resolveOptions = {
1192 cache,
1193 conditionNames: ["loader", "require", "node"],
1194 exportsFields: ["exports"],
1195 mainFields: ["loader", "main"],
1196 extensions: [".js"],
1197 mainFiles: ["index"]
1198 };
1199
1200 return resolveOptions;
1201};
1202
1203/**
1204 * @param {InfrastructureLogging} infrastructureLogging options
1205 * @returns {void}
1206 */
1207const applyInfrastructureLoggingDefaults = infrastructureLogging => {
1208 F(infrastructureLogging, "stream", () => process.stderr);
1209 const tty =
1210 /** @type {any} */ (infrastructureLogging.stream).isTTY &&
1211 process.env.TERM !== "dumb";
1212 D(infrastructureLogging, "level", "info");
1213 D(infrastructureLogging, "debug", false);
1214 D(infrastructureLogging, "colors", tty);
1215 D(infrastructureLogging, "appendOnly", !tty);
1216};
1217
1218exports.applyWebpackOptionsBaseDefaults = applyWebpackOptionsBaseDefaults;
1219exports.applyWebpackOptionsDefaults = applyWebpackOptionsDefaults;