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"
43import { Stage as StageEnum } from "../commands/types"
4+ import formatWebpackMessages from "react-dev-utils/formatWebpackMessages"
55
66const 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+
1336interface 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
2751const transformWebpackError = (
2852 stage : StageEnum ,
29- webpackError : any
53+ webpackError : WebpackError
3054) : ITransformedWebpackError => {
31- const handlers = [
32- {
33- regex : / C a n ' t r e s o l v e ' ( .* ?) ' i n ' ( .* ?) ' / 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+ / C a n ' t r e s o l v e ' ( .* ?) ' i n ' ( .* ?) ' / 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
101120export 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