Skip to content

Commit f8b747e

Browse files
committed
cleanup error messages in webpack
1 parent 915b22f commit f8b747e

File tree

3 files changed

+106
-85
lines changed

3 files changed

+106
-85
lines changed

packages/gatsby/src/commands/build.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ import { store, readState } from "../redux"
1616
import * as appDataUtil from "../utils/app-data"
1717
import { flush as flushPendingPageDataWrites } from "../utils/page-data"
1818
import * as WorkerPool from "../utils/worker/pool"
19-
import { structureWebpackErrors } from "../utils/webpack-error-utils"
19+
import {
20+
structureWebpackErrors,
21+
reportWebpackWarnings,
22+
} from "../utils/webpack-error-utils"
2023
import {
2124
userGetsSevenDayFeedback,
2225
userPassesFeedbackRequestHeuristic,
@@ -139,6 +142,10 @@ module.exports = async function build(program: IBuildArgs): Promise<void> {
139142
let stats
140143
try {
141144
stats = await buildProductionBundle(program, buildActivityTimer.span)
145+
146+
if (stats.hasWarnings()) {
147+
reportWebpackWarnings(stats.compilation.warnings, report)
148+
}
142149
} catch (err) {
143150
buildActivityTimer.panic(structureWebpackErrors(Stage.BuildJavascript, err))
144151
} finally {

packages/gatsby/src/services/start-webpack-server.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import openurl from "better-opn"
22
import report from "gatsby-cli/lib/reporter"
3-
import formatWebpackMessages from "react-dev-utils/formatWebpackMessages"
43
import chalk from "chalk"
54
import { Compiler } from "webpack"
65
import { Stage } from "../commands/types"
@@ -80,19 +79,12 @@ export async function startWebpackServer({
8079
cancelDevJSNotice()
8180
}
8281

83-
// "done" event fires when Webpack has finished recompiling the bundle.
84-
// Whether or not you have warnings or errors, you will get this event.
85-
86-
// We have switched off the default Webpack output in WebpackDevServer
87-
// options so we are going to "massage" the warnings and errors and present
88-
// them in a readable focused way.
89-
const messages = formatWebpackMessages(stats.toJson({}, true))
9082
const urls = prepareUrls(
9183
program.https ? `https` : `http`,
9284
program.host,
9385
program.proxyPort
9486
)
95-
const isSuccessful = !messages.errors.length
87+
const isSuccessful = !stats.hasErrors()
9688

9789
if (isSuccessful && isFirstCompile) {
9890
// Show notices to users about potential experiments/feature flags they could
@@ -119,7 +111,9 @@ export async function startWebpackServer({
119111
isFirstCompile = false
120112

121113
if (webpackActivity) {
122-
reportWebpackWarnings(stats)
114+
if (stats.hasWarnings()) {
115+
reportWebpackWarnings(stats.compilation.warnings, report)
116+
}
123117

124118
if (!isSuccessful) {
125119
const errors = structureWebpackErrors(
Lines changed: 94 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import reporter from "gatsby-cli/lib/reporter"
2-
import { Stats } from "webpack"
3-
import { IMatch } from "../types"
1+
import { Reporter } from "gatsby-cli/lib/reporter/reporter"
2+
import { WebpackError, Module, NormalModule } from "webpack"
43
import { Stage as StageEnum } from "../commands/types"
4+
import formatWebpackMessages from "react-dev-utils/formatWebpackMessages"
55

66
const stageCodeToReadableLabel: Record<StageEnum, string> = {
77
[StageEnum.BuildJavascript]: `Generating JavaScript bundles`,
@@ -10,11 +10,35 @@ const stageCodeToReadableLabel: Record<StageEnum, string> = {
1010
[StageEnum.Develop]: `Generating development JavaScript bundle`,
1111
}
1212

13+
interface IFileLocation {
14+
line: number
15+
column: number
16+
}
17+
18+
interface IWebpackError {
19+
name: string
20+
message: string
21+
file?: string
22+
error?: {
23+
message: string
24+
loc?: {
25+
start: IFileLocation
26+
end: IFileLocation
27+
}
28+
}
29+
module: Module
30+
loc?: {
31+
start: IFileLocation
32+
end: IFileLocation
33+
}
34+
}
35+
1336
interface ITransformedWebpackError {
1437
id: string
15-
filePath?: string
38+
filePath: string
1639
location?: {
17-
start: string
40+
start: IFileLocation
41+
end: IFileLocation
1842
}
1943
context: {
2044
stage: StageEnum
@@ -26,81 +50,76 @@ interface ITransformedWebpackError {
2650

2751
const transformWebpackError = (
2852
stage: StageEnum,
29-
webpackError: any
53+
webpackError: WebpackError
3054
): ITransformedWebpackError => {
31-
const handlers = [
32-
{
33-
regex: /Can't resolve '(.*?)' in '(.*?)'/m,
34-
cb: (match): IMatch => {
35-
return {
36-
id: `98124`,
37-
context: {
38-
sourceMessage: match[0],
39-
packageName: match[1],
40-
},
41-
}
42-
},
43-
},
44-
]
45-
46-
const webpackMessage = webpackError?.error?.message || webpackError?.message
47-
48-
const shared = {
49-
filePath: webpackError?.module?.resource,
50-
location:
51-
webpackError?.module?.resource && webpackError?.error?.loc
52-
? {
53-
start: webpackError.error.loc,
54-
}
55-
: undefined,
56-
context: {
57-
stage,
58-
stageLabel: stageCodeToReadableLabel[stage],
59-
sourceMessage: webpackMessage,
60-
},
61-
// We use original error to display stack trace for the most part.
62-
// In case of webpack error stack will include internals of webpack
63-
// or one of loaders (for example babel-loader) and doesn't provide
64-
// much value to user, so it's purposely omitted.
55+
const castedWebpackError = (webpackError as unknown) as IWebpackError
6556

66-
// error: webpackError?.error || webpackError,
57+
let location
58+
if (castedWebpackError.loc) {
59+
location = castedWebpackError.loc
60+
}
61+
if (!location && castedWebpackError.error?.loc) {
62+
if (castedWebpackError.error.loc.start) {
63+
location = castedWebpackError.error.loc
64+
} else {
65+
location = {
66+
start: castedWebpackError.error.loc,
67+
}
68+
}
6769
}
6870

69-
let structured: ITransformedWebpackError | undefined
70-
71-
for (const { regex, cb } of handlers) {
72-
const matched = webpackMessage?.match(regex)
73-
if (matched) {
74-
const match = cb(matched)
75-
76-
structured = {
77-
id: match.id,
78-
...shared,
79-
context: {
80-
...shared.context,
81-
packageName: match.context.packageName,
82-
sourceMessage: match.context.sourceMessage,
71+
// try to get location out of stacktrace
72+
if (!location) {
73+
const matches = castedWebpackError.message.match(/\((\d+):(\d+)\)/)
74+
if (matches && matches[1] && matches[2]) {
75+
location = {
76+
start: {
77+
line: Number(matches[1]),
78+
column: Number(matches[2]),
8379
},
8480
}
85-
86-
break
8781
}
8882
}
8983

90-
// If we haven't found any known error
91-
if (!structured) {
92-
return {
93-
id: `98123`,
94-
...shared,
95-
}
84+
let id = `98123`
85+
const context: ITransformedWebpackError["context"] = {
86+
stage,
87+
stageLabel: stageCodeToReadableLabel[stage],
88+
sourceMessage:
89+
castedWebpackError.error?.message ?? castedWebpackError.message,
90+
}
91+
92+
// When a module cannot be found we can short circuit
93+
if (castedWebpackError.name === `ModuleNotFoundError`) {
94+
const matches =
95+
castedWebpackError.error?.message.match(
96+
/Can't resolve '(.*?)' in '(.*?)'/m
97+
) ?? []
98+
99+
id = `98124`
100+
context.packageName = matches?.[1]
101+
context.sourceMessage = matches?.[0]
96102
}
97103

98-
return structured
104+
return {
105+
id,
106+
filePath:
107+
(castedWebpackError?.module as NormalModule)?.resource ??
108+
castedWebpackError.file,
109+
location,
110+
context,
111+
// We use original error to display stack trace for the most part.
112+
// In case of webpack error stack will include internals of webpack
113+
// or one of loaders (for example babel-loader) and doesn't provide
114+
// much value to user, so it's purposely omitted.
115+
116+
// error: webpackError?.error || webpackError,
117+
}
99118
}
100119

101120
export const structureWebpackErrors = (
102121
stage: StageEnum,
103-
webpackError: any
122+
webpackError: WebpackError | Array<WebpackError>
104123
): Array<ITransformedWebpackError> | ITransformedWebpackError => {
105124
if (Array.isArray(webpackError)) {
106125
return webpackError.map(e => transformWebpackError(stage, e))
@@ -109,13 +128,14 @@ export const structureWebpackErrors = (
109128
return transformWebpackError(stage, webpackError)
110129
}
111130

112-
export const reportWebpackWarnings = (stats: Stats): void => {
113-
stats.compilation.warnings.forEach(webpackWarning => {
114-
if (webpackWarning.warning) {
115-
// grab inner Exception if it exists
116-
reporter.warn(webpackWarning.warning.toString())
117-
} else {
118-
reporter.warn(webpackWarning.message)
119-
}
120-
})
131+
export const reportWebpackWarnings = (
132+
warnings: Array<WebpackError>,
133+
reporter: Reporter
134+
): void => {
135+
const warningMessages = warnings.map(warning => warning.message)
136+
137+
formatWebpackMessages({
138+
errors: [],
139+
warnings: warningMessages,
140+
}).warnings.forEach(warning => reporter.warn(warning))
121141
}

0 commit comments

Comments
 (0)