Skip to content

Commit 9e14203

Browse files
gatsbybotLekoArts
andauthored
fix(gatsby): Improve readability of page data / long running query warnings (#37220) (#37229)
* show better page data information * clean up longrunning queries Alternative to #36876 Co-authored-by: Tyler Barnes <[email protected]> Co-authored-by: Daniel Lew <[email protected]> Co-authored-by: Tyler Barnes <[email protected]> Co-authored-by: Daniel Lew <[email protected]> (cherry picked from commit 031a08f) Co-authored-by: Lennart <[email protected]>
1 parent 3b75594 commit 9e14203

File tree

5 files changed

+172
-48
lines changed

5 files changed

+172
-48
lines changed

packages/gatsby/src/commands/build-html.ts

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Bluebird from "bluebird"
22
import fs from "fs-extra"
33
import reporter from "gatsby-cli/lib/reporter"
44
import { createErrorFromString } from "gatsby-cli/lib/reporter/errors"
5-
import { chunk, truncate } from "lodash"
5+
import { chunk } from "lodash"
66
import { build, watch } from "../utils/webpack/bundle"
77
import * as path from "path"
88
import fastq from "fastq"
@@ -18,14 +18,14 @@ import { Span } from "opentracing"
1818
import { IProgram, Stage } from "./types"
1919
import { ROUTES_DIRECTORY } from "../constants"
2020
import { PackageJson } from "../.."
21-
import { IPageDataWithQueryResult } from "../utils/page-data"
2221
import { getPublicPath } from "../utils/get-public-path"
2322

2423
import type { GatsbyWorkerPool } from "../utils/worker/pool"
2524
import { stitchSliceForAPage } from "../utils/slices/stitching"
2625
import type { ISlicePropsEntry } from "../utils/worker/child/render-html"
2726
import { getPageMode } from "../utils/page-mode"
2827
import { extractUndefinedGlobal } from "../utils/extract-undefined-global"
28+
import { modifyPageDataForErrorMessage } from "../utils/page-data"
2929

3030
type IActivity = any // TODO
3131

@@ -532,20 +532,6 @@ class BuildHTMLError extends Error {
532532
}
533533
}
534534

535-
const truncateObjStrings = (obj): IPageDataWithQueryResult => {
536-
// Recursively truncate strings nested in object
537-
// These objs can be quite large, but we want to preserve each field
538-
for (const key in obj) {
539-
if (typeof obj[key] === `object`) {
540-
truncateObjStrings(obj[key])
541-
} else if (typeof obj[key] === `string`) {
542-
obj[key] = truncate(obj[key], { length: 250 })
543-
}
544-
}
545-
546-
return obj
547-
}
548-
549535
export const doBuildPages = async (
550536
rendererPath: string,
551537
pagePaths: Array<string>,
@@ -563,22 +549,23 @@ export const doBuildPages = async (
563549

564550
if (error?.context?.path) {
565551
const pageData = await getPageData(error.context.path)
566-
const truncatedPageData = truncateObjStrings(pageData)
552+
const modifiedPageDataForErrorMessage =
553+
modifyPageDataForErrorMessage(pageData)
567554

568-
const pageDataMessage = `Page data from page-data.json for the failed page "${
555+
const errorMessage = `Truncated page data information for the failed page "${
569556
error.context.path
570-
}": ${JSON.stringify(truncatedPageData, null, 2)}`
557+
}": ${JSON.stringify(modifiedPageDataForErrorMessage, null, 2)}`
571558

572559
// This is our only error during preview so customize it a bit + add the
573560
// pretty build error.
574561
if (isPreview) {
575562
reporter.error({
576563
id: `95314`,
577-
context: { pageData: pageDataMessage },
564+
context: { errorMessage },
578565
error: buildError,
579566
})
580567
} else {
581-
reporter.error(pageDataMessage)
568+
reporter.error(errorMessage)
582569
}
583570
}
584571

packages/gatsby/src/query/query-runner.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,14 @@ export interface IQueryJob {
3737
pluginCreatorId?: string
3838
}
3939

