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
* @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
* @returns {string[] | undefined} selected browsers
*/
@ -66,7 +66,7 @@ const load = (input, context) => {
})
: browserslist.loadConfig({ path: context, env });
if (!config) return null;
if (!config) return;
return browserslist(config);
};

View File

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

View File

@ -7,17 +7,28 @@
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").EntryStaticNormalized} EntryStaticNormalized */
/** @typedef {import("../../declarations/WebpackOptions").Externals} Externals */
/** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */
/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
/** @typedef {import("../../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptionsNormalized */
/** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunk} OptimizationRuntimeChunk */
/** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunkNormalized} OptimizationRuntimeChunkNormalized */
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputNormalized */
/** @typedef {import("../../declarations/WebpackOptions").Plugins} Plugins */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptions} WebpackOptions */
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptionsNormalized */
/** @typedef {import("../Entrypoint")} Entrypoint */
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) => {
if (emitOnErrors !== undefined && !noEmitOnErrors === !emitOnErrors) {
throw new Error(
@ -117,45 +128,50 @@ const getNormalizedWebpackOptions = config => {
return {
amd: config.amd,
bail: config.bail,
cache: optionalNestedConfig(config.cache, cache => {
if (cache === false) return false;
if (cache === true) {
return {
type: "memory",
maxGenerations: undefined
};
}
switch (cache.type) {
case "filesystem":
return {
type: "filesystem",
allowCollectingMemory: cache.allowCollectingMemory,
maxMemoryGenerations: cache.maxMemoryGenerations,
maxAge: cache.maxAge,
profile: cache.profile,
buildDependencies: cloneObject(cache.buildDependencies),
cacheDirectory: cache.cacheDirectory,
cacheLocation: cache.cacheLocation,
hashAlgorithm: cache.hashAlgorithm,
compression: cache.compression,
idleTimeout: cache.idleTimeout,
idleTimeoutForInitialStore: cache.idleTimeoutForInitialStore,
idleTimeoutAfterLargeChanges: cache.idleTimeoutAfterLargeChanges,
name: cache.name,
store: cache.store,
version: cache.version
};
case undefined:
case "memory":
return {
type: "memory",
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}`);
}
}),
cache:
/** @type {NonNullable<CacheOptions>} */
(
optionalNestedConfig(config.cache, cache => {
if (cache === false) return false;
if (cache === true) {
return {
type: "memory",
maxGenerations: undefined
};
}
switch (cache.type) {
case "filesystem":
return {
type: "filesystem",
allowCollectingMemory: cache.allowCollectingMemory,
maxMemoryGenerations: cache.maxMemoryGenerations,
maxAge: cache.maxAge,
profile: cache.profile,
buildDependencies: cloneObject(cache.buildDependencies),
cacheDirectory: cache.cacheDirectory,
cacheLocation: cache.cacheLocation,
hashAlgorithm: cache.hashAlgorithm,
compression: cache.compression,
idleTimeout: cache.idleTimeout,
idleTimeoutForInitialStore: cache.idleTimeoutForInitialStore,
idleTimeoutAfterLargeChanges:
cache.idleTimeoutAfterLargeChanges,
name: cache.name,
store: cache.store,
version: cache.version
};
case undefined:
case "memory":
return {
type: "memory",
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,
dependencies: config.dependencies,
devServer: optionalNestedConfig(config.devServer, devServer => ({
@ -184,7 +200,7 @@ const getNormalizedWebpackOptions = config => {
options === true ? {} : options
)
})),
externals: config.externals,
externals: /** @type {NonNullable<Externals>} */ (config.externals),
externalsPresets: cloneObject(config.externalsPresets),
externalsType: config.externalsType,
ignoreWarnings: config.ignoreWarnings
@ -215,32 +231,36 @@ const getNormalizedWebpackOptions = config => {
infrastructureLogging: cloneObject(config.infrastructureLogging),
loader: cloneObject(config.loader),
mode: config.mode,
module: nestedConfig(config.module, module => ({
noParse: module.noParse,
unsafeCache: module.unsafeCache,
parser: keyedNestedConfig(module.parser, cloneObject, {
javascript: parserOptions => ({
unknownContextRequest: module.unknownContextRequest,
unknownContextRegExp: module.unknownContextRegExp,
unknownContextRecursive: module.unknownContextRecursive,
unknownContextCritical: module.unknownContextCritical,
exprContextRequest: module.exprContextRequest,
exprContextRegExp: module.exprContextRegExp,
exprContextRecursive: module.exprContextRecursive,
exprContextCritical: module.exprContextCritical,
wrappedContextRegExp: module.wrappedContextRegExp,
wrappedContextRecursive: module.wrappedContextRecursive,
wrappedContextCritical: module.wrappedContextCritical,
// TODO webpack 6 remove
strictExportPresence: module.strictExportPresence,
strictThisContextOnImports: module.strictThisContextOnImports,
...parserOptions
})
}),
generator: cloneObject(module.generator),
defaultRules: optionalNestedArray(module.defaultRules, r => [...r]),
rules: nestedArray(module.rules, r => [...r])
})),
module:
/** @type {ModuleOptionsNormalized} */
(
nestedConfig(config.module, module => ({
noParse: module.noParse,
unsafeCache: module.unsafeCache,
parser: keyedNestedConfig(module.parser, cloneObject, {
javascript: parserOptions => ({
unknownContextRequest: module.unknownContextRequest,
unknownContextRegExp: module.unknownContextRegExp,
unknownContextRecursive: module.unknownContextRecursive,
unknownContextCritical: module.unknownContextCritical,
exprContextRequest: module.exprContextRequest,
exprContextRegExp: module.exprContextRegExp,
exprContextRecursive: module.exprContextRecursive,
exprContextCritical: module.exprContextCritical,
wrappedContextRegExp: module.wrappedContextRegExp,
wrappedContextRecursive: module.wrappedContextRecursive,
wrappedContextCritical: module.wrappedContextCritical,
// TODO webpack 6 remove
strictExportPresence: module.strictExportPresence,
strictThisContextOnImports: module.strictThisContextOnImports,
...parserOptions
})
}),
generator: cloneObject(module.generator),
defaultRules: optionalNestedArray(module.defaultRules, r => [...r]),
rules: nestedArray(module.rules, r => [...r])
}))
),
name: config.name,
node: nestedConfig(
config.node,
@ -387,7 +407,7 @@ const getNormalizedWebpackOptions = config => {
...performance
};
}),
plugins: nestedArray(config.plugins, p => [...p]),
plugins: /** @type {Plugins} */ (nestedArray(config.plugins, p => [...p])),
profile: config.profile,
recordsInputPath:
config.recordsInputPath !== undefined
@ -488,8 +508,11 @@ const getNormalizedEntryStatic = entry => {
} else {
result[key] = {
import:
value.import &&
(Array.isArray(value.import) ? value.import : [value.import]),
/** @type {EntryDescriptionNormalized["import"]} */
(
value.import &&
(Array.isArray(value.import) ? value.import : [value.import])
),
filename: value.filename,
layer: value.layer,
runtime: value.runtime,
@ -499,8 +522,13 @@ const getNormalizedEntryStatic = entry => {
asyncChunks: value.asyncChunks,
wasmLoading: value.wasmLoading,
dependOn:
value.dependOn &&
(Array.isArray(value.dependOn) ? value.dependOn : [value.dependOn]),
/** @type {EntryDescriptionNormalized["dependOn"]} */
(
value.dependOn &&
(Array.isArray(value.dependOn)
? value.dependOn
: [value.dependOn])
),
library: value.library
};
}
@ -522,6 +550,10 @@ const getNormalizedOptimizationRuntimeChunk = runtimeChunk => {
}
if (runtimeChunk === true || runtimeChunk === "multiple") {
return {
/**
* @param {Entrypoint} entrypoint entrypoint
* @returns {string} runtime chunk 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 */
/** @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 */
/**
* @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) => {
if (!major) return () => /** @type {undefined} */ (undefined);
major = +major;
minor = minor ? +minor : 0;
if (!major) {
return () => /** @type {undefined} */ (undefined);
}
/** @type {number} */
const nMajor = +major;
/** @type {number} */
const nMinor = minor ? +minor : 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 = [
[
"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).
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);
}
],
@ -294,7 +314,7 @@ const getTargetProperties = (target, context) => {
if (match) {
const [, ...args] = match;
const result = handler(...args, context);
if (result) return result;
if (result) return /** @type {TargetProperties} */ (result);
}
}
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 => {
/** @type {Set<keyof TargetProperties>} */
const keys = new Set();
for (const tp of targetProperties) {
for (const key of Object.keys(tp)) {
keys.add(key);
keys.add(/** @type {keyof TargetProperties} */ (key));
}
}
/** @type {Object} */
const result = {};
for (const key of keys) {
let hasTrue = false;
@ -327,7 +353,8 @@ const mergeTargetProperties = targetProperties => {
}
}
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);
};

View File

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