Skip to content

Commit eae3245

Browse files
gaearonfeiqitian
authored andcommitted
Add syntax error overlay in development (facebook#744)
* Add syntax error overlay in development * Support HMR being disabled * Tweak CSS
1 parent 7441d62 commit eae3245

File tree

6 files changed

+371
-53
lines changed

6 files changed

+371
-53
lines changed

packages/react-dev-utils/README.md

+22
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,25 @@ prompt(
178178
}
179179
});
180180
```
181+
182+
#### `webpackHotDevClient.js`
183+
184+
This is an alternative client for [WebpackDevServer](https://github.com/webpack/webpack-dev-server) that shows a syntax error overlay.
185+
186+
It currently supports only Webpack 1.x.
187+
188+
```js
189+
// Webpack development config
190+
module.exports = {
191+
// ...
192+
entry: [
193+
// You can replace the line below with these two lines if you prefer the
194+
// stock client:
195+
// require.resolve('webpack-dev-server/client') + '?/',
196+
// require.resolve('webpack/hot/dev-server'),
197+
'react-dev-utils/webpackHotDevClient',
198+
'src/index'
199+
],
200+
// ...
201+
}
202+
```

packages/react-dev-utils/formatWebpackMessages.js

+99-34
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,115 @@
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

10+
// WARNING: this code is untranspiled and is used in browser too.
11+
// Please make sure any changes are in ES5 or contribute a Babel compile step.
12+
1013
// Some custom utilities to prettify Webpack output.
11-
// This is a little hacky.
12-
// It would be easier if webpack provided a rich error object.
14+
// This is quite hacky and hopefully won't be needed when Webpack fixes this.
15+
// https://github.com/webpack/webpack/issues/2878
16+
1317
var friendlySyntaxErrorLabel = 'Syntax error:';
18+
1419
function isLikelyASyntaxError(message) {
1520
return message.indexOf(friendlySyntaxErrorLabel) !== -1;
1621
}
22+
23+
// Cleans up webpack error messages.
1724
function formatMessage(message) {
18-
return message
19-
// Make some common errors shorter:
20-
.replace(
21-
// Babel syntax error
25+
var lines = message.split('\n');
26+
27+
// line #0 is filename
28+
// line #1 is the main error message
29+
if (!lines[0] || !lines[1]) {
30+
return message;
31+
}
32+
33+
// Remove webpack-specific loader notation from filename.
34+
// Before:
35+
// ./~/css-loader!./~/postcss-loader!./src/App.css
36+
// After:
37+
// ./src/App.css
38+
if (lines[0].lastIndexOf('!') !== -1) {
39+
lines[0] = lines[0].substr(lines[0].lastIndexOf('!') + 1);
40+
}
41+
42+
// Cleans up verbose "module not found" messages for files and packages.
43+
if (lines[1].indexOf('Module not found: ') === 0) {
44+
lines = [
45+
lines[0],
46+
// Clean up message because "Module not found: " is descriptive enough.
47+
lines[1].replace(
48+
'Cannot resolve \'file\' or \'directory\' ', ''
49+
).replace(
50+
'Cannot resolve module ', ''
51+
).replace(
52+
'Error: ', ''
53+
),
54+
// Skip all irrelevant lines.
55+
// (For some reason they only appear on the client in browser.)
56+
'',
57+
lines[lines.length - 1] // error location is the last line
58+
]
59+
}
60+
61+
// Cleans up syntax error messages.
62+
if (lines[1].indexOf('Module build failed: ') === 0) {
63+
// For some reason, on the client messages appear duplicated:
64+
// https://github.com/webpack/webpack/issues/3008
65+
// This won't happen in Node but since we share this helpers,
66+
// we will dedupe them right here. We will ignore all lines
67+
// after the original error message text is repeated the second time.
68+
var errorText = lines[1].substr('Module build failed: '.length);
69+
var cleanedLines = [];
70+
var hasReachedDuplicateMessage = false;
71+
// Gather lines until we reach the beginning of duplicate message.
72+
lines.forEach(function(line, index) {
73+
if (
74+
// First time it occurs is fine.
75+
index !== 1 &&
76+
// line.endsWith(errorText)
77+
line.length >= errorText.length &&
78+
line.indexOf(errorText) === line.length - errorText.length
79+
) {
80+
// We see the same error message for the second time!
81+
// Filter out repeated error message and everything after it.
82+
hasReachedDuplicateMessage = true;
83+
}
84+
if (
85+
!hasReachedDuplicateMessage ||
86+
// Print last line anyway because it contains the source location
87+
index === lines.length - 1
88+
) {
89+
// This line is OK to appear in the output.
90+
cleanedLines.push(line);
91+
}
92+
});
93+
// We are clean now!
94+
lines = cleanedLines;
95+
// Finally, brush up the error message a little.
96+
lines[1] = lines[1].replace(
2297
'Module build failed: SyntaxError:',
2398
friendlySyntaxErrorLabel
24-
)
25-
.replace(
26-
// Webpack file not found error
27-
/Module not found: Error: Cannot resolve 'file' or 'directory'/,
28-
'Module not found:'
29-
)
30-
// Internal stacks are generally useless so we strip them
31-
.replace(/^\s*at\s.*:\d+:\d+[\s\)]*\n/gm, '') // at ... ...:x:y
32-
// Webpack loader names obscure CSS filenames
33-
.replace('./~/css-loader!./~/postcss-loader!', '');
99+
);
100+
}
101+
102+
// Reassemble the message.
103+
message = lines.join('\n');
104+
// Internal stacks are generally useless so we strip them
105+
message = message.replace(
106+
/^\s*at\s.*:\d+:\d+[\s\)]*\n/gm, ''
107+
); // at ... ...:x:y
108+
109+
return message;
34110
}
35111

36-
function formatWebpackMessages(stats) {
37-
var hasErrors = stats.hasErrors();
38-
var hasWarnings = stats.hasWarnings();
39-
if (!hasErrors && !hasWarnings) {
40-
return {
41-
errors: [],
42-
warnings: []
43-
};
44-
}
45-
// We use stats.toJson({}, true) to make output more compact and readable:
46-
// https://github.com/facebookincubator/create-react-app/issues/401#issuecomment-238291901
47-
var json = stats.toJson({}, true);
48-
var formattedErrors = json.errors.map(message =>
49-
'Error in ' + formatMessage(message)
50-
);
51-
var formattedWarnings = json.warnings.map(message =>
52-
'Warning in ' + formatMessage(message)
53-
);
112+
function formatWebpackMessages(json) {
113+
var formattedErrors = json.errors.map(function(message) {
114+
return 'Error in ' + formatMessage(message)
115+
});
116+
var formattedWarnings = json.warnings.map(function(message) {
117+
return 'Warning in ' + formatMessage(message)
118+
});
54119
var result = {
55120
errors: formattedErrors,
56121
warnings: formattedWarnings

packages/react-dev-utils/package.json

+7-2
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@
1818
"openChrome.applescript",
1919
"openBrowser.js",
2020
"prompt.js",
21-
"WatchMissingNodeModulesPlugin.js"
21+
"WatchMissingNodeModulesPlugin.js",
22+
"webpackHotDevClient.js"
2223
],
2324
"dependencies": {
25+
"ansi-html": "0.0.5",
2426
"chalk": "1.1.3",
2527
"escape-string-regexp": "1.0.5",
26-
"opn": "4.0.2"
28+
"html-entities": "1.2.0",
29+
"opn": "4.0.2",
30+
"sockjs-client": "1.0.3",
31+
"strip-ansi": "3.0.1"
2732
},
2833
"peerDependencies": {
2934
"webpack": "^1.13.2"

0 commit comments

Comments
 (0)