Merge pull request #17247 from webpack/refactor-strict-types-for-config

refactor: `strict` for config
This commit is contained in:
Sean Larkin 2023-05-24 07:17:37 -07:00 committed by GitHub
commit 4ca7c01e7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 356 additions and 155 deletions

View File

@ -23,7 +23,7 @@ const inputRx = /^(?:((?:[A-Z]:)?[/\\].*?))?(?::(.+?))?$/i;
*/ */
/** /**
* @param {string} input input string * @param {string | null | undefined} input input string
* @param {string} context the context directory * @param {string} context the context directory
* @returns {BrowserslistHandlerConfig} config * @returns {BrowserslistHandlerConfig} config
*/ */
@ -47,7 +47,7 @@ const parse = (input, context) => {
}; };
/** /**
* @param {string} input input string * @param {string | null | undefined} input input string
* @param {string} context the context directory * @param {string} context the context directory
* @returns {string[] | undefined} selected browsers * @returns {string[] | undefined} selected browsers
*/ */
@ -66,7 +66,7 @@ const load = (input, context) => {
}) })
: browserslist.loadConfig({ path: context, env }); : browserslist.loadConfig({ path: context, env });
if (!config) return null; if (!config) return;
return browserslist(config); return browserslist(config);
}; };

View File

@ -25,30 +25,39 @@ const {
} = require("./target"); } = require("./target");
/** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptions */ /** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptions */
/** @typedef {import("../../declarations/WebpackOptions").Context} Context */
/** @typedef {import("../../declarations/WebpackOptions").CssExperimentOptions} CssExperimentOptions */ /** @typedef {import("../../declarations/WebpackOptions").CssExperimentOptions} CssExperimentOptions */
/** @typedef {import("../../declarations/WebpackOptions").EntryDescription} EntryDescription */ /** @typedef {import("../../declarations/WebpackOptions").EntryDescription} EntryDescription */
/** @typedef {import("../../declarations/WebpackOptions").EntryNormalized} Entry */ /** @typedef {import("../../declarations/WebpackOptions").EntryNormalized} Entry */
/** @typedef {import("../../declarations/WebpackOptions").EntryStaticNormalized} EntryStaticNormalized */
/** @typedef {import("../../declarations/WebpackOptions").Environment} Environment */
/** @typedef {import("../../declarations/WebpackOptions").Experiments} Experiments */ /** @typedef {import("../../declarations/WebpackOptions").Experiments} Experiments */
/** @typedef {import("../../declarations/WebpackOptions").ExperimentsNormalized} ExperimentsNormalized */ /** @typedef {import("../../declarations/WebpackOptions").ExperimentsNormalized} ExperimentsNormalized */
/** @typedef {import("../../declarations/WebpackOptions").ExternalsPresets} ExternalsPresets */ /** @typedef {import("../../declarations/WebpackOptions").ExternalsPresets} ExternalsPresets */
/** @typedef {import("../../declarations/WebpackOptions").ExternalsType} ExternalsType */ /** @typedef {import("../../declarations/WebpackOptions").ExternalsType} ExternalsType */
/** @typedef {import("../../declarations/WebpackOptions").FileCacheOptions} FileCacheOptions */
/** @typedef {import("../../declarations/WebpackOptions").InfrastructureLogging} InfrastructureLogging */ /** @typedef {import("../../declarations/WebpackOptions").InfrastructureLogging} InfrastructureLogging */
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */ /** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
/** @typedef {import("../../declarations/WebpackOptions").Library} Library */ /** @typedef {import("../../declarations/WebpackOptions").Library} Library */
/** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */ /** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */
/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */ /** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
/** @typedef {import("../../declarations/WebpackOptions").LibraryType} LibraryType */
/** @typedef {import("../../declarations/WebpackOptions").Loader} Loader */ /** @typedef {import("../../declarations/WebpackOptions").Loader} Loader */
/** @typedef {import("../../declarations/WebpackOptions").Mode} Mode */ /** @typedef {import("../../declarations/WebpackOptions").Mode} Mode */
/** @typedef {import("../../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */ /** @typedef {import("../../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */
/** @typedef {import("../../declarations/WebpackOptions").Node} WebpackNode */ /** @typedef {import("../../declarations/WebpackOptions").Node} WebpackNode */
/** @typedef {import("../../declarations/WebpackOptions").Optimization} Optimization */ /** @typedef {import("../../declarations/WebpackOptions").Optimization} Optimization */
/** @typedef {import("../../declarations/WebpackOptions").OptimizationSplitChunksOptions} OptimizationSplitChunksOptions */
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */ /** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */
/** @typedef {import("../../declarations/WebpackOptions").ParserOptionsByModuleTypeKnown} ParserOptionsByModuleTypeKnown */
/** @typedef {import("../../declarations/WebpackOptions").Performance} Performance */ /** @typedef {import("../../declarations/WebpackOptions").Performance} Performance */
/** @typedef {import("../../declarations/WebpackOptions").ResolveOptions} ResolveOptions */ /** @typedef {import("../../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
/** @typedef {import("../../declarations/WebpackOptions").RuleSetRules} RuleSetRules */ /** @typedef {import("../../declarations/WebpackOptions").RuleSetRules} RuleSetRules */
/** @typedef {import("../../declarations/WebpackOptions").SnapshotOptions} SnapshotOptions */ /** @typedef {import("../../declarations/WebpackOptions").SnapshotOptions} SnapshotOptions */
/** @typedef {import("../../declarations/WebpackOptions").Target} Target */ /** @typedef {import("../../declarations/WebpackOptions").Target} Target */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */ /** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("./target").TargetProperties} TargetProperties */ /** @typedef {import("./target").TargetProperties} TargetProperties */
const NODE_MODULES_REGEXP = /[\\/]node_modules[\\/]/i; const NODE_MODULES_REGEXP = /[\\/]node_modules[\\/]/i;
@ -100,7 +109,7 @@ const A = (obj, prop, factory) => {
if (value === undefined) { if (value === undefined) {
obj[prop] = factory(); obj[prop] = factory();
} else if (Array.isArray(value)) { } else if (Array.isArray(value)) {
/** @type {any[]} */ /** @type {any[] | undefined} */
let newArray = undefined; let newArray = undefined;
for (let i = 0; i < value.length; i++) { for (let i = 0; i < value.length; i++) {
const item = value[i]; const item = value[i];
@ -138,7 +147,7 @@ const applyWebpackOptionsBaseDefaults = options => {
const applyWebpackOptionsDefaults = options => { const applyWebpackOptionsDefaults = options => {
F(options, "context", () => process.cwd()); F(options, "context", () => process.cwd());
F(options, "target", () => { F(options, "target", () => {
return getDefaultTarget(options.context); return getDefaultTarget(/** @type {string} */ (options.context));
}); });
const { mode, name, target } = options; const { mode, name, target } = options;
@ -147,8 +156,11 @@ const applyWebpackOptionsDefaults = options => {
target === false target === false
? /** @type {false} */ (false) ? /** @type {false} */ (false)
: typeof target === "string" : typeof target === "string"
? getTargetProperties(target, options.context) ? getTargetProperties(target, /** @type {Context} */ (options.context))
: getTargetsProperties(target, options.context); : getTargetsProperties(
/** @type {string[]} */ (target),
/** @type {Context} */ (options.context)
);
const development = mode === "development"; const development = mode === "development";
const production = mode === "production" || !mode; const production = mode === "production" || !mode;
@ -176,7 +188,9 @@ const applyWebpackOptionsDefaults = options => {
targetProperties targetProperties
}); });
const futureDefaults = options.experiments.futureDefaults; const futureDefaults =
/** @type {NonNullable<ExperimentsNormalized["futureDefaults"]>} */
(options.experiments.futureDefaults);
F(options, "cache", () => F(options, "cache", () =>
development ? { type: /** @type {"memory"} */ ("memory") } : false development ? { type: /** @type {"memory"} */ ("memory") } : false
@ -196,22 +210,30 @@ const applyWebpackOptionsDefaults = options => {
applyModuleDefaults(options.module, { applyModuleDefaults(options.module, {
cache, cache,
syncWebAssembly: options.experiments.syncWebAssembly, syncWebAssembly:
asyncWebAssembly: options.experiments.asyncWebAssembly, /** @type {NonNullable<ExperimentsNormalized["syncWebAssembly"]>} */
css: options.experiments.css, (options.experiments.syncWebAssembly),
asyncWebAssembly:
/** @type {NonNullable<ExperimentsNormalized["asyncWebAssembly"]>} */
(options.experiments.asyncWebAssembly),
css:
/** @type {NonNullable<ExperimentsNormalized["css"]>} */
(options.experiments.css),
futureDefaults, futureDefaults,
isNode: targetProperties && targetProperties.node === true isNode: targetProperties && targetProperties.node === true
}); });
applyOutputDefaults(options.output, { applyOutputDefaults(options.output, {
context: options.context, context: /** @type {Context} */ (options.context),
targetProperties, targetProperties,
isAffectedByBrowserslist: isAffectedByBrowserslist:
target === undefined || target === undefined ||
(typeof target === "string" && target.startsWith("browserslist")) || (typeof target === "string" && target.startsWith("browserslist")) ||
(Array.isArray(target) && (Array.isArray(target) &&
target.some(target => target.startsWith("browserslist"))), target.some(target => target.startsWith("browserslist"))),
outputModule: options.experiments.outputModule, outputModule:
/** @type {NonNullable<ExperimentsNormalized["outputModule"]>} */
(options.experiments.outputModule),
development, development,
entry: options.entry, entry: options.entry,
module: options.module, module: options.module,
@ -223,7 +245,10 @@ const applyWebpackOptionsDefaults = options => {
buildHttp: !!options.experiments.buildHttp buildHttp: !!options.experiments.buildHttp
}); });
applyLoaderDefaults(options.loader, { targetProperties }); applyLoaderDefaults(
/** @type {NonNullable<WebpackOptions["loader"]>} */ (options.loader),
{ targetProperties }
);
F(options, "externalsType", () => { F(options, "externalsType", () => {
const validExternalTypes = require("../../schemas/WebpackOptions.json") const validExternalTypes = require("../../schemas/WebpackOptions.json")
@ -237,7 +262,9 @@ const applyWebpackOptionsDefaults = options => {
}); });
applyNodeDefaults(options.node, { applyNodeDefaults(options.node, {
futureDefaults: options.experiments.futureDefaults, futureDefaults:
/** @type {NonNullable<WebpackOptions["experiments"]["futureDefaults"]>} */
(options.experiments.futureDefaults),
targetProperties targetProperties
}); });
@ -248,23 +275,29 @@ const applyWebpackOptionsDefaults = options => {
? {} ? {}
: false : false
); );
applyPerformanceDefaults(options.performance, { applyPerformanceDefaults(
production /** @type {NonNullable<WebpackOptions["performance"]>} */
}); (options.performance),
{
production
}
);
applyOptimizationDefaults(options.optimization, { applyOptimizationDefaults(options.optimization, {
development, development,
production, production,
css: options.experiments.css, css:
/** @type {NonNullable<ExperimentsNormalized["css"]>} */
(options.experiments.css),
records: !!(options.recordsInputPath || options.recordsOutputPath) records: !!(options.recordsInputPath || options.recordsOutputPath)
}); });
options.resolve = cleverMerge( options.resolve = cleverMerge(
getResolveDefaults({ getResolveDefaults({
cache, cache,
context: options.context, context: /** @type {Context} */ (options.context),
targetProperties, targetProperties,
mode: options.mode mode: /** @type {Mode} */ (options.mode)
}), }),
options.resolve options.resolve
); );
@ -323,9 +356,9 @@ const applyExperimentsDefaults = (
* @param {CacheOptions} cache options * @param {CacheOptions} cache options
* @param {Object} options options * @param {Object} options options
* @param {string} options.name name * @param {string} options.name name
* @param {string} options.mode mode * @param {Mode} options.mode mode
* @param {boolean} options.development is development mode * @param {boolean} options.development is development mode
* @param {boolean} options.cacheUnaffected the cacheUnaffected experiment is enabled * @param {Experiments["cacheUnaffected"]} options.cacheUnaffected the cacheUnaffected experiment is enabled
* @returns {void} * @returns {void}
*/ */
const applyCacheDefaults = ( const applyCacheDefaults = (
@ -339,6 +372,7 @@ const applyCacheDefaults = (
D(cache, "version", ""); D(cache, "version", "");
F(cache, "cacheDirectory", () => { F(cache, "cacheDirectory", () => {
const cwd = process.cwd(); const cwd = process.cwd();
/** @type {string | undefined} */
let dir = cwd; let dir = cwd;
for (;;) { for (;;) {
try { try {
@ -363,7 +397,11 @@ const applyCacheDefaults = (
} }
}); });
F(cache, "cacheLocation", () => F(cache, "cacheLocation", () =>
path.resolve(cache.cacheDirectory, cache.name) path.resolve(
/** @type {NonNullable<FileCacheOptions["cacheDirectory"]>} */
(cache.cacheDirectory),
/** @type {NonNullable<FileCacheOptions["name"]>} */ (cache.name)
)
); );
D(cache, "hashAlgorithm", "md4"); D(cache, "hashAlgorithm", "md4");
D(cache, "store", "pack"); D(cache, "store", "pack");
@ -376,9 +414,12 @@ const applyCacheDefaults = (
D(cache, "maxAge", 1000 * 60 * 60 * 24 * 60); // 1 month D(cache, "maxAge", 1000 * 60 * 60 * 24 * 60); // 1 month
D(cache, "allowCollectingMemory", development); D(cache, "allowCollectingMemory", development);
D(cache, "memoryCacheUnaffected", development && cacheUnaffected); D(cache, "memoryCacheUnaffected", development && cacheUnaffected);
D(cache.buildDependencies, "defaultWebpack", [ D(
path.resolve(__dirname, "..") + path.sep /** @type {NonNullable<FileCacheOptions["buildDependencies"]>} */
]); (cache.buildDependencies),
"defaultWebpack",
[path.resolve(__dirname, "..") + path.sep]
);
break; break;
case "memory": case "memory":
D(cache, "maxGenerations", Infinity); D(cache, "maxGenerations", Infinity);
@ -510,25 +551,53 @@ const applyModuleDefaults = (
{ cache, syncWebAssembly, asyncWebAssembly, css, futureDefaults, isNode } { cache, syncWebAssembly, asyncWebAssembly, css, futureDefaults, isNode }
) => { ) => {
if (cache) { if (cache) {
D(module, "unsafeCache", module => { D(
const name = module.nameForCondition(); module,
return name && NODE_MODULES_REGEXP.test(name); "unsafeCache",
}); /**
* @param {Module} module module
* @returns {boolean | null | string} true, if we want to cache the module
*/
module => {
const name = module.nameForCondition();
return name && NODE_MODULES_REGEXP.test(name);
}
);
} else { } else {
D(module, "unsafeCache", false); D(module, "unsafeCache", false);
} }
F(module.parser, ASSET_MODULE_TYPE, () => ({})); F(module.parser, ASSET_MODULE_TYPE, () => ({}));
F(module.parser.asset, "dataUrlCondition", () => ({})); F(
if (typeof module.parser.asset.dataUrlCondition === "object") { /** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */
D(module.parser.asset.dataUrlCondition, "maxSize", 8096); (module.parser.asset),
"dataUrlCondition",
() => ({})
);
if (
typeof (
/** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */
(module.parser.asset).dataUrlCondition
) === "object"
) {
D(
/** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */
(module.parser.asset).dataUrlCondition,
"maxSize",
8096
);
} }
F(module.parser, "javascript", () => ({})); F(module.parser, "javascript", () => ({}));
applyJavascriptParserOptionsDefaults(module.parser.javascript, {
futureDefaults, applyJavascriptParserOptionsDefaults(
isNode /** @type {NonNullable<ParserOptionsByModuleTypeKnown["javascript"]>} */
}); (module.parser.javascript),
{
futureDefaults,
isNode
}
);
A(module, "defaultRules", () => { A(module, "defaultRules", () => {
const esm = { const esm = {
@ -726,7 +795,7 @@ const applyOutputDefaults = (
!Array.isArray(library) && !Array.isArray(library) &&
"type" in library "type" in library
? library.name ? library.name
: /** @type {LibraryName=} */ (library); : /** @type {LibraryName} */ (library);
if (Array.isArray(libraryName)) { if (Array.isArray(libraryName)) {
return libraryName.join("."); return libraryName.join(".");
} else if (typeof libraryName === "object") { } else if (typeof libraryName === "object") {
@ -753,8 +822,11 @@ const applyOutputDefaults = (
const packageInfo = JSON.parse(fs.readFileSync(pkgPath, "utf-8")); const packageInfo = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
return packageInfo.name || ""; return packageInfo.name || "";
} catch (e) { } catch (e) {
if (e.code !== "ENOENT") { if (/** @type {Error & { code: string }} */ (e).code !== "ENOENT") {
e.message += `\nwhile determining default 'output.uniqueName' from 'name' in ${pkgPath}`; /** @type {Error & { code: string }} */
(
e
).message += `\nwhile determining default 'output.uniqueName' from 'name' in ${pkgPath}`;
throw e; throw e;
} }
return ""; return "";
@ -767,7 +839,9 @@ const applyOutputDefaults = (
D(output, "importFunctionName", "import"); D(output, "importFunctionName", "import");
D(output, "importMetaName", "import.meta"); D(output, "importMetaName", "import.meta");
F(output, "chunkFilename", () => { F(output, "chunkFilename", () => {
const filename = output.filename; const filename =
/** @type {NonNullable<Output["chunkFilename"]>} */
(output.filename);
if (typeof filename !== "function") { if (typeof filename !== "function") {
const hasName = filename.includes("[name]"); const hasName = filename.includes("[name]");
const hasId = filename.includes("[id]"); const hasId = filename.includes("[id]");
@ -781,14 +855,18 @@ const applyOutputDefaults = (
return output.module ? "[id].mjs" : "[id].js"; return output.module ? "[id].mjs" : "[id].js";
}); });
F(output, "cssFilename", () => { F(output, "cssFilename", () => {
const filename = output.filename; const filename =
/** @type {NonNullable<Output["cssFilename"]>} */
(output.filename);
if (typeof filename !== "function") { if (typeof filename !== "function") {
return filename.replace(/\.[mc]?js(\?|$)/, ".css$1"); return filename.replace(/\.[mc]?js(\?|$)/, ".css$1");
} }
return "[id].css"; return "[id].css";
}); });
F(output, "cssChunkFilename", () => { F(output, "cssChunkFilename", () => {
const chunkFilename = output.chunkFilename; const chunkFilename =
/** @type {NonNullable<Output["cssChunkFilename"]>} */
(output.chunkFilename);
if (typeof chunkFilename !== "function") { if (typeof chunkFilename !== "function") {
return chunkFilename.replace(/\.[mc]?js(\?|$)/, ".css$1"); return chunkFilename.replace(/\.[mc]?js(\?|$)/, ".css$1");
} }
@ -800,12 +878,18 @@ const applyOutputDefaults = (
D(output, "charset", true); D(output, "charset", true);
F(output, "hotUpdateGlobal", () => F(output, "hotUpdateGlobal", () =>
Template.toIdentifier( Template.toIdentifier(
"webpackHotUpdate" + Template.toIdentifier(output.uniqueName) "webpackHotUpdate" +
Template.toIdentifier(
/** @type {NonNullable<Output["uniqueName"]>} */ (output.uniqueName)
)
) )
); );
F(output, "chunkLoadingGlobal", () => F(output, "chunkLoadingGlobal", () =>
Template.toIdentifier( Template.toIdentifier(
"webpackChunk" + Template.toIdentifier(output.uniqueName) "webpackChunk" +
Template.toIdentifier(
/** @type {NonNullable<Output["uniqueName"]>} */ (output.uniqueName)
)
) )
); );
F(output, "globalObject", () => { F(output, "globalObject", () => {
@ -938,26 +1022,56 @@ const applyOutputDefaults = (
D(output, "hashDigestLength", futureDefaults ? 16 : 20); D(output, "hashDigestLength", futureDefaults ? 16 : 20);
D(output, "strictModuleExceptionHandling", false); D(output, "strictModuleExceptionHandling", false);
const environment = /** @type {Environment} */ (output.environment);
/**
* @param {boolean | undefined} v value
* @returns {boolean} true, when v is truthy or undefined
*/
const optimistic = v => v || v === undefined; const optimistic = v => v || v === undefined;
/**
* @param {boolean | undefined} v value
* @param {boolean | undefined} c condition
* @returns {boolean | undefined} true, when v is truthy or undefined, or c is truthy
*/
const conditionallyOptimistic = (v, c) => (v === undefined && c) || v; const conditionallyOptimistic = (v, c) => (v === undefined && c) || v;
F( F(
output.environment, environment,
"arrowFunction", "arrowFunction",
() => tp && optimistic(tp.arrowFunction) () =>
tp && optimistic(/** @type {boolean | undefined} */ (tp.arrowFunction))
); );
F(output.environment, "const", () => tp && optimistic(tp.const));
F( F(
output.environment, environment,
"const",
() => tp && optimistic(/** @type {boolean | undefined} */ (tp.const))
);
F(
environment,
"destructuring", "destructuring",
() => tp && optimistic(tp.destructuring) () =>
tp && optimistic(/** @type {boolean | undefined} */ (tp.destructuring))
); );
F(output.environment, "forOf", () => tp && optimistic(tp.forOf)); F(
F(output.environment, "bigIntLiteral", () => tp && tp.bigIntLiteral); environment,
F(output.environment, "dynamicImport", () => "forOf",
conditionallyOptimistic(tp && tp.dynamicImport, output.module) () => tp && optimistic(/** @type {boolean | undefined} */ (tp.forOf))
); );
F(output.environment, "module", () => F(
conditionallyOptimistic(tp && tp.module, output.module) environment,
"bigIntLiteral",
() => /** @type {boolean | undefined} */ (tp && tp.bigIntLiteral)
);
F(environment, "dynamicImport", () =>
conditionallyOptimistic(
/** @type {boolean | undefined} */ (tp && tp.dynamicImport),
output.module
)
);
F(environment, "module", () =>
conditionallyOptimistic(
/** @type {boolean | undefined} */ (tp && tp.module),
output.module
)
); );
const { trustedTypes } = output; const { trustedTypes } = output;
@ -966,7 +1080,8 @@ const applyOutputDefaults = (
trustedTypes, trustedTypes,
"policyName", "policyName",
() => () =>
output.uniqueName.replace(/[^a-zA-Z0-9\-#=_/@.%]+/g, "_") || "webpack" /** @type {NonNullable<Output["uniqueName"]>} */
(output.uniqueName).replace(/[^a-zA-Z0-9\-#=_/@.%]+/g, "_") || "webpack"
); );
D(trustedTypes, "onPolicyCreationFailure", "stop"); D(trustedTypes, "onPolicyCreationFailure", "stop");
} }
@ -977,10 +1092,11 @@ const applyOutputDefaults = (
*/ */
const forEachEntry = fn => { const forEachEntry = fn => {
for (const name of Object.keys(entry)) { for (const name of Object.keys(entry)) {
fn(entry[name]); fn(/** @type {{[k: string] : EntryDescription}} */ (entry)[name]);
} }
}; };
A(output, "enabledLibraryTypes", () => { A(output, "enabledLibraryTypes", () => {
/** @type {LibraryType[]} */
const enabledLibraryTypes = []; const enabledLibraryTypes = [];
if (output.library) { if (output.library) {
enabledLibraryTypes.push(output.library.type); enabledLibraryTypes.push(output.library.type);
@ -1040,35 +1156,56 @@ const applyExternalsPresetsDefaults = (
D( D(
externalsPresets, externalsPresets,
"web", "web",
!buildHttp && targetProperties && targetProperties.web /** @type {boolean | undefined} */
(!buildHttp && targetProperties && targetProperties.web)
);
D(
externalsPresets,
"node",
/** @type {boolean | undefined} */
(targetProperties && targetProperties.node)
);
D(
externalsPresets,
"nwjs",
/** @type {boolean | undefined} */
(targetProperties && targetProperties.nwjs)
); );
D(externalsPresets, "node", targetProperties && targetProperties.node);
D(externalsPresets, "nwjs", targetProperties && targetProperties.nwjs);
D( D(
externalsPresets, externalsPresets,
"electron", "electron",
targetProperties && targetProperties.electron /** @type {boolean | undefined} */
(targetProperties && targetProperties.electron)
); );
D( D(
externalsPresets, externalsPresets,
"electronMain", "electronMain",
targetProperties && /** @type {boolean | undefined} */
targetProperties.electron && (
targetProperties.electronMain targetProperties &&
targetProperties.electron &&
targetProperties.electronMain
)
); );
D( D(
externalsPresets, externalsPresets,
"electronPreload", "electronPreload",
targetProperties && /** @type {boolean | undefined} */
targetProperties.electron && (
targetProperties.electronPreload targetProperties &&
targetProperties.electron &&
targetProperties.electronPreload
)
); );
D( D(
externalsPresets, externalsPresets,
"electronRenderer", "electronRenderer",
targetProperties && /** @type {boolean | undefined} */
targetProperties.electron && (
targetProperties.electronRenderer targetProperties &&
targetProperties.electron &&
targetProperties.electronRenderer
)
); );
}; };
@ -1209,7 +1346,9 @@ const applyOptimizationDefaults = (
F(splitChunks, "maxAsyncRequests", () => (production ? 30 : Infinity)); F(splitChunks, "maxAsyncRequests", () => (production ? 30 : Infinity));
F(splitChunks, "maxInitialRequests", () => (production ? 30 : Infinity)); F(splitChunks, "maxInitialRequests", () => (production ? 30 : Infinity));
D(splitChunks, "automaticNameDelimiter", "-"); D(splitChunks, "automaticNameDelimiter", "-");
const { cacheGroups } = splitChunks; const cacheGroups =
/** @type {NonNullable<OptimizationSplitChunksOptions["cacheGroups"]>} */
(splitChunks.cacheGroups);
F(cacheGroups, "default", () => ({ F(cacheGroups, "default", () => ({
idHint: "", idHint: "",
reuseExistingChunk: true, reuseExistingChunk: true,

View File

@ -7,17 +7,28 @@
const util = require("util"); const util = require("util");
/** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptions */
/** @typedef {import("../../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescriptionNormalized */
/** @typedef {import("../../declarations/WebpackOptions").EntryStatic} EntryStatic */ /** @typedef {import("../../declarations/WebpackOptions").EntryStatic} EntryStatic */
/** @typedef {import("../../declarations/WebpackOptions").EntryStaticNormalized} EntryStaticNormalized */ /** @typedef {import("../../declarations/WebpackOptions").EntryStaticNormalized} EntryStaticNormalized */
/** @typedef {import("../../declarations/WebpackOptions").Externals} Externals */
/** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */ /** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */
/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */ /** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
/** @typedef {import("../../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptionsNormalized */
/** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunk} OptimizationRuntimeChunk */ /** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunk} OptimizationRuntimeChunk */
/** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunkNormalized} OptimizationRuntimeChunkNormalized */ /** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunkNormalized} OptimizationRuntimeChunkNormalized */
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputNormalized */ /** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputNormalized */
/** @typedef {import("../../declarations/WebpackOptions").Plugins} Plugins */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptions} WebpackOptions */ /** @typedef {import("../../declarations/WebpackOptions").WebpackOptions} WebpackOptions */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptionsNormalized */ /** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptionsNormalized */
/** @typedef {import("../Entrypoint")} Entrypoint */
const handledDeprecatedNoEmitOnErrors = util.deprecate( const handledDeprecatedNoEmitOnErrors = util.deprecate(
/**
* @param {boolean} noEmitOnErrors no emit on errors
* @param {boolean | undefined} emitOnErrors emit on errors
* @returns {boolean} emit on errors
*/
(noEmitOnErrors, emitOnErrors) => { (noEmitOnErrors, emitOnErrors) => {
if (emitOnErrors !== undefined && !noEmitOnErrors === !emitOnErrors) { if (emitOnErrors !== undefined && !noEmitOnErrors === !emitOnErrors) {
throw new Error( throw new Error(
@ -117,45 +128,50 @@ const getNormalizedWebpackOptions = config => {
return { return {
amd: config.amd, amd: config.amd,
bail: config.bail, bail: config.bail,
cache: optionalNestedConfig(config.cache, cache => { cache:
if (cache === false) return false; /** @type {NonNullable<CacheOptions>} */
if (cache === true) { (
return { optionalNestedConfig(config.cache, cache => {
type: "memory", if (cache === false) return false;
maxGenerations: undefined if (cache === true) {
}; return {
} type: "memory",
switch (cache.type) { maxGenerations: undefined
case "filesystem": };
return { }
type: "filesystem", switch (cache.type) {
allowCollectingMemory: cache.allowCollectingMemory, case "filesystem":
maxMemoryGenerations: cache.maxMemoryGenerations, return {
maxAge: cache.maxAge, type: "filesystem",
profile: cache.profile, allowCollectingMemory: cache.allowCollectingMemory,
buildDependencies: cloneObject(cache.buildDependencies), maxMemoryGenerations: cache.maxMemoryGenerations,
cacheDirectory: cache.cacheDirectory, maxAge: cache.maxAge,
cacheLocation: cache.cacheLocation, profile: cache.profile,
hashAlgorithm: cache.hashAlgorithm, buildDependencies: cloneObject(cache.buildDependencies),
compression: cache.compression, cacheDirectory: cache.cacheDirectory,
idleTimeout: cache.idleTimeout, cacheLocation: cache.cacheLocation,
idleTimeoutForInitialStore: cache.idleTimeoutForInitialStore, hashAlgorithm: cache.hashAlgorithm,
idleTimeoutAfterLargeChanges: cache.idleTimeoutAfterLargeChanges, compression: cache.compression,
name: cache.name, idleTimeout: cache.idleTimeout,
store: cache.store, idleTimeoutForInitialStore: cache.idleTimeoutForInitialStore,
version: cache.version idleTimeoutAfterLargeChanges:
}; cache.idleTimeoutAfterLargeChanges,
case undefined: name: cache.name,
case "memory": store: cache.store,
return { version: cache.version
type: "memory", };
maxGenerations: cache.maxGenerations case undefined:
}; case "memory":
default: return {
// @ts-expect-error Property 'type' does not exist on type 'never'. ts(2339) type: "memory",
throw new Error(`Not implemented cache.type ${cache.type}`); maxGenerations: cache.maxGenerations
} };
}), default:
// @ts-expect-error Property 'type' does not exist on type 'never'. ts(2339)
throw new Error(`Not implemented cache.type ${cache.type}`);
}
})
),
context: config.context, context: config.context,
dependencies: config.dependencies, dependencies: config.dependencies,
devServer: optionalNestedConfig(config.devServer, devServer => ({ devServer: optionalNestedConfig(config.devServer, devServer => ({
@ -184,7 +200,7 @@ const getNormalizedWebpackOptions = config => {
options === true ? {} : options options === true ? {} : options
) )
})), })),
externals: config.externals, externals: /** @type {NonNullable<Externals>} */ (config.externals),
externalsPresets: cloneObject(config.externalsPresets), externalsPresets: cloneObject(config.externalsPresets),
externalsType: config.externalsType, externalsType: config.externalsType,
ignoreWarnings: config.ignoreWarnings ignoreWarnings: config.ignoreWarnings
@ -215,32 +231,36 @@ const getNormalizedWebpackOptions = config => {
infrastructureLogging: cloneObject(config.infrastructureLogging), infrastructureLogging: cloneObject(config.infrastructureLogging),
loader: cloneObject(config.loader), loader: cloneObject(config.loader),
mode: config.mode, mode: config.mode,
module: nestedConfig(config.module, module => ({ module:
noParse: module.noParse, /** @type {ModuleOptionsNormalized} */
unsafeCache: module.unsafeCache, (
parser: keyedNestedConfig(module.parser, cloneObject, { nestedConfig(config.module, module => ({
javascript: parserOptions => ({ noParse: module.noParse,
unknownContextRequest: module.unknownContextRequest, unsafeCache: module.unsafeCache,
unknownContextRegExp: module.unknownContextRegExp, parser: keyedNestedConfig(module.parser, cloneObject, {
unknownContextRecursive: module.unknownContextRecursive, javascript: parserOptions => ({
unknownContextCritical: module.unknownContextCritical, unknownContextRequest: module.unknownContextRequest,
exprContextRequest: module.exprContextRequest, unknownContextRegExp: module.unknownContextRegExp,
exprContextRegExp: module.exprContextRegExp, unknownContextRecursive: module.unknownContextRecursive,
exprContextRecursive: module.exprContextRecursive, unknownContextCritical: module.unknownContextCritical,
exprContextCritical: module.exprContextCritical, exprContextRequest: module.exprContextRequest,
wrappedContextRegExp: module.wrappedContextRegExp, exprContextRegExp: module.exprContextRegExp,
wrappedContextRecursive: module.wrappedContextRecursive, exprContextRecursive: module.exprContextRecursive,
wrappedContextCritical: module.wrappedContextCritical, exprContextCritical: module.exprContextCritical,
// TODO webpack 6 remove wrappedContextRegExp: module.wrappedContextRegExp,
strictExportPresence: module.strictExportPresence, wrappedContextRecursive: module.wrappedContextRecursive,
strictThisContextOnImports: module.strictThisContextOnImports, wrappedContextCritical: module.wrappedContextCritical,
...parserOptions // TODO webpack 6 remove
}) strictExportPresence: module.strictExportPresence,
}), strictThisContextOnImports: module.strictThisContextOnImports,
generator: cloneObject(module.generator), ...parserOptions
defaultRules: optionalNestedArray(module.defaultRules, r => [...r]), })
rules: nestedArray(module.rules, r => [...r]) }),
})), generator: cloneObject(module.generator),
defaultRules: optionalNestedArray(module.defaultRules, r => [...r]),
rules: nestedArray(module.rules, r => [...r])
}))
),
name: config.name, name: config.name,
node: nestedConfig( node: nestedConfig(
config.node, config.node,
@ -387,7 +407,7 @@ const getNormalizedWebpackOptions = config => {
...performance ...performance
}; };
}), }),
plugins: nestedArray(config.plugins, p => [...p]), plugins: /** @type {Plugins} */ (nestedArray(config.plugins, p => [...p])),
profile: config.profile, profile: config.profile,
recordsInputPath: recordsInputPath:
config.recordsInputPath !== undefined config.recordsInputPath !== undefined
@ -488,8 +508,11 @@ const getNormalizedEntryStatic = entry => {
} else { } else {
result[key] = { result[key] = {
import: import:
value.import && /** @type {EntryDescriptionNormalized["import"]} */
(Array.isArray(value.import) ? value.import : [value.import]), (
value.import &&
(Array.isArray(value.import) ? value.import : [value.import])
),
filename: value.filename, filename: value.filename,
layer: value.layer, layer: value.layer,
runtime: value.runtime, runtime: value.runtime,
@ -499,8 +522,13 @@ const getNormalizedEntryStatic = entry => {
asyncChunks: value.asyncChunks, asyncChunks: value.asyncChunks,
wasmLoading: value.wasmLoading, wasmLoading: value.wasmLoading,
dependOn: dependOn:
value.dependOn && /** @type {EntryDescriptionNormalized["dependOn"]} */
(Array.isArray(value.dependOn) ? value.dependOn : [value.dependOn]), (
value.dependOn &&
(Array.isArray(value.dependOn)
? value.dependOn
: [value.dependOn])
),
library: value.library library: value.library
}; };
} }
@ -522,6 +550,10 @@ const getNormalizedOptimizationRuntimeChunk = runtimeChunk => {
} }
if (runtimeChunk === true || runtimeChunk === "multiple") { if (runtimeChunk === true || runtimeChunk === "multiple") {
return { return {
/**
* @param {Entrypoint} entrypoint entrypoint
* @returns {string} runtime chunk name
*/
name: entrypoint => `runtime~${entrypoint.name}` name: entrypoint => `runtime~${entrypoint.name}`
}; };
} }

View File

@ -64,20 +64,39 @@ const getDefaultTarget = context => {
*/ */
///** @typedef {PlatformTargetProperties | ApiTargetProperties | EcmaTargetProperties | PlatformTargetProperties & ApiTargetProperties | PlatformTargetProperties & EcmaTargetProperties | ApiTargetProperties & EcmaTargetProperties} TargetProperties */ ///** @typedef {PlatformTargetProperties | ApiTargetProperties | EcmaTargetProperties | PlatformTargetProperties & ApiTargetProperties | PlatformTargetProperties & EcmaTargetProperties | ApiTargetProperties & EcmaTargetProperties} TargetProperties */
/** @template T @typedef {{ [P in keyof T]?: never }} Never<T> */
/** @template A @template B @typedef {(A & Never<B>) | (Never<A> & B) | (A & B)} Mix<A,B> */ /**
* @template T
* @typedef {{ [P in keyof T]?: never }} Never<T>
*/
/**
* @template A
* @template B
* @typedef {(A & Never<B>) | (Never<A> & B) | (A & B)} Mix<A, B>
*/
/** @typedef {Mix<Mix<PlatformTargetProperties, ElectronContextTargetProperties>, Mix<ApiTargetProperties, EcmaTargetProperties>>} TargetProperties */ /** @typedef {Mix<Mix<PlatformTargetProperties, ElectronContextTargetProperties>, Mix<ApiTargetProperties, EcmaTargetProperties>>} TargetProperties */
/**
* @param {string} major major version
* @param {string | undefined} minor minor version
* @returns {(vMajor: number, vMinor?: number) => boolean | undefined} check if version is greater or equal
*/
const versionDependent = (major, minor) => { const versionDependent = (major, minor) => {
if (!major) return () => /** @type {undefined} */ (undefined); if (!major) {
major = +major; return () => /** @type {undefined} */ (undefined);
minor = minor ? +minor : 0; }
/** @type {number} */
const nMajor = +major;
/** @type {number} */
const nMinor = minor ? +minor : 0;
return (vMajor, vMinor = 0) => { return (vMajor, vMinor = 0) => {
return major > vMajor || (major === vMajor && minor >= vMinor); return nMajor > vMajor || (nMajor === vMajor && nMinor >= vMinor);
}; };
}; };
/** @type {[string, string, RegExp, (...args: string[]) => TargetProperties | false][]} */ /** @type {[string, string, RegExp, (...args: string[]) => Partial<TargetProperties>][]} */
const TARGETS = [ const TARGETS = [
[ [
"browserslist / browserslist:env / browserslist:query / browserslist:path-to-config / browserslist:path-to-config:env", "browserslist / browserslist:env / browserslist:query / browserslist:path-to-config / browserslist:path-to-config:env",
@ -95,6 +114,7 @@ See https://github.com/browserslist/browserslist#queries for possible ways to pr
The recommended way is to add a 'browserslist' key to your package.json and list supported browsers (resp. node.js versions). The recommended way is to add a 'browserslist' key to your package.json and list supported browsers (resp. node.js versions).
You can also more options via the 'target' option: 'browserslist' / 'browserslist:env' / 'browserslist:query' / 'browserslist:path-to-config' / 'browserslist:path-to-config:env'`); You can also more options via the 'target' option: 'browserslist' / 'browserslist:env' / 'browserslist:query' / 'browserslist:path-to-config' / 'browserslist:path-to-config:env'`);
} }
return browserslistTargetHandler.resolve(browsers); return browserslistTargetHandler.resolve(browsers);
} }
], ],
@ -294,7 +314,7 @@ const getTargetProperties = (target, context) => {
if (match) { if (match) {
const [, ...args] = match; const [, ...args] = match;
const result = handler(...args, context); const result = handler(...args, context);
if (result) return result; if (result) return /** @type {TargetProperties} */ (result);
} }
} }
throw new Error( throw new Error(
@ -304,13 +324,19 @@ const getTargetProperties = (target, context) => {
); );
}; };
/**
* @param {TargetProperties[]} targetProperties array of target properties
* @returns {TargetProperties} merged target properties
*/
const mergeTargetProperties = targetProperties => { const mergeTargetProperties = targetProperties => {
/** @type {Set<keyof TargetProperties>} */
const keys = new Set(); const keys = new Set();
for (const tp of targetProperties) { for (const tp of targetProperties) {
for (const key of Object.keys(tp)) { for (const key of Object.keys(tp)) {
keys.add(key); keys.add(/** @type {keyof TargetProperties} */ (key));
} }
} }
/** @type {Object} */
const result = {}; const result = {};
for (const key of keys) { for (const key of keys) {
let hasTrue = false; let hasTrue = false;
@ -327,7 +353,8 @@ const mergeTargetProperties = targetProperties => {
} }
} }
if (hasTrue || hasFalse) if (hasTrue || hasFalse)
result[key] = hasFalse && hasTrue ? null : hasTrue ? true : false; /** @type {TargetProperties} */
(result)[key] = hasFalse && hasTrue ? null : hasTrue ? true : false;
} }
return /** @type {TargetProperties} */ (result); return /** @type {TargetProperties} */ (result);
}; };

View File

@ -50,6 +50,9 @@ class ModuleChunkLoadingRuntimeModule extends RuntimeModule {
return hooks; return hooks;
} }
/**
* @param {ReadonlySet<string>} runtimeRequirements runtime requirements
*/
constructor(runtimeRequirements) { constructor(runtimeRequirements) {
super("import chunk loading", RuntimeModule.STAGE_ATTACH); super("import chunk loading", RuntimeModule.STAGE_ATTACH);
this._runtimeRequirements = runtimeRequirements; this._runtimeRequirements = runtimeRequirements;
@ -112,7 +115,7 @@ class ModuleChunkLoadingRuntimeModule extends RuntimeModule {
); );
const rootOutputDir = getUndoPath( const rootOutputDir = getUndoPath(
outputName, outputName,
this.compilation.outputOptions.path, /** @type {string} */ (this.compilation.outputOptions.path),
true true
); );