From fa973ed029f24e20ba43b59db2c498393e2c7b31 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 26 Apr 2021 16:43:28 +0200 Subject: [PATCH 01/28] wip --- .../src/structured-errors/error-map.ts | 16 +- packages/gatsby/package.json | 2 - .../dev-ssr/__tests__/develop-html-route.ts | 25 --- .../__tests__/fixtures/error-object.js | 33 --- .../src/utils/dev-ssr/develop-html-route.ts | 199 ------------------ .../utils/dev-ssr/render-dev-html-child.js | 86 +------- .../src/utils/dev-ssr/render-dev-html.ts | 20 +- packages/gatsby/src/utils/start-server.ts | 128 ++++++++++- 8 files changed, 152 insertions(+), 357 deletions(-) delete mode 100644 packages/gatsby/src/utils/dev-ssr/__tests__/develop-html-route.ts delete mode 100644 packages/gatsby/src/utils/dev-ssr/__tests__/fixtures/error-object.js delete mode 100644 packages/gatsby/src/utils/dev-ssr/develop-html-route.ts diff --git a/packages/gatsby-cli/src/structured-errors/error-map.ts b/packages/gatsby-cli/src/structured-errors/error-map.ts index 8460f93c84ff3..d2c326bd5cb81 100644 --- a/packages/gatsby-cli/src/structured-errors/error-map.ts +++ b/packages/gatsby-cli/src/structured-errors/error-map.ts @@ -549,18 +549,12 @@ const errors = { docsUrl: `https://www.gatsbyjs.com/docs/reference/gatsby-cli#new`, }, "11614": { - text: ({ - path, - filePath, - line, - column, - }): string => `The path "${path}" errored during SSR. - - Edit its component ${filePath}${ - line ? `:${line}:${column}` : `` - } to resolve the error.`, + text: (context): string => + stripIndent(`The path "${context.path}" errored during SSR. + Edit its component ${context.filePath}${ + context.line ? `:${context.line}:${context.column}` : `` + } to resolve the error.`), level: Level.WARNING, - docsUrl: `https://gatsby.dev/debug-html`, }, // Watchdog "11701": { diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index 0afadd89c3225..1fde091f34f72 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -27,7 +27,6 @@ "@typescript-eslint/parser": "^4.15.2", "address": "1.1.2", "anser": "^2.0.1", - "ansi-html": "^0.0.7", "autoprefixer": "^10.2.4", "axios": "^0.21.1", "babel-loader": "^8.2.2", @@ -142,7 +141,6 @@ "socket.io": "3.1.1", "socket.io-client": "3.1.1", "source-map": "^0.7.3", - "source-map-support": "^0.5.19", "st": "^2.0.0", "stack-trace": "^0.0.10", "string-similarity": "^1.2.2", diff --git a/packages/gatsby/src/utils/dev-ssr/__tests__/develop-html-route.ts b/packages/gatsby/src/utils/dev-ssr/__tests__/develop-html-route.ts deleted file mode 100644 index d80c46b574c22..0000000000000 --- a/packages/gatsby/src/utils/dev-ssr/__tests__/develop-html-route.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as os from "os" -import { parseError } from "../render-dev-html-child" -import error from "./fixtures/error-object" - -describe(`error parsing`, () => { - it(`returns an object w/ the parsed error & codeframe`, () => { - // stack traces have real paths so \\, the fixture does not have them - if (os.platform() === `win32`) { - error.stack = error.stack.replace(/\//g, `\\`) - } - - const parsedError = parseError({ - err: error, - directory: __dirname, - componentPath: __filename, - }) - - expect(parsedError).toMatchObject({ - filename: `fixtures/blog-post.js`, - message: `window is not defined`, - type: `ReferenceError`, - stack: expect.any(String), - }) - }) -}) diff --git a/packages/gatsby/src/utils/dev-ssr/__tests__/fixtures/error-object.js b/packages/gatsby/src/utils/dev-ssr/__tests__/fixtures/error-object.js deleted file mode 100644 index 2bd7b3325ca29..0000000000000 --- a/packages/gatsby/src/utils/dev-ssr/__tests__/fixtures/error-object.js +++ /dev/null @@ -1,33 +0,0 @@ -module.exports = { - stack: `ReferenceError: window is not defined - at BlogPostRoute.render (/programs/blog/public/webpack:/lib/fixtures/blog-post.js:16:17) - at processChild (/programs/blog/node_modules/react-dom/cjs/react-dom-server.node.development.js:3134:18) - at resolve (/programs/blog/node_modules/react-dom/cjs/react-dom-server.node.development.js:2960:5) - at ReactDOMServerRenderer.render (/programs/blog/node_modules/react-dom/cjs/react-dom-server.node.development.js:3435:22) - at ReactDOMServerRenderer.read (/programs/blog/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29) - at renderToString (/programs/blog/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27) - at Module.default (/programs/blog/public/webpack:/lib/.cache/develop-static-entry.js:248:32) - at /programs/blog/node_modules/gatsby/src/utils/worker/render-html.ts:32:11 - at /programs/blog/node_modules/gatsby/src/utils/worker/render-html.ts:25:7 -From previous event: - at renderHTML (/programs/blog/node_modules/gatsby/src/utils/worker/render-html.ts:22:18) - at /programs/blog/node_modules/gatsby/src/utils/develop-html-route.ts:140:36 - at Layer.handle [as handle_request] (/programs/blog/node_modules/express/lib/router/layer.js:95:5) - at next (/programs/blog/node_modules/express/lib/router/route.js:137:13) - at Route.dispatch (/programs/blog/node_modules/express/lib/router/route.js:112:3) - at Layer.handle [as handle_request] (/programs/blog/node_modules/express/lib/router/layer.js:95:5) - at /programs/blog/node_modules/express/lib/router/index.js:281:22 - at param (/programs/blog/node_modules/express/lib/router/index.js:354:14) - at param (/programs/blog/node_modules/express/lib/router/index.js:365:14) - at Function.process_params (/programs/blog/node_modules/express/lib/router/index.js:410:3) - at next (/programs/blog/node_modules/express/lib/router/index.js:275:10) - at cors (/programs/blog/node_modules/cors/lib/index.js:188:7) - at /programs/blog/node_modules/cors/lib/index.js:224:17 - at originCallback (/programs/blog/node_modules/cors/lib/index.js:214:15) - at /programs/blog/node_modules/cors/lib/index.js:219:13 - at optionsCallback (/programs/blog/node_modules/cors/lib/index.js:199:9) - at corsMiddleware (/programs/blog/node_modules/cors/lib/index.js:204:7) - at Layer.handle [as handle_request] (/programs/blog/node_modules/express/lib/router/layer.js:95:5)`, - message: `window is not defined`, - type: `ReferenceError`, -} diff --git a/packages/gatsby/src/utils/dev-ssr/develop-html-route.ts b/packages/gatsby/src/utils/dev-ssr/develop-html-route.ts deleted file mode 100644 index 4a3b8f2596673..0000000000000 --- a/packages/gatsby/src/utils/dev-ssr/develop-html-route.ts +++ /dev/null @@ -1,199 +0,0 @@ -import report from "gatsby-cli/lib/reporter" -import { trackFeatureIsUsed } from "gatsby-telemetry" - -import { findPageByPath } from "../find-page-by-path" -import { renderDevHTML } from "./render-dev-html" -import { appendPreloadHeaders } from "../develop-preload-headers" - -export const route = ({ app, program, store }): any => - // Render an HTML page and serve it. - app.get(`*`, async (req, res, next) => { - trackFeatureIsUsed(`GATSBY_EXPERIMENTAL_DEV_SSR`) - - const pathObj = findPageByPath(store.getState(), decodeURI(req.path)) - - if (!pathObj) { - return next() - } - - await appendPreloadHeaders(pathObj.path, res) - - const htmlActivity = report.phantomActivity(`building HTML for path`, {}) - htmlActivity.start() - - try { - const renderResponse = await renderDevHTML({ - path: pathObj.path, - page: pathObj, - skipSsr: req.query[`skip-ssr`] || false, - store, - htmlComponentRendererPath: `${program.directory}/public/render-page.js`, - directory: program.directory, - }) - res.status(200).send(renderResponse) - } catch (error) { - // THe page errored but couldn't read the page component. - // This is a race condition when a page is deleted but its requested - // immediately after before anything can recompile. - if (error === `404 page`) { - return next() - } - - report.error({ - id: `11614`, - filePath: error.filename, - location: { - start: { - line: error.line, - column: error.row, - }, - }, - context: { - path: pathObj.path, - filePath: error.filename, - line: error.line, - column: error.row, - }, - }) - let errorHtml = ` - Develop SSR Error - - -

