mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-21 22:34:21 +08:00
fix(@angular-devkit/build-angular): hide stacktraces from webpack errors
In many cases Webpack will output errors with stacktraces even when `errorStack` is configured to false which bloats the terminal and makes the actual error harder to find. With this change we output stacktraces only when using the `verbose` option. Before ``` $ ng build ./src/styles.scss.webpack[javascript/auto]!=!./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[2]!./node_modules/resolve-url-loader/index.js??ruleSet[1].rules[5].rules[1].use[0]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[5].rules[1].use[1]!./src/styles.scss - Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): SassError: Can't find stylesheet to import. ╷ 1 │ @import "invalid"; │ ^^^^^^^^^ ╵ src/styles.scss 1:9 root stylesheet ./src/styles.scss - Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): HookWebpackError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): SassError: Can't find stylesheet to import. ╷ 1 │ @import "invalid"; │ ^^^^^^^^^ ╵ src/styles.scss 1:9 root stylesheet at tryRunOrWebpackError (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/HookWebpackError.js:88:9) at __webpack_require_module__ (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:5051:12) at __webpack_require__ (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:5008:18) at /usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:5079:20 at symbolIterator (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/neo-async/async.js:3485:9) at done (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/neo-async/async.js:3527:9) at Hook.eval [as callAsync] (eval at create (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1) at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/tapable/lib/Hook.js:18:14) at /usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:4986:43 at symbolIterator (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/neo-async/async.js:3482:9) -- inner error -- Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): SassError: Can't find stylesheet to import. ╷ 1 │ @import "invalid"; │ ^^^^^^^^^ ╵ src/styles.scss 1:9 root stylesheet at Object.<anonymous> (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[1]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[2]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/resolve-url-loader/index.js??ruleSet[1].rules[5].rules[1].use[0]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[5].rules[1].use[1]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/src/styles.scss:1:7) at /usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js:441:11 at Hook.eval [as call] (eval at create (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/tapable/lib/HookCodeFactory.js:19:10), <anonymous>:7:1) at Hook.CALL_DELEGATE [as _call] (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/tapable/lib/Hook.js:14:14) at /usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:5053:39 at tryRunOrWebpackError (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/HookWebpackError.js:83:7) at __webpack_require_module__ (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:5051:12) at __webpack_require__ (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:5008:18) at /usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/webpack/lib/Compilation.js:5079:20 at symbolIterator (/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/neo-async/async.js:3485:9) Generated code for /usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[1]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[5].rules[0].oneOf[0].use[2]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/resolve-url-loader/index.js??ruleSet[1].rules[5].rules[1].use[0]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[5].rules[1].use[1]!/usr/local/xxxxxxx/cli-reproductions/showwcase-v14-rc0/src/styles.scss 1 | throw new Error("Module build failed (from ./node_modules/sass-loader/dist/cjs.js):\nSassError: Can't find stylesheet to import.\n ╷\n1 │ @import \"invalid\";\n │ ^^^^^^^^^\n ╵\n src/styles.scss 1:9 root stylesheet"); ``` After ``` $ ng build ./src/styles.scss - Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): SassError: Can't find stylesheet to import. ╷ 1 │ @import "invalid"; │ ^^^^^^^^^ ╵ src/styles.scss 1:9 root stylesheet ./src/styles.scss - Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): HookWebpackError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): SassError: Can't find stylesheet to import. ╷ 1 │ @import "invalid"; │ ^^^^^^^^^ ╵ src/styles.scss 1:9 root stylesheet ```
This commit is contained in:
parent
4fcfc37cb9
commit
b40aeed441
@ -102,5 +102,59 @@ describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
|
||||
)
|
||||
.toPromise();
|
||||
});
|
||||
|
||||
it('should not include error stacktraces when false', async () => {
|
||||
harness.useTarget('build', {
|
||||
...BASE_OPTIONS,
|
||||
verbose: false,
|
||||
styles: ['./src/styles.scss'],
|
||||
});
|
||||
|
||||
// Create a compilatation error.
|
||||
await harness.writeFile('./src/styles.scss', `@import 'invalid-module';`);
|
||||
|
||||
const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false });
|
||||
expect(result?.success).toBeFalse();
|
||||
expect(logs).toContain(
|
||||
jasmine.objectContaining<logging.LogEntry>({
|
||||
message: jasmine.stringMatching(`SassError: Can't find stylesheet to import.`),
|
||||
}),
|
||||
);
|
||||
expect(logs).not.toContain(
|
||||
jasmine.objectContaining<logging.LogEntry>({
|
||||
message: jasmine.stringMatching('styles.scss.webpack'),
|
||||
}),
|
||||
);
|
||||
expect(logs).not.toContain(
|
||||
jasmine.objectContaining<logging.LogEntry>({
|
||||
message: jasmine.stringMatching('at Object.loader'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should include error stacktraces when true', async () => {
|
||||
harness.useTarget('build', {
|
||||
...BASE_OPTIONS,
|
||||
verbose: true,
|
||||
styles: ['./src/styles.scss'],
|
||||
});
|
||||
|
||||
// Create a compilatation error.
|
||||
await harness.writeFile('./src/styles.scss', `@import 'invalid-module';`);
|
||||
|
||||
const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false });
|
||||
expect(result?.success).toBeFalse();
|
||||
|
||||
expect(logs).toContain(
|
||||
jasmine.objectContaining<logging.LogEntry>({
|
||||
message: jasmine.stringMatching('styles.scss.webpack'),
|
||||
}),
|
||||
);
|
||||
expect(logs).toContain(
|
||||
jasmine.objectContaining<logging.LogEntry>({
|
||||
message: jasmine.stringMatching('at Object.loader'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -29,6 +29,8 @@ export interface HashFormat {
|
||||
script: string;
|
||||
}
|
||||
|
||||
export type WebpackStatsOptions = Exclude<Configuration['stats'], string | boolean | undefined>;
|
||||
|
||||
export function getOutputHashFormat(outputHashing = OutputHashing.None, length = 20): HashFormat {
|
||||
const hashTemplate = `.[contenthash:${length}]`;
|
||||
|
||||
@ -276,7 +278,6 @@ export function externalizePackages(
|
||||
}
|
||||
}
|
||||
|
||||
type WebpackStatsOptions = Exclude<Configuration['stats'], string | boolean>;
|
||||
export function getStatsOptions(verbose = false): WebpackStatsOptions {
|
||||
const webpackOutputOptions: WebpackStatsOptions = {
|
||||
all: false, // Fallback value for stats options when an option is not defined. It has precedence over local webpack defaults.
|
||||
@ -306,6 +307,7 @@ export function getStatsOptions(verbose = false): WebpackStatsOptions {
|
||||
version: true,
|
||||
chunkModules: true,
|
||||
errorDetails: true,
|
||||
errorStack: true,
|
||||
moduleTrace: true,
|
||||
logging: 'verbose',
|
||||
modulesSpace: Infinity,
|
||||
|
@ -15,7 +15,7 @@ import { Schema as BrowserBuilderOptions } from '../../builders/browser/schema';
|
||||
import { BudgetCalculatorResult } from '../../utils/bundle-calculator';
|
||||
import { colors as ansiColors, removeColor } from '../../utils/color';
|
||||
import { markAsyncChunksNonInitial } from './async-chunks';
|
||||
import { getStatsOptions, normalizeExtraEntryPoints } from './helpers';
|
||||
import { WebpackStatsOptions, getStatsOptions, normalizeExtraEntryPoints } from './helpers';
|
||||
|
||||
export function formatSize(size: number): string {
|
||||
if (size <= 0) {
|
||||
@ -317,8 +317,10 @@ function statsToString(
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function statsWarningsToString(json: StatsCompilation, statsConfig: any): string {
|
||||
export function statsWarningsToString(
|
||||
json: StatsCompilation,
|
||||
statsConfig: WebpackStatsOptions,
|
||||
): string {
|
||||
const colors = statsConfig.colors;
|
||||
const c = (x: string) => (colors ? ansiColors.reset.cyan(x) : x);
|
||||
const y = (x: string) => (colors ? ansiColors.reset.yellow(x) : x);
|
||||
@ -352,8 +354,10 @@ export function statsWarningsToString(json: StatsCompilation, statsConfig: any):
|
||||
return output ? '\n' + output : output;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function statsErrorsToString(json: StatsCompilation, statsConfig: any): string {
|
||||
export function statsErrorsToString(
|
||||
json: StatsCompilation,
|
||||
statsConfig: WebpackStatsOptions,
|
||||
): string {
|
||||
const colors = statsConfig.colors;
|
||||
const c = (x: string) => (colors ? ansiColors.reset.cyan(x) : x);
|
||||
const yb = (x: string) => (colors ? ansiColors.reset.yellowBright(x) : x);
|
||||
@ -369,7 +373,17 @@ export function statsErrorsToString(json: StatsCompilation, statsConfig: any): s
|
||||
if (typeof error === 'string') {
|
||||
output += r(`Error: ${error}\n\n`);
|
||||
} else {
|
||||
const file = error.file || error.moduleName;
|
||||
let file = error.file || error.moduleName;
|
||||
// Clean up error paths
|
||||
// Ex: ./src/app/styles.scss.webpack[javascript/auto]!=!./node_modules/css-loader/dist/cjs.js....
|
||||
// to ./src/app/styles.scss.webpack
|
||||
if (file && !statsConfig.errorDetails) {
|
||||
const webpackPathIndex = file.indexOf('.webpack[');
|
||||
if (webpackPathIndex !== -1) {
|
||||
file = file.substring(0, webpackPathIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (file) {
|
||||
output += c(file);
|
||||
if (error.loc) {
|
||||
@ -377,10 +391,18 @@ export function statsErrorsToString(json: StatsCompilation, statsConfig: any): s
|
||||
}
|
||||
output += ' - ';
|
||||
}
|
||||
if (!/^error/i.test(error.message)) {
|
||||
|
||||
// In most cases webpack will add stack traces to error messages.
|
||||
// This below cleans up the error from stacks.
|
||||
// See: https://github.com/webpack/webpack/issues/15980
|
||||
const message = statsConfig.errorStack
|
||||
? error.message
|
||||
: /[\s\S]+?(?=[\n\s]+at)/.exec(error.message)?.[0] ?? error.message;
|
||||
|
||||
if (!/^error/i.test(message)) {
|
||||
output += r('Error: ');
|
||||
}
|
||||
output += `${error.message}\n\n`;
|
||||
output += `${message}\n\n`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -428,9 +450,14 @@ export function webpackStatsLogger(
|
||||
): void {
|
||||
logger.info(statsToString(json, config.stats, budgetFailures));
|
||||
|
||||
if (typeof config.stats !== 'object') {
|
||||
throw new Error('Invalid Webpack stats configuration.');
|
||||
}
|
||||
|
||||
if (statsHasWarnings(json)) {
|
||||
logger.warn(statsWarningsToString(json, config.stats));
|
||||
}
|
||||
|
||||
if (statsHasErrors(json)) {
|
||||
logger.error(statsErrorsToString(json, config.stats));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user