Skip to content

Commit b78547a

Browse files
committed
feat: improve error and warning messages in overlay
1 parent eea50f3 commit b78547a

File tree

3 files changed

+143
-14
lines changed

3 files changed

+143
-14
lines changed

client-src/overlay.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import ansiHTML from "ansi-html-community";
55
import { encode } from "html-entities";
6+
import formatWebpackMessage from "./utils/format-webpack-message.js";
67

78
const colors = {
89
reset: ["transparent", "transparent"],
@@ -147,11 +148,8 @@ function hide() {
147148
*/
148149
function formatProblem(type, item) {
149150
let header = type === "warning" ? "WARNING" : "ERROR";
150-
let body = "";
151151

152-
if (typeof item === "string") {
153-
body += item;
154-
} else {
152+
if (typeof item === "object") {
155153
const file = item.file || "";
156154
// eslint-disable-next-line no-nested-ternary
157155
const moduleName = item.moduleName
@@ -168,10 +166,9 @@ function formatProblem(type, item) {
168166
}${loc ? ` ${loc}` : ""}`
169167
: ""
170168
}`;
171-
body += item.message || "";
172169
}
173170

174-
return { header, body };
171+
return { header, body: formatWebpackMessage(item) };
175172
}
176173

177174
// Compilation with errors (e.g. syntax error or missing modules).
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
MIT License
3+
Copyright (c) 2015-present, Facebook, Inc.
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18+
SOFTWARE.
19+
*/
20+
21+
import stripAnsi from "../modules/strip-ansi/index.js";
22+
// This file is based on https://github.com/facebook/create-react-app/blob/7b1a32be6ec9f99a6c9a3c66813f3ac09c4736b9/packages/react-dev-utils/formatWebpackMessages.js
23+
// It's been edited to remove chalk and CRA-specific logic
24+
25+
const friendlySyntaxErrorLabel = "Syntax error:";
26+
27+
// Cleans up webpack error messages.
28+
function formatWebpackMessage(message, verbose) {
29+
if (typeof message === "object" && message.message) {
30+
const filteredModuleTrace =
31+
message.moduleTrace &&
32+
message.moduleTrace.filter(
33+
(trace) =>
34+
!/next-(middleware|client-pages|flight-(client|server))-loader\.js/.test(
35+
trace.originName
36+
)
37+
);
38+
message =
39+
(message.moduleName ? `${stripAnsi(message.moduleName)}\n` : "") +
40+
(message.file ? `${stripAnsi(message.file)}\n` : "") +
41+
message.message +
42+
(message.details && verbose ? `\n${message.details}` : "") +
43+
(filteredModuleTrace && filteredModuleTrace.length && verbose
44+
? `\n\nImport trace for requested module:${filteredModuleTrace
45+
.map((trace) => `\n${trace.originName}`)
46+
.join("")}`
47+
: "") +
48+
(message.stack && verbose ? `\n${message.stack}` : "");
49+
}
50+
let lines = message.split("\n");
51+
52+
// Strip Webpack-added headers off errors/warnings
53+
// https://github.com/webpack/webpack/blob/master/lib/ModuleError.js
54+
lines = lines.filter((line) => !/Module [A-z ]+\(from/.test(line));
55+
56+
// Transform parsing error into syntax error
57+
lines = lines.map((line) => {
58+
const parsingError = /Line (\d+):(?:(\d+):)?\s*Parsing error: (.+)$/.exec(
59+
line
60+
);
61+
if (!parsingError) {
62+
return line;
63+
}
64+
const [, errorLine, errorColumn, errorMessage] = parsingError;
65+
return `${friendlySyntaxErrorLabel} ${errorMessage} (${errorLine}:${errorColumn})`;
66+
});
67+
68+
message = lines.join("\n");
69+
// Smoosh syntax errors (commonly found in CSS)
70+
message = message.replace(
71+
/SyntaxError\s+\((\d+):(\d+)\)\s*(.+?)\n/g,
72+
`${friendlySyntaxErrorLabel} $3 ($1:$2)\n`
73+
);
74+
// Clean up export errors
75+
message = message.replace(
76+
/^.*export '(.+?)' was not found in '(.+?)'.*$/gm,
77+
`Attempted import error: '$1' is not exported from '$2'.`
78+
);
79+
message = message.replace(
80+
/^.*export 'default' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
81+
`Attempted import error: '$2' does not contain a default export (imported as '$1').`
82+
);
83+
message = message.replace(
84+
/^.*export '(.+?)' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
85+
`Attempted import error: '$1' is not exported from '$3' (imported as '$2').`
86+
);
87+
lines = message.split("\n");
88+
89+
// Remove leading newline
90+
if (lines.length > 2 && lines[1].trim() === "") {
91+
lines.splice(1, 1);
92+
}
93+
94+
// Cleans up verbose "module not found" messages for files and packages.
95+
if (lines[1] && lines[1].indexOf("Module not found: ") === 0) {
96+
lines = [
97+
lines[0],
98+
lines[1]
99+
.replace("Error: ", "")
100+
.replace("Module not found: Cannot find file:", "Cannot find file:"),
101+
...lines.slice(2),
102+
];
103+
}
104+
105+
if (!verbose) {
106+
message = lines.join("\n");
107+
// Internal stacks are generally useless so we strip them... with the
108+
// exception of stacks containing `webpack:` because they're normally
109+
// from user code generated by Webpack. For more information see
110+
// https://github.com/facebook/create-react-app/pull/1050
111+
message = message.replace(
112+
/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm,
113+
""
114+
// eslint-disable-next-line line-comment-position
115+
); // at ... ...:x:y
116+
// eslint-disable-next-line line-comment-position
117+
message = message.replace(/^\s*at\s<anonymous>(\n|$)/gm, ""); // at <anonymous>
118+
lines = message.split("\n");
119+
}
120+
121+
// Remove duplicated newlines
122+
lines = lines.filter(
123+
(line, index, arr) =>
124+
index === 0 || line.trim() !== "" || line.trim() !== arr[index - 1].trim()
125+
);
126+
127+
// Reassemble the message
128+
message = lines.join("\n");
129+
return message.trim();
130+
}
131+
132+
export default formatWebpackMessage;

test/e2e/__snapshots__/overlay.test.js.snap.webpack5

+8-8
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ exports[`overlay should not show initially, then show on an error and allow to c
7070
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
7171
><br /><br />
7272
<div>
73-
Module parse failed: Unterminated template (1:1) You may need an
74-
appropriate loader to handle this file type, currently no loaders are
73+
./foo.js Module parse failed: Unterminated template (1:1) You may need
74+
an appropriate loader to handle this file type, currently no loaders are
7575
configured to process this file. See
7676
https://webpack.js.org/concepts#loaders &gt; \`;
7777
</div>
@@ -157,8 +157,8 @@ exports[`overlay should not show initially, then show on an error, then hide on
157157
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
158158
><br /><br />
159159
<div>
160-
Module parse failed: Unterminated template (1:1) You may need an
161-
appropriate loader to handle this file type, currently no loaders are
160+
./foo.js Module parse failed: Unterminated template (1:1) You may need
161+
an appropriate loader to handle this file type, currently no loaders are
162162
configured to process this file. See
163163
https://webpack.js.org/concepts#loaders &gt; \`;
164164
</div>
@@ -244,8 +244,8 @@ exports[`overlay should not show initially, then show on an error, then show oth
244244
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
245245
><br /><br />
246246
<div>
247-
Module parse failed: Unterminated template (1:1) You may need an
248-
appropriate loader to handle this file type, currently no loaders are
247+
./foo.js Module parse failed: Unterminated template (1:1) You may need
248+
an appropriate loader to handle this file type, currently no loaders are
249249
configured to process this file. See
250250
https://webpack.js.org/concepts#loaders &gt; \`;
251251
</div>
@@ -294,8 +294,8 @@ exports[`overlay should not show initially, then show on an error, then show oth
294294
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
295295
><br /><br />
296296
<div>
297-
Module parse failed: Unterminated template (1:1) You may need an
298-
appropriate loader to handle this file type, currently no loaders are
297+
./foo.js Module parse failed: Unterminated template (1:1) You may need
298+
an appropriate loader to handle this file type, currently no loaders are
299299
configured to process this file. See
300300
https://webpack.js.org/concepts#loaders &gt; \`;a
301301
</div>

0 commit comments

Comments
 (0)