Error

-

The page didn't server render (SSR) correctly

-

- React components in Gatsby must render successfully in the browser and in a - node.js environment. When we tried to render your page component in - node.js, it errored. -

-
    -
  • URL path: ${pathObj.path}
  • -
  • File path: ${error.filename}
  • -
-

error

- ${error.message} - ` - - if (error.codeFrame) { - errorHtml += `
${error.codeFrame}
` - } - - // Add link to help page - errorHtml += ` -

For help debugging SSR errors, see this docs page: https://www.gatsbyjs.com/docs/debugging-html-builds/

` - - // Add skip ssr button - errorHtml += ` -

Skip SSR

-

- If you don't wish to fix the SSR error at the moment, press the - button below to reload the page without attempting SSR

-

- Note: this error will show up in when you build your site so must be fixed before then.

-

- Caveat: SSR errors in module scope i.e. outside of your components can't be skipped so will need fixed before you can continue

- - - ` - res.status(500).send(errorHtml) - } - - htmlActivity.end() - - // Make eslint happy - return null - }) diff --git a/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js b/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js index 04dd05732c1b1..0aefe3cea7990 100644 --- a/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js +++ b/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js @@ -1,14 +1,10 @@ -require(`source-map-support`).install() -const { codeFrameColumns } = require(`@babel/code-frame`) -const ansiHTML = require(`ansi-html`) -const fs = require(`fs-extra`) const sysPath = require(`path`) const { slash } = require(`gatsby-core-utils`) const getPosition = function (stackObject) { let filename let line - let row + let column // Because the JavaScript error stack has not yet been standardized, // wrap the stack parsing in a try/catch for a soft fail if an // unexpected stack is encountered. @@ -27,29 +23,18 @@ const getPosition = function (stackObject) { const splitLength = splitLine.length filename = splitLine[splitLength - 3] line = Number(splitLine[splitLength - 2]) - row = Number(splitLine[splitLength - 1]) + column = Number(splitLine[splitLength - 1]) } catch (err) { filename = `` line = 0 - row = 0 + column = 0 } return { filename, line, - row, + column, } } -// Colors taken from Gatsby's design tokens -// https://github.com/gatsbyjs/gatsby/blob/d8acab3a135fa8250a0eb3a47c67300dde6eae32/packages/gatsby-design-tokens/src/colors.js#L185-L205 -const colors = { - background: `fdfaf6`, - text: `452475`, - green: `137886`, - darkGreen: `006500`, - comment: `527713`, - keyword: `096fb3`, - yellow: `DB3A00`, -} // Code borrowed and modified from https://github.com/watilde/parse-error const parseError = function ({ err, directory, componentPath }) { @@ -76,51 +61,15 @@ const parseError = function ({ err, directory, componentPath }) { const trueFileName = filename.includes(`render-page`) ? componentPath : filename - const data = { + + return { filename: slash(sysPath.relative(directory, trueFileName)), message: message, type: type, stack: stack, + line: position.line, + column: position.column, } - - // Try to generate a codeFrame - try { - const code = fs.readFileSync(filename, `utf-8`) - const line = position.line - const row = position.row - ansiHTML.setColors({ - reset: [colors.text, `ffffff`], // [FOREGROUND-COLOR, BACKGROUND-COLOR] - black: `aaa`, // String - red: colors.keyword, - green: colors.green, - yellow: colors.yellow, - blue: `eee`, - magenta: `fff`, - cyan: colors.darkGreen, - lightgrey: `888`, - darkgrey: colors.comment, - }) - const codeFrame = ansiHTML( - codeFrameColumns( - code, - { - start: { line: line, column: row }, - }, - { forceColor: true } - ) - ) - - data.line = line - data.row = row - data.codeFrame = codeFrame - } catch (e) { - console.log( - `Couldn't read the file ${filename}, possibly due to source maps failing` - ) - console.log(`original error`, err) - } - - return data } exports.parseError = parseError @@ -151,23 +100,10 @@ exports.renderHTML = ({ }) } } catch (err) { - const stack = err.stack ? err.stack : `` + console.log({ err, componentPath, directory, path }) - // Only generate error pages for webpack errors. If it's not a webpack - // error, it's not a user error so probably a system error so we'll just - // panic and quit. - const regex = /webpack:[/\\]/gm - const moduleBuildFailed = /Module.build.failed/gm - if (stack.match(moduleBuildFailed)) { - reject(`500 page`) - } else if (!stack.match(regex)) { - console.log(`unexpected error while SSRing the path: ${path}`) - console.log(err) - reject(err) - } else { - const error = parseError({ err, directory, componentPath }) - reject(error) - } + const error = parseError({ err, directory, componentPath }) + reject(error) } }) diff --git a/packages/gatsby/src/utils/dev-ssr/render-dev-html.ts b/packages/gatsby/src/utils/dev-ssr/render-dev-html.ts index a8640cd81c62e..870b37040362b 100644 --- a/packages/gatsby/src/utils/dev-ssr/render-dev-html.ts +++ b/packages/gatsby/src/utils/dev-ssr/render-dev-html.ts @@ -3,15 +3,14 @@ import fs from "fs-extra" import nodePath from "path" import report from "gatsby-cli/lib/reporter" import { isCI } from "gatsby-core-utils" - +import { Stats } from "webpack" import { startListener } from "../../bootstrap/requires-writer" import { findPageByPath } from "../find-page-by-path" import { getPageData as getPageDataExperimental } from "../get-page-data" import { getDevSSRWebpack } from "../../commands/build-html" import { emitter } from "../../redux" -import { Stats } from "webpack" -const startWorker = (): any => { +const startWorker = (): JestWorker => { const newWorker = new JestWorker(require.resolve(`./render-dev-html-child`), { exposedMethods: [`renderHTML`, `deleteModuleCache`, `warmup`], numWorkers: 1, @@ -20,8 +19,8 @@ const startWorker = (): any => { env: { ...process.env, NODE_ENV: isCI() ? `production` : `development`, - forceColors: true, - GATSBY_EXPERIMENTAL_DEV_SSR: true, + forceColors: `true`, + GATSBY_EXPERIMENTAL_DEV_SSR: `true`, }, }, }) @@ -40,11 +39,11 @@ export const initDevWorkerPool = (): void => { } let changeCount = 0 -export const restartWorker = (htmlComponentRendererPath): void => { +export const restartWorker = (htmlComponentRendererPath: string): void => { changeCount += 1 // Forking is expensive — each time we re-require the outputted webpack // file, memory grows ~10 mb — 25 regenerations means ~250mb which seems - // like an accepatable amount of memory to grow before we reclaim it + // like an acceptable amount of memory to grow before we reclaim it // by rebooting the worker process. if (changeCount > 25) { const oldWorker = worker @@ -57,7 +56,10 @@ export const restartWorker = (htmlComponentRendererPath): void => { } } -const searchFileForString = (substring, filePath): Promise => +const searchFileForString = ( + substring: string, + filePath: string +): Promise => new Promise(resolve => { const escapedSubString = substring.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`) @@ -86,7 +88,7 @@ const searchFileForString = (substring, filePath): Promise => const ensurePathComponentInSSRBundle = async ( page, directory -): Promise => { +): Promise => { // This shouldn't happen. if (!page) { report.panic(`page not found`, page) diff --git a/packages/gatsby/src/utils/start-server.ts b/packages/gatsby/src/utils/start-server.ts index 374f954de1914..44366ded9b959 100644 --- a/packages/gatsby/src/utils/start-server.ts +++ b/packages/gatsby/src/utils/start-server.ts @@ -48,6 +48,7 @@ import { routeLoadingIndicatorRequests, writeVirtualLoadingIndicatorModule, } from "./loading-indicator" +import { renderDevHTML } from "./dev-ssr/render-dev-html" type ActivityTracker = any // TODO: Replace this with proper type once reporter is typed @@ -487,9 +488,130 @@ module.exports = { // Render an HTML page and serve it. if (process.env.GATSBY_EXPERIMENTAL_DEV_SSR) { - // Setup HTML route. - const { route } = require(`./dev-ssr/develop-html-route`) - route({ app, program, store }) + app.get(`*`, async (req, res, next) => { + telemetry.trackFeatureIsUsed(`GATSBY_EXPERIMENTAL_DEV_SSR`) + + const pathObj = findPageByPath(store.getState(), decodeURI(req.path)) + + if (!pathObj) { + return next() + } + + await appendPreloadHeaders(pathObj.path, res) + + const htmlActivity = report.phantomActivity(`building HTML for path`, {}) + htmlActivity.start() + + try { + const renderResponse = await renderDevHTML({ + path: pathObj.path, + page: pathObj, + skipSsr: req.query[`skip-ssr`] || false, + store, + htmlComponentRendererPath: `${program.directory}/public/render-page.js`, + directory: program.directory, + }) + res.status(200).send(renderResponse) + } catch (error) { + // The page errored but couldn't read the page component. + // This is a race condition when a page is deleted but its requested + // immediately after before anything can recompile. + if (error === `404 page`) { + return next() + } + + report.error({ + id: `11614`, + context: { + path: pathObj.path, + filePath: error.filename, + line: error.line, + column: error.column, + }, + }) + + const compilation = + res.locals?.webpack?.devMiddleware?.stats?.compilation + const emptyResponse = { + codeFrame: `No codeFrame could be generated`, + sourcePosition: null, + sourceContent: null, + } + + if (!compilation) { + res.json(emptyResponse) + } + + const moduleId = pathObj.path + const lineNumber = parseInt(error.line, 10) + const columnNumber = parseInt(error.column, 10) + + let fileModule + for (const module of compilation.modules) { + const moduleIdentifier = compilation.chunkGraph.getModuleId(module) + if (moduleIdentifier === moduleId) { + fileModule = module + break + } + } + + if (!fileModule) { + res.json(emptyResponse) + } + + // We need the internal webpack file that is used in the bundle, not the module source. + // It doesn't have the correct sourceMap. + const webpackSource = compilation?.codeGenerationResults + ?.get(fileModule) + ?.sources.get(`javascript`) + + const sourceMap = webpackSource?.map() + + if (!sourceMap) { + res.json(emptyResponse) + } + + const position = { + line: lineNumber, + column: columnNumber, + } + const result = await findOriginalSourcePositionAndContent( + sourceMap, + position + ) + + const sourcePosition = result?.sourcePosition + const sourceLine = sourcePosition?.line + const sourceColumn = sourcePosition?.column + const sourceContent = result?.sourceContent + + if (!sourceContent || !sourceLine) { + res.json(emptyResponse) + } + + const codeFrame = codeFrameColumns( + sourceContent, + { + start: { + line: sourceLine, + column: sourceColumn ?? 0, + }, + }, + { + highlightCode: true, + } + ) + res.json({ + codeFrame, + sourcePosition, + sourceContent, + }) + } + + htmlActivity.end() + + return null + }) } if ( From bbf8ece97a03df8ba65d853a179701b39e0790de Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 26 Apr 2021 16:49:58 +0200 Subject: [PATCH 02/28] update lock fiel --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 4a52b0c0a1c15..0851d932d41f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24996,7 +24996,7 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" -source-map-support@^0.5.0, source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.19: +source-map-support@^0.5.0, source-map-support@^0.5.16, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== From fe66c812ff051ae7d49f40e40259bab0703294a6 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Tue, 27 Apr 2021 13:52:16 +0200 Subject: [PATCH 03/28] working error codes in json --- .../components/dev-ssr-error.js | 28 +++++++ .../cache-dir/fast-refresh-overlay/index.js | 25 ++++++- packages/gatsby/package.json | 1 + .../utils/dev-ssr/render-dev-html-child.js | 7 +- packages/gatsby/src/utils/start-server.ts | 75 +++++-------------- yarn.lock | 2 +- 6 files changed, 78 insertions(+), 60 deletions(-) create mode 100644 packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js diff --git a/packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js b/packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js new file mode 100644 index 0000000000000..c198663b94109 --- /dev/null +++ b/packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js @@ -0,0 +1,28 @@ +import * as React from "react" +import { Overlay, Header, Body, Footer, HeaderOpenClose } from "./overlay" +import { CodeFrame } from "./code-frame" +import { prettifyStack, openInEditor } from "../utils" + +export function DevSsrError({ error }) { + return ( + +
+
+

