improve warnings and errors handling in stats

respect warningsFilter for warnings count
include child compilation warnings and errors in count
show hint for child compilation errors and warnings
This commit is contained in:
Tobias Koppers 2020-09-20 21:24:15 +02:00
parent e81882adb2
commit 07fc554bef
5 changed files with 133 additions and 13 deletions

View File

@ -582,6 +582,11 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
/** @type {SyncBailHook<[string, LogEntry], true>} */
log: new SyncBailHook(["origin", "logEntry"]),
/** @type {SyncWaterfallHook<[WebpackError[]]>} */
processWarnings: new SyncWaterfallHook(["warnings"]),
/** @type {SyncWaterfallHook<[WebpackError[]]>} */
processErrors: new SyncWaterfallHook(["errors"]),
/** @type {HookMap<SyncHook<[Object, Object]>>} */
statsPreset: new HookMap(() => new SyncHook(["options", "context"])),
/** @type {SyncHook<[Object, Object]>} */
@ -3232,6 +3237,14 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
return { path: newPath, info: assetInfo };
}
getWarnings() {
return this.hooks.processWarnings.call(this.warnings);
}
getErrors() {
return this.hooks.processErrors.call(this.errors);
}
/**
* This function allows you to run another instance of webpack inside of webpack however as
* a child with different settings and configurations (if desired) applied. It copies all hooks, plugins

View File

@ -52,6 +52,8 @@ const { makePathsRelative, parseResource } = require("../util/identifier");
* @property {Map<string,Chunk[]>} compilationFileToChunks
* @property {Map<string,Chunk[]>} compilationAuxiliaryFileToChunks
* @property {RuntimeSpec} runtime
* @property {function(Compilation): WebpackError[]} cachedGetErrors
* @property {function(Compilation): WebpackError[]} cachedGetWarnings
*/
/**
@ -173,6 +175,21 @@ const countIterable = iterable => {
return i;
};
/**
* @param {Compilation} compilation the compilation
* @param {function(Compilation, string): any[]} getItems get items
* @returns {number} total number
*/
const countWithChildren = (compilation, getItems) => {
let count = getItems(compilation, "").length;
for (const child of compilation.children) {
count += countWithChildren(child, (c, type) =>
getItems(c, `.children[].compilation${type}`)
);
}
return count;
};
/** @type {ExtractorsByOption<WebpackError | string>} */
const EXTRACT_ERROR = {
_: (object, error, context, { requestShortener }) => {
@ -249,10 +266,34 @@ const EXTRACT_ERROR = {
const SIMPLE_EXTRACTORS = {
compilation: {
_: (object, compilation, context) => {
context.makePathsRelative = makePathsRelative.bindContextCache(
compilation.compiler.context,
compilation.compiler.root
);
if (!context.makePathsRelative) {
context.makePathsRelative = makePathsRelative.bindContextCache(
compilation.compiler.context,
compilation.compiler.root
);
}
if (!context.cachedGetErrors) {
const map = new WeakMap();
context.cachedGetErrors = compilation => {
return (
map.get(compilation) ||
(errors => (map.set(compilation, errors), errors))(
compilation.getErrors()
)
);
};
}
if (!context.cachedGetWarnings) {
const map = new WeakMap();
context.cachedGetWarnings = compilation => {
return (
map.get(compilation) ||
(warnings => (map.set(compilation, warnings), warnings))(
compilation.getWarnings()
)
);
};
}
if (compilation.name) {
object.name = compilation.name;
}
@ -434,26 +475,48 @@ const SIMPLE_EXTRACTORS = {
);
},
errors: (object, compilation, context, options, factory) => {
const { type } = context;
const { type, cachedGetErrors } = context;
object.errors = factory.create(
`${type}.errors`,
compilation.errors,
cachedGetErrors(compilation),
context
);
},
errorsCount: (object, compilation) => {
object.errorsCount = compilation.errors.length;
errorsCount: (object, compilation, { cachedGetErrors }) => {
object.errorsCount = countWithChildren(compilation, c =>
cachedGetErrors(c)
);
},
warnings: (object, compilation, context, options, factory) => {
const { type } = context;
const { type, cachedGetWarnings } = context;
object.warnings = factory.create(
`${type}.warnings`,
compilation.warnings,
cachedGetWarnings(compilation),
context
);
},
warningsCount: (object, compilation) => {
object.warningsCount = compilation.warnings.length;
warningsCount: (
object,
compilation,
context,
{ warningsFilter },
factory
) => {
const { type, cachedGetWarnings } = context;
object.warningsCount = countWithChildren(compilation, (c, childType) => {
if (!warningsFilter && warningsFilter.length === 0)
return cachedGetWarnings(c);
return factory
.create(`${type}${childType}.warnings`, cachedGetWarnings(c), context)
.filter(warning => {
const warningString = Object.keys(warning)
.map(key => `${warning[key]}`)
.join("\n");
return !warningsFilter.some(filter =>
filter(warning, warningString)
);
});
});
},
logging: (object, compilation, _context, options, factory) => {
const util = require("util");

View File

@ -178,6 +178,43 @@ const SIMPLE_PRINTERS = {
Object.entries(logging).map(([name, value]) => ({ ...value, name })),
context
),
"compilation.warningsInChildren!": (_, { yellow, compilation }) => {
if (
!compilation.children &&
compilation.warningsCount > 0 &&
compilation.warnings
) {
const childWarnings =
compilation.warningsCount - compilation.warnings.length;
if (childWarnings > 0) {
return yellow(
`${childWarnings} ${plural(
childWarnings,
"WARNING",
"WARNINGS"
)} in child compilations`
);
}
}
},
"compilation.errorsInChildren!": (_, { red, compilation }) => {
if (
!compilation.children &&
compilation.errorsCount > 0 &&
compilation.errors
) {
const childErrors = compilation.errorsCount - compilation.errors.length;
if (childErrors > 0) {
return red(
`${childErrors} ${plural(
childErrors,
"ERROR",
"ERRORS"
)} in child compilations`
);
}
}
},
"asset.type": type => type,
"asset.name": (name, { formatFilename, asset: { isOverSizeLimit } }) =>
@ -578,7 +615,9 @@ const PREFERRED_ORDERS = {
"children",
"logging",
"warnings",
"warningsInChildren!",
"errors",
"errorsInChildren!",
"summary!",
"needAdditionalPass"
],

View File

@ -1419,7 +1419,8 @@ WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
webpack x.x.x compiled with 1 warning in X ms"
1 ERROR in child compilations
webpack x.x.x compiled with 1 error and 1 warning in X ms"
`;
exports[`StatsTestCases should print correct stats for optimize-chunks 1`] = `

4
types.d.ts vendored
View File

@ -1234,6 +1234,8 @@ declare class Compilation {
needAdditionalPass: SyncBailHook<[], boolean>;
childCompiler: SyncHook<[Compiler, string, number], void>;
log: SyncBailHook<[string, LogEntry], true>;
processWarnings: SyncWaterfallHook<[WebpackError[]]>;
processErrors: SyncWaterfallHook<[WebpackError[]]>;
statsPreset: HookMap<SyncHook<[any, any], void>>;
statsNormalize: SyncHook<[any, any], void>;
statsFactory: SyncHook<[StatsFactory, any], void>;
@ -1472,6 +1474,8 @@ declare class Compilation {
filename: string | ((arg0: PathData, arg1: AssetInfo) => string),
data: PathData
): { path: string; info: AssetInfo };
getWarnings(): WebpackError[];
getErrors(): WebpackError[];
/**
* This function allows you to run another instance of webpack inside of webpack however as