From b097d4983ef6d0bb1aeceef6621ac297359365da Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 28 Feb 2023 17:30:55 -0700 Subject: [PATCH 1/2] fix: de-duplicated async storage access --- .../next-edge-app-route-loader/handle.ts | 2 +- .../static-generation-async-storage.ts | 2 +- packages/next/src/server/app-render.tsx | 10 +-- ...static-generation-async-storage-wrapper.ts | 9 +-- .../route-handlers/app-route-route-handler.ts | 6 +- packages/next/src/server/render.tsx | 2 +- .../server/run-with-request-async-storage.ts | 77 ------------------- ...un-with-static-generation-async-storage.ts | 41 ---------- 8 files changed, 15 insertions(+), 134 deletions(-) delete mode 100644 packages/next/src/server/run-with-request-async-storage.ts delete mode 100644 packages/next/src/server/run-with-static-generation-async-storage.ts diff --git a/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts b/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts index ffe1927328283..3353af0903cd3 100644 --- a/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts +++ b/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts @@ -30,7 +30,7 @@ export function getHandle({ page, mod }: any) { extendedReq, extendedRes, // TODO: pass incrementalCache here - {}, + { supportsDynamicHTML: false }, request ) diff --git a/packages/next/src/client/components/static-generation-async-storage.ts b/packages/next/src/client/components/static-generation-async-storage.ts index 78260ed4293c5..9977c0e07040d 100644 --- a/packages/next/src/client/components/static-generation-async-storage.ts +++ b/packages/next/src/client/components/static-generation-async-storage.ts @@ -8,7 +8,7 @@ export interface StaticGenerationStore { readonly isRevalidate?: boolean forceDynamic?: boolean - revalidate?: boolean | number + revalidate?: false | number forceStatic?: boolean dynamicShouldError?: boolean pendingRevalidates?: Promise[] diff --git a/packages/next/src/server/app-render.tsx b/packages/next/src/server/app-render.tsx index 30d394208a4ab..b619ccbe428d2 100644 --- a/packages/next/src/server/app-render.tsx +++ b/packages/next/src/server/app-render.tsx @@ -45,8 +45,8 @@ import type { StaticGenerationAsyncStorage } from '../client/components/static-g import type { RequestAsyncStorage } from '../client/components/request-async-storage' import { formatServerError } from '../lib/format-server-error' import { MetadataTree } from '../lib/metadata/metadata' -import { runWithRequestAsyncStorage } from './run-with-request-async-storage' -import { runWithStaticGenerationAsyncStorage } from './run-with-static-generation-async-storage' +import { RequestAsyncStorageWrapper } from './async-storage/request-async-storage-wrapper' +import { StaticGenerationAsyncStorageWrapper } from './async-storage/static-generation-async-storage-wrapper' import { collectMetadata } from '../lib/metadata/resolve-metadata' import type { MetadataItems } from '../lib/metadata/resolve-metadata' import { isClientReference } from '../build/is-client-reference' @@ -184,7 +184,7 @@ export type RenderOptsPartial = { dev?: boolean serverComponentManifest?: FlightManifest serverCSSManifest?: FlightCSSManifest - supportsDynamicHTML?: boolean + supportsDynamicHTML: boolean runtime?: ServerRuntime serverComponents?: boolean assetPrefix?: string @@ -2001,11 +2001,11 @@ export async function renderToHTMLOrFlight( return renderResult } - return runWithRequestAsyncStorage( + return RequestAsyncStorageWrapper.wrap( requestAsyncStorage, { req, res, renderOpts }, () => - runWithStaticGenerationAsyncStorage( + StaticGenerationAsyncStorageWrapper.wrap( staticGenerationAsyncStorage, { pathname, renderOpts }, () => wrappedRender() diff --git a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts index 71082538ae0cf..5c2ae6d505c31 100644 --- a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts @@ -7,7 +7,7 @@ export type RequestContext = { pathname: string renderOpts: { incrementalCache?: IncrementalCache - supportsDynamicHTML?: boolean + supportsDynamicHTML: boolean isRevalidate?: boolean isBot?: boolean } @@ -45,11 +45,8 @@ export class StaticGenerationAsyncStorageWrapper * These rules help ensure that other existing features like request caching, * coalescing, and ISR continue working as intended. */ - const supportsDynamicHTML = - typeof renderOpts.supportsDynamicHTML !== 'boolean' || - renderOpts.supportsDynamicHTML - - const isStaticGeneration = !supportsDynamicHTML && !renderOpts.isBot + const isStaticGeneration = + !renderOpts.supportsDynamicHTML && !renderOpts.isBot const store: StaticGenerationStore = { isStaticGeneration, diff --git a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts index ee1fffed9c82c..ef1abf867b8b1 100644 --- a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts @@ -93,7 +93,7 @@ export type AppRouteModule = { export type StaticGenerationContext = { incrementalCache?: IncrementalCache - supportsDynamicHTML?: boolean + supportsDynamicHTML: boolean } /** @@ -309,7 +309,9 @@ export class AppRouteRouteHandler implements RouteHandler { staticGenerationAsyncStorage, { pathname: definition.pathname, - renderOpts: context || {}, + renderOpts: context ?? { + supportsDynamicHTML: false, + }, }, () => { const _req = (request ? request : wrapRequest(req)) as NextRequest diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 4036142a7e725..73eb8ee7788ef 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -254,7 +254,7 @@ export type RenderOptsPartial = { defaultLocale?: string domainLocales?: DomainLocale[] disableOptimizedLoading?: boolean - supportsDynamicHTML?: boolean + supportsDynamicHTML: boolean isBot?: boolean runtime?: ServerRuntime serverComponents?: boolean diff --git a/packages/next/src/server/run-with-request-async-storage.ts b/packages/next/src/server/run-with-request-async-storage.ts deleted file mode 100644 index f202d33336d7c..0000000000000 --- a/packages/next/src/server/run-with-request-async-storage.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'http' -import type { PreviewData } from 'next/types' -import { FLIGHT_PARAMETERS } from '../client/components/app-router-headers' -import type { - RequestStore, - RequestAsyncStorage, -} from '../client/components/request-async-storage' -import { - ReadonlyHeaders, - ReadonlyRequestCookies, - type RenderOpts, -} from './app-render' - -function headersWithoutFlight(headers: IncomingHttpHeaders) { - const newHeaders = { ...headers } - for (const param of FLIGHT_PARAMETERS) { - delete newHeaders[param.toString().toLowerCase()] - } - return newHeaders -} - -type RunWithRequestAsyncStorageContext = { - req: IncomingMessage - res: ServerResponse - renderOpts?: RenderOpts -} - -export function runWithRequestAsyncStorage( - requestAsyncStorage: RequestAsyncStorage, - { req, res, renderOpts }: RunWithRequestAsyncStorageContext, - callback: () => Promise -): Promise { - const tryGetPreviewData = - process.env.NEXT_RUNTIME === 'edge' - ? () => false - : require('./api-utils/node').tryGetPreviewData - - // Reads of this are cached on the `req` object, so this should resolve - // instantly. There's no need to pass this data down from a previous - // invoke, where we'd have to consider server & serverless. - const previewData: PreviewData = renderOpts - ? // TODO: investigate why previewProps isn't on RenderOpts - tryGetPreviewData(req, res, (renderOpts as any).previewProps) - : false - - let cachedHeadersInstance: ReadonlyHeaders - let cachedCookiesInstance: ReadonlyRequestCookies - - const store: RequestStore = { - get headers() { - if (!cachedHeadersInstance) { - cachedHeadersInstance = new ReadonlyHeaders( - headersWithoutFlight(req.headers) - ) - } - return cachedHeadersInstance - }, - get cookies() { - if (!cachedCookiesInstance) { - cachedCookiesInstance = new ReadonlyRequestCookies({ - headers: { - get: (key) => { - if (key !== 'cookie') { - throw new Error('Only cookie header is supported') - } - return req.headers.cookie - }, - }, - }) - } - return cachedCookiesInstance - }, - previewData, - } - - return requestAsyncStorage.run(store, callback) -} diff --git a/packages/next/src/server/run-with-static-generation-async-storage.ts b/packages/next/src/server/run-with-static-generation-async-storage.ts deleted file mode 100644 index 8ebb5f7561cfa..0000000000000 --- a/packages/next/src/server/run-with-static-generation-async-storage.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { - StaticGenerationStore, - StaticGenerationAsyncStorage, -} from '../client/components/static-generation-async-storage' -import type { RenderOpts } from './app-render' - -type RunWithStaticGenerationAsyncStorageContext = { - pathname: string - renderOpts: RenderOpts -} - -export function runWithStaticGenerationAsyncStorage( - staticGenerationAsyncStorage: StaticGenerationAsyncStorage, - { pathname, renderOpts }: RunWithStaticGenerationAsyncStorageContext, - callback: () => Promise -): Promise { - /** - * Rules of Static & Dynamic HTML: - * - * 1.) We must generate static HTML unless the caller explicitly opts - * in to dynamic HTML support. - * - * 2.) If dynamic HTML support is requested, we must honor that request - * or throw an error. It is the sole responsibility of the caller to - * ensure they aren't e.g. requesting dynamic HTML for an AMP page. - * - * These rules help ensure that other existing features like request caching, - * coalescing, and ISR continue working as intended. - */ - const isStaticGeneration = - renderOpts.supportsDynamicHTML !== true && !renderOpts.isBot - - const store: StaticGenerationStore = { - isStaticGeneration, - pathname, - incrementalCache: renderOpts.incrementalCache, - isRevalidate: renderOpts.isRevalidate, - } - - return staticGenerationAsyncStorage.run(store, callback) -} From 5ce645a47baf4024abacb12301b6bc64bc4980e4 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 28 Feb 2023 18:06:17 -0700 Subject: [PATCH 2/2] fix: change default for edge --- .../webpack/loaders/next-edge-app-route-loader/handle.ts | 2 +- .../server/future/route-handlers/app-route-route-handler.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts b/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts index 3353af0903cd3..830ba823e19b3 100644 --- a/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts +++ b/packages/next/src/build/webpack/loaders/next-edge-app-route-loader/handle.ts @@ -30,7 +30,7 @@ export function getHandle({ page, mod }: any) { extendedReq, extendedRes, // TODO: pass incrementalCache here - { supportsDynamicHTML: false }, + { supportsDynamicHTML: true }, request ) diff --git a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts index ef1abf867b8b1..671cd8c88e4f4 100644 --- a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts @@ -319,7 +319,7 @@ export class AppRouteRouteHandler implements RouteHandler { // We can currently only statically optimize if only GET/HEAD // are used as a Prerender can't be used conditionally based // on the method currently - const nonStaticHandlers = [ + const nonStaticHandlers: ReadonlyArray = [ 'OPTIONS', 'POST', 'PUT', @@ -327,7 +327,7 @@ export class AppRouteRouteHandler implements RouteHandler { 'PATCH', ] const usedNonStaticHandlers = nonStaticHandlers.filter( - (name) => !!(module.handlers as any)[name] + (name) => name in module.handlers ) if (usedNonStaticHandlers.length > 0) {