40-
function reportLongRunningQueryJob(queryJob): void {
40+
function reportLongRunningQueryJob(queryJob: IQueryJob): void {
4141
const messageParts = [
42-
`This query took more than 15s to run — which is unusually long and might indicate you're querying too much or have some unoptimized code:`,
42+
`This query took more than 15s to run — which might indicate you're querying too much or have some unoptimized code:`,
4343
`File path: ${queryJob.componentPath}`,
4444
]
4545

46-
if (queryJob.isPage) {
47-
const { path, context } = queryJob.context
48-
messageParts.push(`URL path: ${path}`)
49-
50-
if (!_.isEmpty(context)) {
51-
messageParts.push(`Context: ${JSON.stringify(context, null, 4)}`)
52-
}
46+
if (queryJob.queryType === `page`) {
47+
messageParts.push(`URL path: ${queryJob.context.path}`)
5348
}
5449

5550
report.warn(messageParts.join(`\n`))

packages/gatsby/src/utils/__tests__/page-data.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import {
44
savePageQueryResult,
55
readPageQueryResult,
66
waitUntilPageQueryResultsAreStored,
7+
modifyPageDataForErrorMessage,
8+
IPageDataWithQueryResult,
79
} from "../page-data"
810

911
describe(`savePageQueryResults / readPageQueryResults`, () => {
@@ -24,3 +26,111 @@ describe(`savePageQueryResults / readPageQueryResults`, () => {
2426
expect(JSON.parse(result)).toEqual(inputResult)
2527
})
2628
})
29+
30+
describe(`modifyPageDataForErrorMessage`, () => {
31+
it(`handles optional data gracefully`, () => {
32+
const input: IPageDataWithQueryResult = {
33+
path: `/foo/`,
34+
componentChunkName: `component`,
35+
matchPath: `/`,
36+
slicesMap: {},
37+
staticQueryHashes: [],
38+
result: {},
39+
}
40+
expect(modifyPageDataForErrorMessage(input)).toMatchInlineSnapshot(`
41+
Object {
42+
"errors": Object {},
43+
"matchPath": "/",
44+
"path": "/foo/",
45+
"slicesMap": Object {},
46+
}
47+
`)
48+
})
49+
it(`outputs expected result shape`, () => {
50+
const input: IPageDataWithQueryResult = {
51+
path: `/foo/`,
52+
componentChunkName: `component`,
53+
matchPath: `/`,
54+
slicesMap: {
55+
foo: `bar`,
56+
},
57+
getServerDataError: [
58+
{
59+
level: `ERROR`,
60+
text: `error`,
61+
stack: [{ fileName: `a` }],
62+
type: `UNKNOWN`,
63+
},
64+
],
65+
staticQueryHashes: [`123`],
66+
result: {
67+
data: undefined,
68+
// @ts-ignore - Can ignore for this test
69+
errors: [`error`],
70+
extensions: {
71+
foo: `bar`,
72+
},
73+
pageContext: {
74+
foo: `bar`,
75+
},
76+
serverData: {
77+
foo: `bar`,
78+
},
79+
},
80+
}
81+
expect(modifyPageDataForErrorMessage(input)).toMatchInlineSnapshot(`
82+
Object {
83+
"errors": Object {
84+
"getServerData": Array [
85+
Object {
86+
"level": "ERROR",
87+
"stack": Array [
88+
Object {
89+
"fileName": "a",
90+
},
91+
],
92+
"text": "error",
93+
"type": "UNKNOWN",
94+
},
95+
],
96+
"graphql": Array [
97+
"error",
98+
],
99+
},
100+
"matchPath": "/",
101+
"pageContext": Object {
102+
"foo": "bar",
103+
},
104+
"path": "/foo/",
105+
"slicesMap": Object {
106+
"foo": "bar",
107+
},
108+
}
109+
`)
110+
})
111+
it(`doesn't print out the GraphQL result and serverData result`, () => {
112+
const input: IPageDataWithQueryResult = {
113+
path: `/foo/`,
114+
componentChunkName: `component`,
115+
matchPath: `/`,
116+
slicesMap: {},
117+
staticQueryHashes: [],
118+
result: {
119+
data: {
120+
foo: `bar`,
121+
},
122+
serverData: {
123+
foo: `bar`,
124+
},
125+
},
126+
}
127+
expect(modifyPageDataForErrorMessage(input)).toMatchInlineSnapshot(`
128+
Object {
129+
"errors": Object {},
130+
"matchPath": "/",
131+
"path": "/foo/",
132+
"slicesMap": Object {},
133+
}
134+
`)
135+
})
136+
})

packages/gatsby/src/utils/page-data.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,3 +452,45 @@ export async function handleStalePageData(parentSpan: Span): Promise<void> {
452452

453453
activity.end()
454454
}
455+
456+
interface IModifyPageDataForErrorMessage {
457+
errors: {
458+
graphql?: IPageDataWithQueryResult["result"]["errors"]
459+
getServerData?: IPageDataWithQueryResult["getServerDataError"]
460+
}
461+
graphqlExtensions?: IPageDataWithQueryResult["result"]["extensions"]
462+
pageContext?: IPageDataWithQueryResult["result"]["pageContext"]
463+
path: IPageDataWithQueryResult["path"]
464+
matchPath: IPageDataWithQueryResult["matchPath"]
465+
slicesMap: IPageDataWithQueryResult["slicesMap"]
466+
}
467+
468+
export function modifyPageDataForErrorMessage(
469+
input: IPageDataWithQueryResult
470+
): IModifyPageDataForErrorMessage {
471+
const optionalData = {
472+
...(input.result?.pageContext
473+
? { pageContext: input.result.pageContext }
474+
: {}),
475+
...(input.result?.pageContext
476+
? { pageContext: input.result.pageContext }
477+
: {}),
478+
}
479+
480+
const optionalErrors = {
481+
...(input.result?.errors ? { graphql: input.result.errors } : {}),
482+
...(input.getServerDataError
483+
? { getServerData: input.getServerDataError }
484+
: {}),
485+
}
486+
487+
return {
488+
errors: {
489+
...optionalErrors,
490+
},
491+
path: input.path,
492+
matchPath: input.matchPath,
493+
slicesMap: input.slicesMap,
494+
...optionalData,
495+
}
496+
}

packages/gatsby/src/utils/worker/child/render-html.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import Bluebird from "bluebird"
55
import * as path from "path"
66
import { generateHtmlPath } from "gatsby-core-utils/page-html"
77
import { generatePageDataPath } from "gatsby-core-utils/page-data"
8-
import { truncate } from "lodash"
98

109
import {
1110
readWebpackStats,
@@ -14,6 +13,7 @@ import {
1413
} from "../../client-assets-for-template"
1514
import {
1615
IPageDataWithQueryResult,
16+
modifyPageDataForErrorMessage,
1717
readPageData,
1818
readSliceData,
1919
} from "../../page-data"
@@ -135,20 +135,6 @@ async function getResourcesForTemplate(
135135
return resources
136136
}
137137

138-
const truncateObjStrings = (obj): IPageDataWithQueryResult => {
139-
// Recursively truncate strings nested in object
140-
// These objs can be quite large, but we want to preserve each field
141-
for (const key in obj) {
142-
if (typeof obj[key] === `object` && obj[key] !== null) {
143-
truncateObjStrings(obj[key])
144-
} else if (typeof obj[key] === `string`) {
145-
obj[key] = truncate(obj[key], { length: 250 })
146-
}
147-
}
148-
149-
return obj
150-
}
151-
152138
interface IPreviewErrorProps {
153139
pagePath: string
154140
publicDir: string
@@ -161,7 +147,7 @@ const generatePreviewErrorPage = async ({
161147
error,
162148
}: IPreviewErrorProps): Promise<string> => {
163149
const pageData = await readPageData(publicDir, pagePath)
164-
const truncatedPageData = truncateObjStrings(pageData)
150+
const pageDataForErrorMessage = modifyPageDataForErrorMessage(pageData)
165151

166152
const html = `<!doctype html>
167153
<html lang="en">
@@ -359,8 +345,12 @@ const generatePreviewErrorPage = async ({
359345
<p>Below you'll find additional data that might help you debug the error.</p>
360346
<details>
361347
<summary>Page Data</summary>
362-
<p>The page data contains some metadata about the affected page but also the GraphQL data if you have queries in your page. If e.g. data from the GraphQL query is undefined, check if it's available here.</p>
363-
<pre><code>${JSON.stringify(truncatedPageData, null, 2)}</code></pre>
348+
<p>The page data contains some metadata about the affected page. If data from the GraphQL is undefined, try running the query in the GraphiQL IDE.</p>
349+
<pre><code>${JSON.stringify(
350+
pageDataForErrorMessage,
351+
null,
352+
2
353+
)}</code></pre>
364354
</details>
365355
</main>
366356
</body>

0 commit comments

Comments
 (0)