From fc22f4ba3ad7ca5fb3592f38f4f0ca8ae60b4bf7 Mon Sep 17 00:00:00 2001 From: GatsbyJS Bot Date: Fri, 5 May 2023 13:40:44 -0400 Subject: [PATCH] fix(gatsby): don't serve codeframes for files outside of compilation (#38059) (#38063) * test: add test case for overlay handlers * fix: don't serve codeframes for files outside of compilation (cherry picked from commit ed5855e511ce00c765525c687f36d1be177c22f2) Co-authored-by: Michal Piechowiak --- .../development-runtime/SHOULD_NOT_SERVE | 2 +- .../error-handling/overlay-endpoints.js | 11 +++++ packages/gatsby/src/commands/build-html.ts | 6 +++ packages/gatsby/src/utils/start-server.ts | 22 +++++++++- .../utils/is-file-inside-compilations.ts | 42 +++++++++++++++++++ 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 e2e-tests/development-runtime/cypress/integration/hot-reloading/error-handling/overlay-endpoints.js create mode 100644 packages/gatsby/src/utils/webpack/utils/is-file-inside-compilations.ts diff --git a/e2e-tests/development-runtime/SHOULD_NOT_SERVE b/e2e-tests/development-runtime/SHOULD_NOT_SERVE index 73068df3213cb..48b27a60e1401 100644 --- a/e2e-tests/development-runtime/SHOULD_NOT_SERVE +++ b/e2e-tests/development-runtime/SHOULD_NOT_SERVE @@ -1 +1 @@ -this file shouldn't be allowed to be served +this file shouldn't be allowed to be served. CYPRESS-MARKER diff --git a/e2e-tests/development-runtime/cypress/integration/hot-reloading/error-handling/overlay-endpoints.js b/e2e-tests/development-runtime/cypress/integration/hot-reloading/error-handling/overlay-endpoints.js new file mode 100644 index 0000000000000..5220331dc2633 --- /dev/null +++ b/e2e-tests/development-runtime/cypress/integration/hot-reloading/error-handling/overlay-endpoints.js @@ -0,0 +1,11 @@ +const cwd = Cypress.config(`projectRoot`) + +describe(`overlay handlers don't serve unrelated files`, () => { + it(`__file-code-frame`, () => { + cy.request( + `__file-code-frame?filePath=${cwd}/SHOULD_NOT_SERVE&lineNumber=0` + ).should(response => { + expect(response.body.codeFrame).not.to.match(/CYPRESS-MARKER/) + }) + }) +}) diff --git a/packages/gatsby/src/commands/build-html.ts b/packages/gatsby/src/commands/build-html.ts index a13696a4da687..eeb366c713780 100644 --- a/packages/gatsby/src/commands/build-html.ts +++ b/packages/gatsby/src/commands/build-html.ts @@ -20,6 +20,8 @@ import { PackageJson } from "../.." import { IPageDataWithQueryResult } from "../utils/page-data" import type { GatsbyWorkerPool } from "../utils/worker/pool" +import { setFilesFromDevelopHtmlCompilation } from "../utils/webpack/utils/is-file-inside-compilations" + type IActivity = any // TODO const isPreview = process.env.GATSBY_IS_PREVIEW === `true` @@ -211,6 +213,10 @@ const doBuildRenderer = async ( ) } + if (stage === `develop-html`) { + setFilesFromDevelopHtmlCompilation(stats.compilation) + } + // render-page.js is hard coded in webpack.config return { rendererPath: `${directory}/${ROUTES_DIRECTORY}render-page.js`, diff --git a/packages/gatsby/src/utils/start-server.ts b/packages/gatsby/src/utils/start-server.ts index e6b3270a5b1fd..0fae323c546e0 100644 --- a/packages/gatsby/src/utils/start-server.ts +++ b/packages/gatsby/src/utils/start-server.ts @@ -1,7 +1,7 @@ import webpackHotMiddleware from "@gatsbyjs/webpack-hot-middleware" import webpackDevMiddleware from "webpack-dev-middleware" import got, { Method } from "got" -import webpack from "webpack" +import webpack, { Compilation } from "webpack" import express from "express" import compression from "compression" import { graphqlHTTP, OptionsData } from "express-graphql" @@ -55,6 +55,7 @@ import { getPageMode } from "./page-mode" import { configureTrailingSlash } from "./express-middlewares" import type { Express } from "express" import { addImageRoutes } from "gatsby-plugin-utils/polyfill-remote-file" +import { isFileInsideCompilations } from "./webpack/utils/is-file-inside-compilations" type ActivityTracker = any // TODO: Replace this with proper type once reporter is typed @@ -502,7 +503,24 @@ export async function startServer( return } - const sourceContent = await fs.readFile(filePath, `utf-8`) + const absolutePath = path.resolve( + store.getState().program.directory, + filePath + ) + + const compilation: Compilation = + res.locals?.webpack?.devMiddleware?.stats?.compilation + if (!compilation) { + res.json(emptyResponse) + return + } + + if (!isFileInsideCompilations(absolutePath, compilation)) { + res.json(emptyResponse) + return + } + + const sourceContent = await fs.readFile(absolutePath, `utf-8`) const codeFrame = codeFrameColumns( sourceContent, diff --git a/packages/gatsby/src/utils/webpack/utils/is-file-inside-compilations.ts b/packages/gatsby/src/utils/webpack/utils/is-file-inside-compilations.ts new file mode 100644 index 0000000000000..10fd470dac75e --- /dev/null +++ b/packages/gatsby/src/utils/webpack/utils/is-file-inside-compilations.ts @@ -0,0 +1,42 @@ +import { Compilation, NormalModule } from "webpack" + +const filesInsideDevelopHtmlCompilation = new Set() + +function removeQueryParams(path: string): string { + return path.split(`?`)[0] +} + +export function setFilesFromDevelopHtmlCompilation( + developHtmlCompilation: Compilation +): void { + filesInsideDevelopHtmlCompilation.clear() + + for (const module of developHtmlCompilation.modules) { + if (module instanceof NormalModule && module.resource) { + filesInsideDevelopHtmlCompilation.add(removeQueryParams(module.resource)) + } + } +} + +/** + * Checks if a file is inside either `develop` or `develop-html` compilation. Used to determine if + * we should generate codeframe for this file for error overlay. + */ +export function isFileInsideCompilations( + absolutePath: string, + developBrowserCompilation: Compilation +): boolean { + if (filesInsideDevelopHtmlCompilation.has(absolutePath)) { + return true + } + + for (const module of developBrowserCompilation.modules) { + if (module instanceof NormalModule && module.resource) { + if (absolutePath === removeQueryParams(module.resource)) { + return true + } + } + } + + return false +}