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

Retry Static Data Fetch on Hydration #10513

Merged
merged 2 commits into from Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 15 additions & 8 deletions packages/next/next-server/lib/router/router.ts
Expand Up @@ -70,19 +70,26 @@ function fetchNextData(
isServerRender: boolean,
cb?: (...args: any) => any
) {
return fetch(
formatWithValidation({
// @ts-ignore __NEXT_DATA__
pathname: `/_next/data/${__NEXT_DATA__.buildId}${pathname}.json`,
query,
})
)
.then(res => {
let attempts = isServerRender ? 3 : 1
function getResponse(): Promise<any> {
return fetch(
formatWithValidation({
// @ts-ignore __NEXT_DATA__
pathname: `/_next/data/${__NEXT_DATA__.buildId}${pathname}.json`,
query,
})
).then(res => {
if (!res.ok) {
if (--attempts > 0 && res.status >= 500) {
return getResponse()
}
throw new Error(`Failed to load static props`)
}
return res.json()
})
}

return getResponse()
.then(data => {
return cb ? cb(data) : data
})
Expand Down
8 changes: 8 additions & 0 deletions test/integration/prerender/pages/blog/[post]/index.js
Expand Up @@ -16,6 +16,8 @@ export async function unstable_getStaticPaths() {
}
}

let counter = 0

// eslint-disable-next-line camelcase
export async function unstable_getStaticProps({ params }) {
if (params.post === 'post-10') {
Expand All @@ -28,6 +30,12 @@ export async function unstable_getStaticProps({ params }) {
throw new Error('such broken..')
}

if (params.post === 'post-999') {
if (++counter < 3) {
throw new Error('try again..')
}
}

return {
props: {
params,
Expand Down
3 changes: 3 additions & 0 deletions test/integration/prerender/pages/index.js
Expand Up @@ -32,6 +32,9 @@ const Page = ({ world, time }) => {
<Link href="/blog/[post]" as="/blog/post-100">
<a id="broken-post">to broken</a>
</Link>
<Link href="/blog/[post]" as="/blog/post-999">
<a id="broken-at-first-post">to broken at first</a>
</Link>
<br />
<Link href="/blog/[post]/[comment]" as="/blog/post-1/comment-1">
<a id="comment-1">to another dynamic</a>
Expand Down
15 changes: 15 additions & 0 deletions test/integration/prerender/test/index.test.js
Expand Up @@ -348,6 +348,21 @@ const runTests = (dev = false) => {
expect(await browser.eval('window.beforeClick')).not.toBe('true')
})

// TODO: dev currently renders this page as blocking, meaning it shows the
// server error instead of continously retrying. Do we want to change this?
if (!dev) {
it('should reload page on failed data request, and retry', async () => {
const browser = await webdriver(appPort, '/')
await browser.eval('window.beforeClick = true')
await browser.elementByCss('#broken-at-first-post').click()
await waitFor(3000)
expect(await browser.eval('window.beforeClick')).not.toBe('true')

const text = await browser.elementByCss('#params').text()
expect(text).toMatch(/post.*?post-999/)
})
}

it('should support prerendered catchall route', async () => {
const html = await renderViaHTTP(appPort, '/catchall/another/value')
const $ = cheerio.load(html)
Expand Down