Dev SSR

+ filename +
+ openInEditor(`test`, 1)} dismiss={false} /> +
+ +

Source

+
+
{JSON.stringify(error, null, 2)}
+
+
+ This error occurred during the build process and can only be dismissed + by fixing the error. +
+ +
+ ) +} diff --git a/packages/gatsby/cache-dir/fast-refresh-overlay/index.js b/packages/gatsby/cache-dir/fast-refresh-overlay/index.js index 640392c246928..8e8b016e939cb 100644 --- a/packages/gatsby/cache-dir/fast-refresh-overlay/index.js +++ b/packages/gatsby/cache-dir/fast-refresh-overlay/index.js @@ -5,6 +5,7 @@ import { Style } from "./style" import { BuildError } from "./components/build-error" import { RuntimeErrors } from "./components/runtime-errors" import { GraphqlErrors } from "./components/graphql-errors" +import { DevSsrError } from "./components/dev-ssr-error" const reducer = (state, event) => { switch (event.action) { @@ -14,9 +15,15 @@ const reducer = (state, event) => { case `CLEAR_RUNTIME_ERRORS`: { return { ...state, errors: [] } } + case `CLEAR_DEV_SSR_ERROR`: { + return { ...state, devSsrError: null } + } case `SHOW_COMPILE_ERROR`: { return { ...state, buildError: event.payload } } + case `SHOW_DEV_SSR_ERROR`: { + return { ...state, devSsrError: event.payload } + } case `HANDLE_RUNTIME_ERROR`: case `SHOW_RUNTIME_ERRORS`: { return { ...state, errors: state.errors.concat(event.payload) } @@ -47,6 +54,7 @@ const reducer = (state, event) => { const initialState = { errors: [], buildError: null, + devSsrError: null, graphqlErrors: [], } @@ -73,6 +81,16 @@ function DevOverlay({ children }) { } }, [dispatch]) + React.useEffect(() => { + async function fetchData() { + const res = await fetch(`/`) + console.log(res) + const json = await res.json() + console.log(json) + } + fetchData() + }, []) + const dismiss = () => { dispatch({ action: `DISMISS` }) window._gatsbyEvents = [] @@ -81,7 +99,9 @@ function DevOverlay({ children }) { const hasBuildError = state.buildError !== null const hasRuntimeErrors = Boolean(state.errors.length) const hasGraphqlErrors = Boolean(state.graphqlErrors.length) - const hasErrors = hasBuildError || hasRuntimeErrors || hasGraphqlErrors + const hasDevSsrError = state.devSsrError !== null + const hasErrors = + hasBuildError || hasRuntimeErrors || hasGraphqlErrors || hasDevSsrError // This component has a deliberate order (priority) const ErrorComponent = () => { @@ -94,6 +114,9 @@ function DevOverlay({ children }) { if (hasGraphqlErrors) { return } + if (hasDevSsrError) { + return + } return null } diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index 1fde091f34f72..c01e33ee54636 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -141,6 +141,7 @@ "socket.io": "3.1.1", "socket.io-client": "3.1.1", "source-map": "^0.7.3", + "source-map-support": "^0.5.19", "st": "^2.0.0", "stack-trace": "^0.0.10", "string-similarity": "^1.2.2", diff --git a/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js b/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js index 0aefe3cea7990..cabdfb3324f27 100644 --- a/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js +++ b/packages/gatsby/src/utils/dev-ssr/render-dev-html-child.js @@ -1,4 +1,6 @@ +require(`source-map-support`).install() const sysPath = require(`path`) +const fs = require(`fs-extra`) const { slash } = require(`gatsby-core-utils`) const getPosition = function (stackObject) { @@ -50,6 +52,8 @@ const parseError = function ({ err, directory, componentPath }) { ...position.filename.split(sysPath.sep).slice(2) ) + const code = fs.readFileSync(filename, `utf-8`) + const splitMessage = err.message ? err.message.split(`\n`) : [``] const message = splitMessage[splitMessage.length - 1] const type = err.type ? err.type : err.name @@ -66,6 +70,7 @@ const parseError = function ({ err, directory, componentPath }) { filename: slash(sysPath.relative(directory, trueFileName)), message: message, type: type, + code, stack: stack, line: position.line, column: position.column, @@ -100,8 +105,6 @@ exports.renderHTML = ({ }) } } catch (err) { - console.log({ err, componentPath, directory, path }) - const error = parseError({ err, directory, componentPath }) reject(error) } diff --git a/packages/gatsby/src/utils/start-server.ts b/packages/gatsby/src/utils/start-server.ts index 44366ded9b959..3d46a5cceca67 100644 --- a/packages/gatsby/src/utils/start-server.ts +++ b/packages/gatsby/src/utils/start-server.ts @@ -520,72 +520,29 @@ module.exports = { return next() } + const lineNumber = error?.line + const columnNumber = error?.column + const filePath = error?.filename + const sourceContent = error?.code + report.error({ id: `11614`, context: { path: pathObj.path, - filePath: error.filename, - line: error.line, - column: error.column, + filePath: filePath, + line: lineNumber, + column: columnNumber, }, }) - const compilation = - res.locals?.webpack?.devMiddleware?.stats?.compilation const emptyResponse = { + isDevSSRError: true, codeFrame: `No codeFrame could be generated`, sourcePosition: null, sourceContent: null, } - if (!compilation) { - res.json(emptyResponse) - } - - const moduleId = pathObj.path - const lineNumber = parseInt(error.line, 10) - const columnNumber = parseInt(error.column, 10) - - let fileModule - for (const module of compilation.modules) { - const moduleIdentifier = compilation.chunkGraph.getModuleId(module) - if (moduleIdentifier === moduleId) { - fileModule = module - break - } - } - - if (!fileModule) { - res.json(emptyResponse) - } - - // We need the internal webpack file that is used in the bundle, not the module source. - // It doesn't have the correct sourceMap. - const webpackSource = compilation?.codeGenerationResults - ?.get(fileModule) - ?.sources.get(`javascript`) - - const sourceMap = webpackSource?.map() - - if (!sourceMap) { - res.json(emptyResponse) - } - - const position = { - line: lineNumber, - column: columnNumber, - } - const result = await findOriginalSourcePositionAndContent( - sourceMap, - position - ) - - const sourcePosition = result?.sourcePosition - const sourceLine = sourcePosition?.line - const sourceColumn = sourcePosition?.column - const sourceContent = result?.sourceContent - - if (!sourceContent || !sourceLine) { + if (!sourceContent || !lineNumber) { res.json(emptyResponse) } @@ -593,8 +550,8 @@ module.exports = { sourceContent, { start: { - line: sourceLine, - column: sourceColumn ?? 0, + line: lineNumber, + column: columnNumber ?? 0, }, }, { @@ -602,8 +559,14 @@ module.exports = { } ) res.json({ + isDevSsrError: true, codeFrame, - sourcePosition, + sourcePosition: { + source: filePath, + line: lineNumber, + column: columnNumber ?? 0, + name: null, + }, sourceContent, }) } diff --git a/yarn.lock b/yarn.lock index 0851d932d41f3..4a52b0c0a1c15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24996,7 +24996,7 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" -source-map-support@^0.5.0, source-map-support@^0.5.16, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.19: +source-map-support@^0.5.0, source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== From 1f6814cbfbedd139ac2923935648b0ddd49b060f Mon Sep 17 00:00:00 2001 From: LekoArts Date: Tue, 27 Apr 2021 16:44:16 +0200 Subject: [PATCH 04/28] get the overlay correctly working (albeit with a little hack :D) --- .../components/dev-ssr-error.js | 46 +++++++++++++++---- .../components/overlay.js | 4 +- .../cache-dir/fast-refresh-overlay/index.js | 10 ---- .../cache-dir/fast-refresh-overlay/style.js | 8 ++-- .../cache-dir/fast-refresh-overlay/utils.js | 18 ++++---- packages/gatsby/src/utils/start-server.ts | 22 +++++---- 6 files changed, 64 insertions(+), 44 deletions(-) diff --git a/packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js b/packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js index c198663b94109..bd4563ba90a88 100644 --- a/packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js +++ b/packages/gatsby/cache-dir/fast-refresh-overlay/components/dev-ssr-error.js @@ -1,26 +1,54 @@ import * as React from "react" import { Overlay, Header, Body, Footer, HeaderOpenClose } from "./overlay" import { CodeFrame } from "./code-frame" -import { prettifyStack, openInEditor } from "../utils" +import { prettifyStack, openInEditor, skipSSR } from "../utils" export function DevSsrError({ error }) { + const { codeFrame, source, line } = error + const decoded = prettifyStack(codeFrame) + return (
-

Dev SSR

- filename +

Failed to server render (SSR)

+ {source}
- openInEditor(`test`, 1)} dismiss={false} /> + openInEditor(source, line)} + dismiss={false} + />
+

+ React Components in Gatsby must render both successfully in the + browser and in a Node.js environment. When we tried to render your + page component in Node.js, it errored. +

Source

-
-
{JSON.stringify(error, null, 2)}
+ +
+ See our docs page for more info on SSR errors:{` `} + + https://www.gatsbyjs.com/docs/debugging-html-builds/ +
-