Skip to content

Commit 44654be

Browse files
KyleAMathewswardpeet
authored andcommitted
fix(gatsby): Make createPage action errors structured (#15619)
1 parent e1eaf9a commit 44654be

File tree

3 files changed

+178
-77
lines changed

3 files changed

+178
-77
lines changed

packages/gatsby-cli/src/structured-errors/error-map.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,77 @@ const errorMap = {
8989
type: `PLUGIN`,
9090
level: `ERROR`,
9191
},
92+
"11322": {
93+
text: context =>
94+
`${
95+
context.pluginName
96+
} created a page and didn't pass the path to the component.\n\nThe page object passed to createPage:\n${JSON.stringify(
97+
context.pageObject,
98+
null,
99+
4
100+
)}\n\nSee the documentation for the "createPage" action — https://www.gatsbyjs.org/docs/actions/#createPage`,
101+
level: `ERROR`,
102+
},
103+
"11323": {
104+
text: context =>
105+
`${
106+
context.pluginName
107+
} must set the page path when creating a page.\n\nThe page object passed to createPage:\n${JSON.stringify(
108+
context.pageObject,
109+
null,
110+
4
111+
)}\n\nSee the documentation for the "createPage" action — https://www.gatsbyjs.org/docs/actions/#createPage`,
112+
level: `ERROR`,
113+
},
114+
"11324": {
115+
text: context =>
116+
`${
117+
context.message
118+
}\n\nSee the documentation for the "createPage" action — https://www.gatsbyjs.org/docs/actions/#createPage`,
119+
level: `ERROR`,
120+
},
121+
"11325": {
122+
text: context =>
123+
`${
124+
context.pluginName
125+
} created a page with a component that doesn't exist.\n\nThe path to the missing component is "${
126+
context.component
127+
}"\n\nThe page object passed to createPage:\n${JSON.stringify(
128+
context.pageObject,
129+
null,
130+
4
131+
)}\n\nSee the documentation for the "createPage" action — https://www.gatsbyjs.org/docs/actions/#createPage`,
132+
level: `ERROR`,
133+
},
134+
"11326": {
135+
text: context =>
136+
`${
137+
context.pluginName
138+
} must set the absolute path to the page component when create creating a page.\n\nThe (relative) path you used for the component is "${
139+
context.component
140+
}"\n\nYou can convert a relative path to an absolute path by requiring the path module and calling path.resolve() e.g.\n\nconst path = require("path")\npath.resolve("${
141+
context.component
142+
}")\n\nThe page object passed to createPage:\n${JSON.stringify(
143+
context.pageObject,
144+
null,
145+
4
146+
)}\n\nSee the documentation for the "createPage" action — https://www.gatsbyjs.org/docs/actions/#createPage`,
147+
level: `ERROR`,
148+
},
149+
"11327": {
150+
text: context =>
151+
`You have an empty file in the "src/pages" directory at "${
152+
context.relativePath
153+
}". Please remove it or make it a valid component`,
154+
level: `ERROR`,
155+
},
156+
"11328": {
157+
text: context =>
158+
`A page component must export a React component for it to be valid. Please make sure this file exports a React component:\n\n${
159+
context.fileName
160+
}`,
161+
level: `ERROR`,
162+
},
92163
}
93164

94165
module.exports = { errorMap, defaultError: errorMap[``] }

packages/gatsby/src/redux/__tests__/__snapshots__/pages.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`Add pages Fails if component path is missing 1`] = `"The plugin \\"test\\" must set the absolute path to the page component when create creating a page"`;
3+
exports[`Add pages Fails if component path is missing 1`] = `"A component must be set when creating a page"`;
44

55
exports[`Add pages Fails if path is missing 1`] = `"The plugin \\"test\\" must set the page path when creating a page"`;
66

packages/gatsby/src/redux/actions/public.js

