Skip to content

Commit ac0f615

Browse files
gaearonromaindso
authored andcommitted
Prettify errors and warnings for Webpack 2 (facebook#2113)
* Prettify errors and warnings for Webpack 2 * Update formatWebpackMessages.js
1 parent e91ba24 commit ac0f615

File tree

2 files changed

+84
-43
lines changed

2 files changed

+84
-43
lines changed

packages/react-dev-utils/formatWebpackMessages.js

+77-41
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ function isLikelyASyntaxError(message) {
2323
}
2424

2525
// Cleans up webpack error messages.
26-
function formatMessage(message) {
26+
function formatMessage(message, isError) {
2727
var lines = message.split('\n');
2828

29+
if (lines.length > 2 && lines[1] === '') {
30+
// Remove extra newline.
31+
lines.splice(1, 1);
32+
}
33+
2934
// Remove webpack-specific loader notation from filename.
3035
// Before:
3136
// ./~/css-loader!./~/postcss-loader!./src/App.css
@@ -35,6 +40,15 @@ function formatMessage(message) {
3540
lines[0] = lines[0].substr(lines[0].lastIndexOf('!') + 1);
3641
}
3742

43+
lines = lines.filter(function(line) {
44+
// Webpack adds a list of entry points to warning messages:
45+
// @ ./src/index.js
46+
// @ multi react-scripts/~/react-dev-utils/webpackHotDevClient.js ...
47+
// It is misleading (and unrelated to the warnings) so we clean it up.
48+
// It is only useful for syntax errors but we have beautiful frames for them.
49+
return line.indexOf(' @ ') !== 0;
50+
});
51+
3852
// line #0 is filename
3953
// line #1 is the main error message
4054
if (!lines[0] || !lines[1]) {
@@ -50,54 +64,76 @@ function formatMessage(message) {
5064
.replace("Cannot resolve 'file' or 'directory' ", '')
5165
.replace('Cannot resolve module ', '')
5266
.replace('Error: ', ''),
53-
// Skip all irrelevant lines.
54-
// (For some reason they only appear on the client in browser.)
55-
'',
56-
lines[lines.length - 1], // error location is the last line
5767
];
5868
}
5969

6070
// Cleans up syntax error messages.
6171
if (lines[1].indexOf('Module build failed: ') === 0) {
62-
// For some reason, on the client messages appear duplicated:
63-
// https://github.com/webpack/webpack/issues/3008
64-
// This won't happen in Node but since we share this helpers,
65-
// we will dedupe them right here. We will ignore all lines
66-
// after the original error message text is repeated the second time.
67-
var errorText = lines[1].substr('Module build failed: '.length);
68-
var cleanedLines = [];
69-
var hasReachedDuplicateMessage = false;
70-
// Gather lines until we reach the beginning of duplicate message.
71-
lines.forEach(function(line, index) {
72-
if (
73-
// First time it occurs is fine.
74-
index !== 1 &&
75-
// line.endsWith(errorText)
76-
line.length >= errorText.length &&
77-
line.indexOf(errorText) === line.length - errorText.length
78-
) {
79-
// We see the same error message for the second time!
80-
// Filter out repeated error message and everything after it.
81-
hasReachedDuplicateMessage = true;
82-
}
83-
if (
84-
!hasReachedDuplicateMessage ||
85-
// Print last line anyway because it contains the source location
86-
index === lines.length - 1
87-
) {
88-
// This line is OK to appear in the output.
89-
cleanedLines.push(line);
90-
}
91-
});
92-
// We are clean now!
93-
lines = cleanedLines;
94-
// Finally, brush up the error message a little.
9572
lines[1] = lines[1].replace(
9673
'Module build failed: SyntaxError:',
9774
friendlySyntaxErrorLabel
9875
);
9976
}
10077

78+
// Clean up export errors.
79+
// TODO: we should really send a PR to Webpack for this.
80+
var exportError = /\s*(.+?)\s*(")?export '(.+?)' was not found in '(.+?)'/;
81+
if (lines[1].match(exportError)) {
82+
lines[1] = lines[1].replace(
83+
exportError,
84+
"$1 '$4' does not contain an export named '$3'."
85+
);
86+
}
87+
88+
// TODO: Ideally we should write a custom ESLint formatter instead.
89+
90+
// If the second line already includes a filename, and it's a warning,
91+
// this is likely coming from ESLint. Skip it because Webpack also prints it.
92+
// Let's omit that in this case.
93+
var BEGIN_ESLINT_FILENAME = String.fromCharCode(27) + '[4m';
94+
// Also filter out ESLint summaries for each file
95+
var BEGIN_ESLINT_WARNING_SUMMARY = String.fromCharCode(27) +
96+
'[33m' +
97+
String.fromCharCode(27) +
98+
'[1m' +
99+
String.fromCharCode(10006);
100+
var BEGIN_ESLINT_ERROR_SUMMARY = String.fromCharCode(27) +
101+
'[31m' +
102+
String.fromCharCode(27) +
103+
'[1m' +
104+
String.fromCharCode(10006);
105+
// ESLint puts separators like this between groups. We don't need them:
106+
var ESLINT_EMPTY_SEPARATOR = String.fromCharCode(27) +
107+
'[22m' +
108+
String.fromCharCode(27) +
109+
'[39m';
110+
// Go!
111+
lines = lines.filter(function(line) {
112+
if (line === ESLINT_EMPTY_SEPARATOR) {
113+
return false;
114+
}
115+
if (
116+
line.indexOf(BEGIN_ESLINT_FILENAME) === 0 ||
117+
line.indexOf(BEGIN_ESLINT_WARNING_SUMMARY) === 0 ||
118+
line.indexOf(BEGIN_ESLINT_ERROR_SUMMARY) === 0
119+
) {
120+
return false;
121+
}
122+
return true;
123+
});
124+
125+
// Prepend filename with an explanation.
126+
lines[0] =
127+
// Underline
128+
String.fromCharCode(27) +
129+
'[4m' +
130+
// Filename
131+
lines[0] +
132+
// End underline
133+
String.fromCharCode(27) +
134+
'[24m' +
135+
(isError ? ' contains errors.' : ' contains warnings.');
136+
101137
// Reassemble the message.
102138
message = lines.join('\n');
103139
// Internal stacks are generally useless so we strip them... with the
@@ -109,15 +145,15 @@ function formatMessage(message) {
109145
''
110146
); // at ... ...:x:y
111147

112-
return message;
148+
return message.trim();
113149
}
114150

115151
function formatWebpackMessages(json) {
116152
var formattedErrors = json.errors.map(function(message) {
117-
return 'Error in ' + formatMessage(message);
153+
return formatMessage(message, true);
118154
});
119155
var formattedWarnings = json.warnings.map(function(message) {
120-
return 'Warning in ' + formatMessage(message);
156+
return formatMessage(message, false);
121157
});
122158
var result = {
123159
errors: formattedErrors,

packages/react-dev-utils/webpackHotDevClient.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,13 @@ function handleWarnings(warnings) {
182182

183183
function printWarnings() {
184184
// Print warnings to the console.
185-
for (var i = 0; i < warnings.length; i++) {
186-
console.warn(stripAnsi(warnings[i]));
185+
var formatted = formatWebpackMessages({
186+
warnings: warnings,
187+
errors: [],
188+
});
189+
190+
for (var i = 0; i < formatted.warnings.length; i++) {
191+
console.warn(stripAnsi(formatted.warnings[i]));
187192
}
188193
}
189194

0 commit comments

Comments
 (0)