Skip to content

Commit 478b963

Browse files
committed
feat: improve error and warning messages in overlay
1 parent e489ac8 commit 478b963

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"],
@@ -126,11 +127,8 @@ function hide() {
126127

127128
function formatProblem(type, item) {
128129
let header = type === "warning" ? "WARNING" : "ERROR";
129-
let body = "";
130130

131-
if (typeof item === "string") {
132-
body += item;
133-
} else {
131+
if (typeof item === "object") {
134132
const file = item.file || "";
135133
// eslint-disable-next-line no-nested-ternary
136134
const moduleName = item.moduleName
@@ -147,10 +145,9 @@ function formatProblem(type, item) {
147145
}${loc ? ` ${loc}` : ""}`
148146
: ""
149147
}`;
150-
body += item.message || "";
151148
}
152149

153-
return { header, body };
150+
return { header, body: formatWebpackMessage(item) };
154151
}
155152

156153
// 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
@@ -66,8 +66,8 @@ exports[`overlay should not show initially, then show on an error and allow to c
6666
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
6767
><br /><br />
6868
<div>
69-
Module parse failed: Unterminated template (1:1) You may need an
70-
appropriate loader to handle this file type, currently no loaders are
69+
./foo.js Module parse failed: Unterminated template (1:1) You may need
70+
an appropriate loader to handle this file type, currently no loaders are
7171
configured to process this file. See
7272
https://webpack.js.org/concepts#loaders &gt; \`;
7373
</div>
@@ -149,8 +149,8 @@ exports[`overlay should not show initially, then show on an error, then hide on
149149
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
150150
><br /><br />
151151
<div>
152-
Module parse failed: Unterminated template (1:1) You may need an
153-
appropriate loader to handle this file type, currently no loaders are
152+
./foo.js Module parse failed: Unterminated template (1:1) You may need
153+
an appropriate loader to handle this file type, currently no loaders are
154154
configured to process this file. See
155155
https://webpack.js.org/concepts#loaders &gt; \`;
156156
</div>
@@ -232,8 +232,8 @@ exports[`overlay should not show initially, then show on an error, then show oth
232232
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
233233
><br /><br />
234234
<div>
235-
Module parse failed: Unterminated template (1:1) You may need an
236-
appropriate loader to handle this file type, currently no loaders are
235+
./foo.js Module parse failed: Unterminated template (1:1) You may need
236+
an appropriate loader to handle this file type, currently no loaders are
237237
configured to process this file. See
238238
https://webpack.js.org/concepts#loaders &gt; \`;
239239
</div>
@@ -282,8 +282,8 @@ exports[`overlay should not show initially, then show on an error, then show oth
282282
<span style=\\"color: rgb(227, 96, 73)\\">ERROR in ./foo.js 1:1</span
283283
><br /><br />
284284
<div>
285-
Module parse failed: Unterminated template (1:1) You may need an
286-
appropriate loader to handle this file type, currently no loaders are
285+
./foo.js Module parse failed: Unterminated template (1:1) You may need
286+
an appropriate loader to handle this file type, currently no loaders are
287287
configured to process this file. See
288288
https://webpack.js.org/concepts#loaders &gt; \`;a
289289
</div>

0 commit comments

Comments
 (0)