Lines changed: 106 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ actions.createPage = (
111111
plugin?: Plugin,
112112
actionOptions?: ActionOptions
113113
) => {
114-
let noPageOrComponent = false
115114
let name = `The plugin "${plugin.name}"`
116115
if (plugin.name === `default-site-plugin`) {
117116
name = `Your site's "gatsby-node.js"`
@@ -120,13 +119,17 @@ actions.createPage = (
120119
const message = `${name} must set the page path when creating a page`
121120
// Don't log out when testing
122121
if (process.env.NODE_ENV !== `test`) {
123-
console.log(chalk.bold.red(message))
124-
console.log(``)
125-
console.log(page)
122+
report.panic({
123+
id: `11323`,
124+
context: {
125+
pluginName: name,
126+
pageObject: page,
127+
message,
128+
},
129+
})
126130
} else {
127131
return message
128132
}
129-
noPageOrComponent = true
130133
}
131134

132135
// Validate that the context object doesn't overlap with any core page fields
@@ -176,7 +179,12 @@ ${reservedFields.map(f => ` * "${f}"`).join(`\n`)}
176179
// version. People in v1 often thought that they needed to also pass
177180
// the path to context for it to be available in GraphQL
178181
} else if (invalidFields.some(f => page.context[f] !== page[f])) {
179-
report.panic(error)
182+
report.panic({
183+
id: `11324`,
184+
context: {
185+
message: error,
186+
},
187+
})
180188
} else {
181189
if (!hasWarnedForPageComponentInvalidContext.has(page.component)) {
182190
report.warn(error)
@@ -186,83 +194,99 @@ ${reservedFields.map(f => ` * "${f}"`).join(`\n`)}
186194
}
187195
}
188196

197+
// Check if a component is set.
198+
if (!page.component) {
199+
if (process.env.NODE_ENV !== `test`) {
200+
report.panic({
201+
id: `11322`,
202+
context: {
203+
pluginName: name,
204+
pageObject: page,
205+
},
206+
})
207+
} else {
208+
// For test
209+
return `A component must be set when creating a page`
210+
}
211+
}
212+
189213
// Don't check if the component exists during tests as we use a lot of fake
190214
// component paths.
191215
if (process.env.NODE_ENV !== `test`) {
192216
if (!fileExistsSync(page.component)) {
193-
const message = `${name} created a page with a component that doesn't exist. Missing component is ${
194-
page.component
195-
}`
196-
console.log(``)
197-
console.log(chalk.bold.red(message))
198-
console.log(``)
199-
console.log(page)
200-
noPageOrComponent = true
201-
} else if (page.component) {
202-
// check if we've processed this component path
203-
// before, before running the expensive "truePath"
204-
// operation
205-
if (pageComponentCache[page.component]) {
206-
page.component = pageComponentCache[page.component]
207-
} else {
208-
const originalPageComponent = page.component
209-
210-
// normalize component path
211-
page.component = slash(page.component)
212-
// check if path uses correct casing - incorrect casing will
213-
// cause issues in query compiler and inconsistencies when
214-
// developing on Mac or Windows and trying to deploy from
215-
// linux CI/CD pipeline
216-
const trueComponentPath = slash(truePath(page.component))
217-
if (trueComponentPath !== page.component) {
218-
if (!hasWarnedForPageComponentInvalidCasing.has(page.component)) {
219-
const markers = page.component
220-
.split(``)
221-
.map((letter, index) => {
222-
if (letter !== trueComponentPath[index]) {
223-
return `^`
224-
}
225-
return ` `
226-
})
227-
.join(``)
228-
229-
report.warn(
230-
stripIndent`
231-
${name} created a page with a component path that doesn't match the casing of the actual file. This may work locally, but will break on systems which are case-sensitive, e.g. most CI/CD pipelines.
232-
233-
page.component: "${page.component}"
234-
path in filesystem: "${trueComponentPath}"
235-
${markers}
236-
`
237-
)
238-
hasWarnedForPageComponentInvalidCasing.add(page.component)
239-
}
240-
241-
page.component = trueComponentPath
242-
}
243-
pageComponentCache[originalPageComponent] = page.component
244-
}
217+
report.panic({
218+
id: `11325`,
219+
context: {
220+
pluginName: name,
221+
pageObject: page,
222+
component: page.component,
223+
},
224+
})
245225
}
246226
}
247-
248-
if (!page.component || !path.isAbsolute(page.component)) {
249-
const message = `${name} must set the absolute path to the page component when create creating a page`
227+
if (!path.isAbsolute(page.component)) {
250228
// Don't log out when testing
251229
if (process.env.NODE_ENV !== `test`) {
252-
console.log(``)
253-
console.log(chalk.bold.red(message))
254-
console.log(``)
255-
console.log(page)
230+
report.panic({
231+
id: `11326`,
232+
context: {
233+
pluginName: name,
234+
pageObject: page,
235+
component: page.component,
236+
},
237+
})
256238
} else {
239+
const message = `${name} must set the absolute path to the page component when create creating a page`
257240
return message
258241
}
259-
noPageOrComponent = true
260242
}
261243

262-
if (noPageOrComponent) {
263-
report.panic(
264-
`See the documentation for createPage https://www.gatsbyjs.org/docs/actions/#createPage`
265-
)
244+
// check if we've processed this component path
245+
// before, before running the expensive "truePath"
246+
// operation
247+
//
248+
// Skip during testing as the paths don't exist on disk.
249+
if (process.env.NODE_ENV !== `test`) {
250+
if (pageComponentCache[page.component]) {
251+
page.component = pageComponentCache[page.component]
252+
} else {
253+
const originalPageComponent = page.component
254+
255+
// normalize component path
256+
page.component = slash(page.component)
257+
// check if path uses correct casing - incorrect casing will
258+
// cause issues in query compiler and inconsistencies when
259+
// developing on Mac or Windows and trying to deploy from
260+
// linux CI/CD pipeline
261+
const trueComponentPath = slash(truePath(page.component))
262+
if (trueComponentPath !== page.component) {
263+
if (!hasWarnedForPageComponentInvalidCasing.has(page.component)) {
264+
const markers = page.component
265+
.split(``)
266+
.map((letter, index) => {
267+
if (letter !== trueComponentPath[index]) {
268+
return `^`
269+
}
270+
return ` `
271+
})
272+
.join(``)
273+
274+
report.warn(
275+
stripIndent`
276+
${name} created a page with a component path that doesn't match the casing of the actual file. This may work locally, but will break on systems which are case-sensitive, e.g. most CI/CD pipelines.
277+
278+
page.component: "${page.component}"
279+
path in filesystem: "${trueComponentPath}"
280+
${markers}
281+
`
282+
)
283+
hasWarnedForPageComponentInvalidCasing.add(page.component)
284+
}
285+
286+
page.component = trueComponentPath
287+
}
288+
pageComponentCache[originalPageComponent] = page.component
289+
}
266290
}
267291

268292
let internalComponentName
@@ -325,15 +349,21 @@ ${reservedFields.map(f => ` * "${f}"`).join(`\n`)}
325349
)
326350

327351
if (!notEmpty) {
328-
report.panicOnBuild(
329-
`You have an empty file in the "src/pages" directory at "${relativePath}". Please remove it or make it a valid component`
330-
)
352+
report.panicOnBuild({
353+
id: `11327`,
354+
context: {
355+
relativePath,
356+
},
357+
})
331358
}
332359

333360
if (!includesDefaultExport) {
334-
report.panicOnBuild(
335-
`[${fileName}] The page component must export a React component for it to be valid`
336-
)
361+
report.panicOnBuild({
362+
id: `11328`,
363+
context: {
364+
fileName,
365+
},
366+
})
337367
}
338368
}
339369

0 commit comments

Comments
 (0)