Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby): New overlay for DEV_SSR #31061

Merged
merged 29 commits into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fa973ed
wip
LekoArts Apr 26, 2021
bbf8ece
update lock fiel
LekoArts Apr 26, 2021
fe66c81
working error codes in json
LekoArts Apr 27, 2021
1f6814c
get the overlay correctly working (albeit with a little hack :D)
LekoArts Apr 27, 2021
862e9ca
add note for reloading page
LekoArts Apr 28, 2021
d87f716
fix build-html ts issue
LekoArts Apr 28, 2021
a8fb25e
fix snapshot test
LekoArts Apr 28, 2021
08c3f66
use error message inside react template itself instead of hacky solution
LekoArts Apr 29, 2021
87ed4fc
fix unit test
LekoArts Apr 29, 2021
4ce68fa
cypress tests
LekoArts Apr 29, 2021
a256448
update snapshot
LekoArts Apr 29, 2021
52fdd95
use status(200)
LekoArts May 3, 2021
051171b
404 with cypress options
LekoArts May 3, 2021
0a87b43
try some stuff
LekoArts May 4, 2021
938a29f
rename code to sourceContent
LekoArts May 4, 2021
e8af19e
remove unused stuff
LekoArts May 4, 2021
5f7d19e
use custom structured error for failure on dev-404-page
LekoArts May 5, 2021
e364f3a
Merge remote-tracking branch 'upstream/master' into dev-ssr-new-overlay
May 5, 2021
81b4885
revert some e2e changes
LekoArts May 6, 2021
a7ba407
revert some failOnStatusCode changes
LekoArts May 6, 2021
2143440
try catch for clientOnlyShell
LekoArts May 6, 2021
daf954c
minimal html for error outside of module scope
LekoArts May 6, 2021
9edb3f9
account for disabled JS
LekoArts May 6, 2021
3b00bde
updates snapshot
LekoArts May 6, 2021
7615e6c
use snapshot serializer
LekoArts May 6, 2021
4ecfd3c
update snapshot
pieh May 6, 2021
9eb5a5b
make stripIndent actually strip intendent
pieh May 6, 2021
4430c5f
maybe correct snapshot now?
pieh May 6, 2021
8826dc7
colors are bad
pieh May 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,38 @@ Cypress.on(`window:before:load`, win => {

const runTests = () => {
it(`should redirect page to index page when there is no such page`, () => {
cy.visit(`/redirect-without-page`).waitForRouteChange()
cy.visit(`/redirect-without-page`, {
failOnStatusCode: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left these in as in the future when we'd send 404 for the not found page those would fail

}).waitForRouteChange()

cy.location(`pathname`).should(`equal`, `/`)
cy.then(() => {
const calls = spy.getCalls()

const callsAboutRedirectMatchingPage = calls.filter(call => {
return call.args[0].includes(
"matches both a page and a redirect; this is probably not intentional."
const callsAboutRedirectMatchingPage = calls.filter(call =>
call.args[0].includes(
`matches both a page and a redirect; this is probably not intentional.`
)
})
)

expect(callsAboutRedirectMatchingPage.length).to.equal(0)
})
})

it(`should redirect page to index page even there is a such page`, () => {
cy.visit(`/redirect`).waitForRouteChange()
cy.visit(`/redirect`, {
failOnStatusCode: false,
}).waitForRouteChange()

cy.location(`pathname`).should(`equal`, `/`)
cy.then(() => {
const calls = spy.getCalls()

const callsAboutRedirectMatchingPage = calls.filter(call => {
return call.args[0].includes(
"matches both a page and a redirect; this is probably not intentional."
const callsAboutRedirectMatchingPage = calls.filter(call =>
call.args[0].includes(
`matches both a page and a redirect; this is probably not intentional.`
)
})
)

expect(callsAboutRedirectMatchingPage.length).not.to.equal(0)
expect(spy).to.be.calledWith(
Expand All @@ -42,43 +46,47 @@ const runTests = () => {
})

it(`should redirect to a dynamically-created replacement page`, () => {
cy.visit(`/redirect-me/`).waitForRouteChange()
cy.visit(`/redirect-me/`, {
failOnStatusCode: false,
}).waitForRouteChange()

cy.location(`pathname`).should(`equal`, `/pt/redirect-me/`)
cy.then(() => {
expect(spy).not.to.be.calledWith(
`The route "/redirect" matches both a page and a redirect; this is probably not intentional.`
)

cy.findByText("This should be at /pt/redirect-me/", {
cy.findByText(`This should be at /pt/redirect-me/`, {
exact: false,
}).should(`exist`)
})
})
}

describe(`redirect`, () => {
describe("404 is present", () => {
describe(`404 is present`, () => {
before(() => {
cy.task(`restoreAllBlockedResources`)
})

// this is sanity check for this group
it(`make sure 404 is present`, () => {
cy.visit(`/______not_existing_page`).waitForRouteChange()
cy.findByText("Preview custom 404 page").click()
cy.findByText("A custom 404 page wasn't detected", {
cy.visit(`/______not_existing_page`, {
failOnStatusCode: false,
}).waitForRouteChange()
cy.findByText(`Preview custom 404 page`).click()
cy.findByText(`A custom 404 page wasn't detected`, {
exact: false,
}).should(`not.exist`)
cy.findByText(
"You just hit a route that does not exist... the sadness."
`You just hit a route that does not exist... the sadness.`
).should(`exist`)
})

runTests()
})

describe("no 404", () => {
describe(`no 404`, () => {
before(() => {
cy.task(`restoreAllBlockedResources`)

Expand All @@ -100,13 +108,15 @@ describe(`redirect`, () => {
})

it(`make sure 404 is NOT present`, () => {
cy.visit(`/______not_existing_page`).waitForRouteChange()
cy.findByText("Preview custom 404 page").click()
cy.findByText("A custom 404 page wasn't detected", {
cy.visit(`/______not_existing_page`, {
failOnStatusCode: false,
}).waitForRouteChange()
cy.findByText(`Preview custom 404 page`).click()
cy.findByText(`A custom 404 page wasn't detected`, {
exact: false,
}).should(`exist`)
cy.findByText(
"You just hit a route that does not exist... the sadness.",
`You just hit a route that does not exist... the sadness.`,
{ exact: false }
).should(`not.exist`)
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
describe(`page not found`, () => {
beforeEach(() => {
cy.visit(`/__404__`)
cy.visit(`/__404__`, {
failOnStatusCode: false,
})
})
it(`should display message `, () => {
cy.get(`h1`).invoke(`text`).should(`eq`, `Gatsby.js development 404 page`)
Expand Down
133 changes: 1 addition & 132 deletions integration-tests/ssr/__tests__/__snapshots__/ssr.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,135 +2,4 @@

exports[`SSR is run for a page when it is requested 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><link data-identity=\\"gatsby-dev-css\\" rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/commons.css\\"/><meta name=\\"note\\" content=\\"environment=development\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" id=\\"gatsby-focus-wrapper\\"><div><h1 class=\\"hi\\">Hello world</h1></div></div><div id=\\"gatsby-announcer\\" style=\\"position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\\" aria-live=\\"assertive\\" aria-atomic=\\"true\\"></div></div><script src=\\"/polyfill.js\\" nomodule=\\"\\"></script><script src=\\"/framework.js\\"></script><script src=\\"/commons.js\\"></script></body></html>"`;

exports[`SSR it generates an error page correctly 1`] = `
"<head>
<title>Develop SSR Error</title>
<style>
* {
--gatsby: #663399;
--gatsbyLight: #9158ca;
--dimmedWhite: rgba(255, 255, 255, 0.8);
--white: #ffffff;
--black: #000000;
--color-ansi-selection: rgba(95, 126, 151, 0.48);
--color-ansi-bg: #fafafa;
--color-ansi-fg: #545454;
--color-ansi-white: #969896;
--color-ansi-black: #141414;
--color-ansi-blue: #183691;
--color-ansi-cyan: #007faa;
--color-ansi-green: #008000;
--color-ansi-magenta: #795da3;
--color-ansi-red: #d91e18;
--color-ansi-yellow: #aa5d00;
--color-ansi-bright-white: #ffffff;
--color-ansi-bright-black: #545454;
--color-ansi-bright-blue: #183691;
--color-ansi-bright-cyan: #007faa;
--color-ansi-bright-green: #008000;
--color-ansi-bright-magenta: #795da3;
--color-ansi-bright-red: #d91e18;
--color-ansi-bright-yellow: #aa5d00;
--radii: 5px;
--z-index-normal: 5;
--z-index-elevated: 10;
--space: 1.5em;
--space-sm: 1em;
--space-lg: 2.5em;
}
[data-gatsby-overlay=\\"backdrop\\"] {
background: rgba(72, 67, 79, 0.5);
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: var(--z-index-normal);
backdrop-filter: blur(10px);
}
body {
font: 18px/1.5 -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto,
Helvetica, Arial, sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\",
\\"Segoe UI Symbol\\" !important;
background: var(--color-ansi-bright-white);
padding: var(--space);
overflow: auto;
}
h1,
h2,
h3 {
display: flex;
align-items: center;
color: var(--dimmedWhite);
background: var(--gatsby);
padding: var(--space);
border-top-left-radius: var(--radii);
border-top-right-radius: var(--radii);
}
code {
font-family: Consolas, \\"Andale Mono WT\\", \\"Andale Mono\\", \\"Lucida Console\\", \\"Lucida Sans Typewriter\\", \\"DejaVu Sans Mono\\", \\"Bitstream Vera Sans Mono\\", \\"Liberation Mono\\", \\"Nimbus Mono L\\", Monaco, \\"Courier New\\", Courier, monospace;
}
pre {
margin: 0;
color: var(--color-ansi-fg);
padding: var(--space-sm);
border-radius: var(--radii);
}
button {
cursor: pointer;
border: 1px;
padding: 10px;
background-color: var(--gatsbyLight);
color: var(--white);
appearance: none;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radii);
}
</style>
</head>
<h1>Error</h1>
<h2>The page didn't server render (SSR) correctly</h2>
<p style=\\"padding-left: var(--space-sm);\\">
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.
</p>
<ul>
<li><strong>URL path:</strong> <code>/bad-page/</code></li>
<li><strong>File path:</strong> <code>src/pages/bad-page.js</code></li>
</ul>
<h3>error</h3>
<code style=\\"padding: var(--space);padding-left: var(--space-sm);\\">window is not defined</code>
<pre><span style=\\"font-weight:normal;opacity:1;color:#452475;background:#ffffff;\\"> <span style=\\"color:#527713;\\"> 2 |</span></span>
<span style=\\"font-weight:normal;opacity:1;color:#452475;background:#ffffff;\\"> <span style=\\"color:#527713;\\"> 3 |</span> <span style=\\"color:#006500;\\">const</span> <span style=\\"color:#DB3A00;\\">Component</span> <span style=\\"color:#DB3A00;\\">=</span> () <span style=\\"color:#DB3A00;\\">=></span> {</span>
<span style=\\"font-weight:normal;opacity:1;color:#452475;background:#ffffff;\\"><span style=\\"color:#096fb3;\\"><span style=\\"font-weight:bold;\\">></span></span><span style=\\"color:#527713;\\"> 4 |</span> <span style=\\"color:#006500;\\">const</span> a <span style=\\"color:#DB3A00;\\">=</span> window<span style=\\"color:#DB3A00;\\">.</span>width</span>
<span style=\\"font-weight:normal;opacity:1;color:#452475;background:#ffffff;\\"> <span style=\\"color:#527713;\\"> |</span> <span style=\\"color:#096fb3;\\"><span style=\\"font-weight:bold;\\">^</span></span></span>
<span style=\\"font-weight:normal;opacity:1;color:#452475;background:#ffffff;\\"> <span style=\\"color:#527713;\\"> 5 |</span></span>
<span style=\\"font-weight:normal;opacity:1;color:#452475;background:#ffffff;\\"> <span style=\\"color:#527713;\\"> 6 |</span> <span style=\\"color:#006500;\\">return</span> <span style=\\"color:#DB3A00;\\"><</span><span style=\\"color:#DB3A00;\\">div</span><span style=\\"color:#DB3A00;\\">></span>hi<span style=\\"color:#DB3A00;\\"><</span><span style=\\"color:#DB3A00;\\">/</span><span style=\\"color:#DB3A00;\\">div</span><span style=\\"color:#DB3A00;\\">></span></span>
<span style=\\"font-weight:normal;opacity:1;color:#452475;background:#ffffff;\\"> <span style=\\"color:#527713;\\"> 7 |</span> }</span></pre>
<p>For help debugging SSR errors, see this docs page: <a
href=\\"https://www.gatsbyjs.com/docs/debugging-html-builds/\\">https://www.gatsbyjs.com/docs/debugging-html-builds/</a></p>
<h3>Skip SSR</h3>
<p style=\\"padding-left: var(--space-sm);\\">
If you don't wish to fix the SSR error at the moment, press the
button below to reload the page without attempting SSR</p>
<p style=\\"padding-left: var(--space-sm);\\">
<strong>Note</strong>: this error will show up in when you build your site so must be fixed before then.</p>
<p style=\\"padding-left: var(--space-sm);\\">
<strong>Caveat</strong>: SSR errors in module scope i.e. outside of your components can't be skipped so will need fixed before you can continue</p>
<button style=\\"margin-left: var(--space-sm);\\" onclick='refreshWithQueryString()'>Skip SSR</button>
<script>
function refreshWithQueryString() {
if ('URLSearchParams' in window) {
var searchParams = new URLSearchParams(window.location.search);
searchParams.set(\\"skip-ssr\\", \\"true\\");
window.location.search = searchParams.toString();
}
}
</script>
"
`;
exports[`SSR it generates an error page correctly 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><link data-identity=\\"gatsby-dev-css\\" rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/commons.css\\"/><meta name=\\"note\\" content=\\"environment=development\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" id=\\"gatsby-focus-wrapper\\"></div><div id=\\"gatsby-announcer\\" style=\\"position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\\" aria-live=\\"assertive\\" aria-atomic=\\"true\\"></div></div><script>window._gatsbyEvents = window._gatsbyEvents || []; window._gatsbyEvents.push([\\"FAST_REFRESH\\", { action: \\"SHOW_DEV_SSR_ERROR\\", payload: {\\"codeFrame\\":\\"\\\\u001b[0m \\\\u001b[90m 2 |\\\\u001b[39m\\\\u001b[0m\\\\n\\\\u001b[0m \\\\u001b[90m 3 |\\\\u001b[39m \\\\u001b[36mconst\\\\u001b[39m \\\\u001b[33mComponent\\\\u001b[39m \\\\u001b[33m=\\\\u001b[39m () \\\\u001b[33m=>\\\\u001b[39m {\\\\u001b[0m\\\\n\\\\u001b[0m\\\\u001b[31m\\\\u001b[1m>\\\\u001b[22m\\\\u001b[39m\\\\u001b[90m 4 |\\\\u001b[39m \\\\u001b[36mconst\\\\u001b[39m a \\\\u001b[33m=\\\\u001b[39m window\\\\u001b[33m.\\\\u001b[39mwidth\\\\u001b[0m\\\\n\\\\u001b[0m \\\\u001b[90m |\\\\u001b[39m \\\\u001b[31m\\\\u001b[1m^\\\\u001b[22m\\\\u001b[39m\\\\u001b[0m\\\\n\\\\u001b[0m \\\\u001b[90m 5 |\\\\u001b[39m\\\\u001b[0m\\\\n\\\\u001b[0m \\\\u001b[90m 6 |\\\\u001b[39m \\\\u001b[36mreturn\\\\u001b[39m \\\\u001b[33m<\\\\u001b[39m\\\\u001b[33mdiv\\\\u001b[39m\\\\u001b[33m>\\\\u001b[39mhi\\\\u001b[33m<\\\\u001b[39m\\\\u001b[33m/\\\\u001b[39m\\\\u001b[33mdiv\\\\u001b[39m\\\\u001b[33m>\\\\u001b[39m\\\\u001b[0m\\\\n\\\\u001b[0m \\\\u001b[90m 7 |\\\\u001b[39m }\\\\u001b[0m\\",\\"source\\":\\"src/pages/bad-page.js\\",\\"line\\":4,\\"column\\":13} }])</script><script src=\\"/polyfill.js\\" nomodule=\\"\\"></script><script src=\\"/framework.js\\"></script><script src=\\"/commons.js\\"></script></body></html>"`;
2 changes: 1 addition & 1 deletion integration-tests/ssr/__tests__/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe(`SSR`, () => {
const pageUrl = `http://localhost:8000/bad-page/`
// Poll until the new page is bundled (so starts returning a non-404 status).
const rawDevHtml = await fetchUntil(pageUrl, res => {
return res.status === 500
return res
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't explicitly send 500 status anymore as other errors (runtime, build, graphql) also don't do that

}).then(res => res.text())
expect(rawDevHtml).toMatchSnapshot()
await fs.remove(dest)
Expand Down
23 changes: 12 additions & 11 deletions packages/gatsby-cli/src/structured-errors/error-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,18 +549,19 @@ 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.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's a WARNING the docsUrl is unused. Also added stripIndent

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stripIndent won't do anything here because it looks for shortest indentation and removes that from every line - in here shortest indentation is empty string (because first line doesn't have any indentation)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

above comment addressed in 9eb5a5b

Edit its component ${context.filePath}${
context.line ? `:${context.line}:${context.column}` : ``
} to resolve the error.`),
level: Level.WARNING,
docsUrl: `https://gatsby.dev/debug-html`,
},
"11615": {
text: (context): string =>
stripIndent(`There was an error while trying to load dev-404-page:
${context.sourceMessage}`),
level: Level.ERROR,
category: ErrorCategory.SYSTEM,
},
// Watchdog
"11701": {
Expand Down
10 changes: 5 additions & 5 deletions packages/gatsby/cache-dir/__tests__/static-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ describe(`develop-static-entry`, () => {
test(`SSR: onPreRenderHTML can be used to replace headComponents`, done => {
global.plugins = [fakeStylesPlugin, reverseHeadersPlugin]

ssrDevelopStaticEntry(`/about/`, false, publicDir, (_, html) => {
ssrDevelopStaticEntry(`/about/`, false, publicDir, undefined, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
Expand All @@ -207,7 +207,7 @@ describe(`develop-static-entry`, () => {
reverseBodyComponentsPluginFactory(`Post`),
]

ssrDevelopStaticEntry(`/about/`, false, publicDir, (_, html) => {
ssrDevelopStaticEntry(`/about/`, false, publicDir, undefined, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
Expand All @@ -219,14 +219,14 @@ describe(`develop-static-entry`, () => {
reverseBodyComponentsPluginFactory(`Pre`),
]

ssrDevelopStaticEntry(`/about/`, false, publicDir, (_, html) => {
ssrDevelopStaticEntry(`/about/`, false, publicDir, undefined, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
})

test(`SSR: onPreRenderHTML adds metatag note for development environment`, done => {
ssrDevelopStaticEntry(`/about/`, false, publicDir, (_, html) => {
ssrDevelopStaticEntry(`/about/`, false, publicDir, undefined, (_, html) => {
expect(html).toContain(
`<meta name="note" content="environment=development"/>`
)
Expand All @@ -237,7 +237,7 @@ describe(`develop-static-entry`, () => {
test(`SSR: onPreRenderHTML adds metatag note for development environment after replaceHeadComponents`, done => {
global.plugins = [reverseHeadersPlugin]

ssrDevelopStaticEntry(`/about/`, false, publicDir, (_, html) => {
ssrDevelopStaticEntry(`/about/`, false, publicDir, undefined, (_, html) => {
expect(html).toContain(
`<meta name="note" content="environment=development"/>`
)
Expand Down
Loading