Skip to content

Commit

Permalink
Move fetch revalidate config under next options (vercel#41505)
Browse files Browse the repository at this point in the history
  • Loading branch information
huozhi authored and Kikobeats committed Oct 24, 2022
1 parent 5117ff3 commit 20999e9
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 16 deletions.
26 changes: 18 additions & 8 deletions packages/next/server/app-render.tsx
Expand Up @@ -207,9 +207,8 @@ function patchFetch(ComponentMod: any) {

const staticGenerationAsyncStorage = ComponentMod.staticGenerationAsyncStorage

const origFetch = (global as any).fetch

;(global as any).fetch = async (init: any, opts: any) => {
const origFetch = globalThis.fetch
globalThis.fetch = async (url, opts) => {
const staticGenerationStore =
'getStore' in staticGenerationAsyncStorage
? staticGenerationAsyncStorage.getStore()
Expand All @@ -225,20 +224,31 @@ function patchFetch(ComponentMod: any) {
// TODO: ensure this error isn't logged to the user
// seems it's slipping through currently
throw new DynamicServerError(
`no-store fetch ${init}${pathname ? ` ${pathname}` : ''}`
`no-store fetch ${url}${pathname ? ` ${pathname}` : ''}`
)
}

const hasNextConfig = 'next' in opts
const next = (hasNextConfig && opts.next) || {}
if (
typeof opts.revalidate === 'number' &&
typeof next.revalidate === 'number' &&
(typeof fetchRevalidate === 'undefined' ||
opts.revalidate < fetchRevalidate)
next.revalidate < fetchRevalidate)
) {
staticGenerationStore.fetchRevalidate = opts.revalidate
staticGenerationStore.fetchRevalidate = next.revalidate

// TODO: ensure this error isn't logged to the user
// seems it's slipping through currently
throw new DynamicServerError(
`revalidate: ${next.revalidate} fetch ${url}${
pathname ? ` ${pathname}` : ''
}`
)
}
if (hasNextConfig) delete opts.next
}
}
return origFetch(init, opts)
return origFetch(url, opts)
}
}

Expand Down
9 changes: 9 additions & 0 deletions packages/next/types/global.d.ts
Expand Up @@ -32,3 +32,12 @@ declare module '*.module.scss' {
interface Window {
MSInputMethodContext?: unknown
}

type NextFetchRequestConfig = {
revalidate?: number
}

declare function fetch(
url: RequestInfo,
opts: RequestInit & { next?: NextFetchRequestConfig }
): Promise<Response>
45 changes: 39 additions & 6 deletions test/e2e/app-dir/app-static.test.ts
Expand Up @@ -59,7 +59,8 @@ describe('app-dir static/dynamic handling', () => {
'blog/tim/first-post.rsc',
'dynamic-no-gen-params-ssr/[slug]/page.js',
'dynamic-no-gen-params/[slug]/page.js',
'ssr-auto/page.js',
'ssr-auto/cache-no-store/page.js',
'ssr-auto/fetch-revalidate-zero/page.js',
'ssr-forced/page.js',
])
})
Expand Down Expand Up @@ -264,29 +265,61 @@ describe('app-dir static/dynamic handling', () => {
expect(await browser.eval('window.beforeNav')).toBe(1)
})

it('should ssr dynamically when detected automatically', async () => {
const initialRes = await fetchViaHTTP(next.url, '/ssr-auto', undefined, {
it('should ssr dynamically when detected automatically with fetch cache option', async () => {
const pathname = '/ssr-auto/cache-no-store'
const initialRes = await fetchViaHTTP(next.url, pathname, undefined, {
redirect: 'manual',
})
expect(initialRes.status).toBe(200)

const initialHtml = await initialRes.text()
const initial$ = cheerio.load(initialHtml)

expect(initial$('#page').text()).toBe('/ssr-auto')
expect(initial$('#page').text()).toBe(pathname)
const initialDate = initial$('#date').text()

expect(initialHtml).toContain('Example Domain')

const secondRes = await fetchViaHTTP(next.url, '/ssr-auto', undefined, {
const secondRes = await fetchViaHTTP(next.url, pathname, undefined, {
redirect: 'manual',
})
expect(secondRes.status).toBe(200)

const secondHtml = await secondRes.text()
const second$ = cheerio.load(secondHtml)

expect(second$('#page').text()).toBe('/ssr-auto')
expect(second$('#page').text()).toBe(pathname)
const secondDate = second$('#date').text()

expect(secondHtml).toContain('Example Domain')
expect(secondDate).not.toBe(initialDate)
})

// TODO-APP: support fetch revalidate case for dynamic rendering
it.skip('should ssr dynamically when detected automatically with fetch revalidate option', async () => {
const pathname = '/ssr-auto/fetch-revalidate-zero'
const initialRes = await fetchViaHTTP(next.url, pathname, undefined, {
redirect: 'manual',
})
expect(initialRes.status).toBe(200)

const initialHtml = await initialRes.text()
const initial$ = cheerio.load(initialHtml)

expect(initial$('#page').text()).toBe(pathname)
const initialDate = initial$('#date').text()

expect(initialHtml).toContain('Example Domain')

const secondRes = await fetchViaHTTP(next.url, pathname, undefined, {
redirect: 'manual',
})
expect(secondRes.status).toBe(200)

const secondHtml = await secondRes.text()
const second$ = cheerio.load(secondHtml)

expect(second$('#page').text()).toBe(pathname)
const secondDate = second$('#date').text()

expect(secondHtml).toContain('Example Domain')
Expand Down
@@ -1,4 +1,4 @@
import { cache, use } from '../../lib/utils'
import { cache, use } from '../../../lib/utils'

export default function Page() {
const getData = () =>
Expand All @@ -12,7 +12,7 @@ export default function Page() {

return (
<>
<p id="page">/ssr-auto</p>
<p id="page">/ssr-auto/cache-no-store</p>
<div id="example-dat">{data}</div>
<p id="date">{Date.now()}</p>
</>
Expand Down
@@ -0,0 +1,3 @@
export default function Page() {
return <p>loading...</p>
}
@@ -0,0 +1,25 @@
import { cache, use } from '../../../lib/utils'

export default function Page() {
const getData = () =>
fetch('https://example.vercel.sh', {
next: { revalidate: 0 },
})
.then((res) => res.text())
.then((text) => new Promise((res) => setTimeout(() => res(text), 1000)))
const dataPromise = cache(getData)
const data = use(dataPromise)

return (
<>
<p id="page">/ssr-auto/fetch-revalidate-zero</p>
<div id="example-dat">{data}</div>
<p id="date">{Date.now()}</p>
</>
)
}

// TODO-APP: remove revalidate config once next.revalidate is supported
export const config = {
revalidate: 0,
}

0 comments on commit 20999e9

Please sign in to comment.