diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 562eed1b6fece..c7071093ff5aa 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -208,8 +208,8 @@ function patchFetch(ComponentMod: any) { const staticGenerationAsyncStorage = ComponentMod.staticGenerationAsyncStorage - const origFetch = globalThis.fetch - globalThis.fetch = async (url, opts) => { + const originFetch = globalThis.fetch + globalThis.fetch = async (input, init) => { const staticGenerationStore = 'getStore' in staticGenerationAsyncStorage ? staticGenerationAsyncStorage.getStore() @@ -219,18 +219,18 @@ function patchFetch(ComponentMod: any) { staticGenerationStore || {} if (staticGenerationStore && isStaticGeneration) { - if (opts && typeof opts === 'object') { - if (opts.cache === 'no-store') { + if (init && typeof init === 'object') { + if (init.cache === 'no-store') { staticGenerationStore.revalidate = 0 // TODO: ensure this error isn't logged to the user // seems it's slipping through currently throw new DynamicServerError( - `no-store fetch ${url}${pathname ? ` ${pathname}` : ''}` + `no-store fetch ${input}${pathname ? ` ${pathname}` : ''}` ) } - const hasNextConfig = 'next' in opts - const next = (hasNextConfig && opts.next) || {} + const hasNextConfig = 'next' in init + const next = init.next || {} if ( typeof next.revalidate === 'number' && (typeof fetchRevalidate === 'undefined' || @@ -241,15 +241,15 @@ function patchFetch(ComponentMod: any) { // TODO: ensure this error isn't logged to the user // seems it's slipping through currently throw new DynamicServerError( - `revalidate: ${next.revalidate} fetch ${url}${ + `revalidate: ${next.revalidate} fetch ${input}${ pathname ? ` ${pathname}` : '' }` ) } - if (hasNextConfig) delete opts.next + if (hasNextConfig) delete init.next } } - return origFetch(url, opts) + return originFetch(input, init) } } diff --git a/packages/next/server/node-polyfill-fetch.js b/packages/next/server/node-polyfill-fetch.js index 745c37d169870..9b2d359c107e3 100644 --- a/packages/next/server/node-polyfill-fetch.js +++ b/packages/next/server/node-polyfill-fetch.js @@ -6,6 +6,17 @@ if (!global.fetch) { ? require('next/dist/compiled/undici') : require('next/dist/compiled/node-fetch') } + + function getRequestImpl() { + const OriginRequest = getFetchImpl().Request + return class Request extends OriginRequest { + constructor(input, init) { + super(input, init) + this.next = init?.next + } + } + } + // Due to limitation of global configuration, we have to do this resolution at runtime global.fetch = (...args) => { const fetchImpl = getFetchImpl() @@ -44,7 +55,7 @@ if (!global.fetch) { }, Request: { get() { - return getFetchImpl().Request + return getRequestImpl() }, }, Response: { diff --git a/packages/next/server/web/sandbox/context.ts b/packages/next/server/web/sandbox/context.ts index 943b8e2076ff7..da0d334f979c5 100644 --- a/packages/next/server/web/sandbox/context.ts +++ b/packages/next/server/web/sandbox/context.ts @@ -265,6 +265,7 @@ Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`), const __Request = context.Request context.Request = class extends __Request { + next?: NextFetchRequestConfig | undefined constructor(input: URL | RequestInfo, init?: RequestInit | undefined) { const url = typeof input !== 'string' && 'url' in input @@ -272,6 +273,7 @@ Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`), : String(input) validateURL(url) super(url, init) + this.next = init?.next } } diff --git a/packages/next/types/global.d.ts b/packages/next/types/global.d.ts index f3e2d59d3829f..e07479561b08e 100644 --- a/packages/next/types/global.d.ts +++ b/packages/next/types/global.d.ts @@ -12,6 +12,10 @@ declare namespace NodeJS { interface ProcessEnv { readonly NODE_ENV: 'development' | 'production' | 'test' } + + interface RequestInit extends globalThis.RequestInit { + next?: NextFetchRequestConfig | undefined + } } declare module '*.module.css' { @@ -34,11 +38,10 @@ interface Window { __NEXT_HMR_CB?: null | ((message?: string) => void) } -type NextFetchRequestConfig = { +interface NextFetchRequestConfig { revalidate?: number } -declare function fetch( - url: RequestInfo, - opts: RequestInit & { next?: NextFetchRequestConfig } -): Promise +interface RequestInit { + next?: NextFetchRequestConfig | undefined +} diff --git a/test/e2e/app-dir/app-alias/src/app/typing/page.tsx b/test/e2e/app-dir/app-alias/src/app/typing/page.tsx new file mode 100644 index 0000000000000..593d8b7f4b3ad --- /dev/null +++ b/test/e2e/app-dir/app-alias/src/app/typing/page.tsx @@ -0,0 +1,11 @@ +// Typing test +// eslint-disable-next-line +function noop() { + fetch('/button', { next: { revalidate: 0 } }) + const request = new Request('/button', { next: { revalidate: 0 } }) + fetch(request) +} + +export default function page() { + return 'typing' +}