From 816d60582180c8e5d4e651b9ab4ee0758109977f Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 2 May 2023 11:00:14 -0400 Subject: [PATCH 1/5] chore: rename draft mode enabled to isEnabled --- packages/next/src/client/components/headers.ts | 4 ++-- packages/next/src/server/async-storage/draft-mode.ts | 4 ++-- packages/next/types/index.d.ts | 2 +- test/e2e/app-dir/draft-mode/app/page.tsx | 4 ++-- test/e2e/app-dir/draft-mode/app/state/route.ts | 4 ++-- test/e2e/app-dir/draft-mode/app/with-edge/page.tsx | 4 ++-- test/e2e/app-dir/draft-mode/app/with-edge/state/route.ts | 4 ++-- test/e2e/app-dir/hooks/app/hooks/use-draft-mode/page.js | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/next/src/client/components/headers.ts b/packages/next/src/client/components/headers.ts index 388d768d2067..48bde0d4907c 100644 --- a/packages/next/src/client/components/headers.ts +++ b/packages/next/src/client/components/headers.ts @@ -57,8 +57,8 @@ export function draftMode(): DraftMode { ) } return { - get enabled() { - return requestStore.draftMode.enabled + get isEnabled() { + return requestStore.draftMode.isEnabled }, enable() { if (staticGenerationBailout('draftMode().enable()')) { diff --git a/packages/next/src/server/async-storage/draft-mode.ts b/packages/next/src/server/async-storage/draft-mode.ts index e3f3f82b8fdc..edf451338740 100644 --- a/packages/next/src/server/async-storage/draft-mode.ts +++ b/packages/next/src/server/async-storage/draft-mode.ts @@ -11,7 +11,7 @@ import { } from '../api-utils' export class DraftMode { - public readonly enabled: boolean + public readonly isEnabled: boolean private readonly previewModeId: string | undefined @@ -29,7 +29,7 @@ export class DraftMode { const cookieValue = this.cookies.get(COOKIE_NAME_PRERENDER_BYPASS)?.value - this.enabled = Boolean( + this.isEnabled = Boolean( !isOnDemandRevalidate && cookieValue && previewProps && diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index 9942b6c11842..152e85800abc 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -146,7 +146,7 @@ export type DraftMode = { * Get the current value of Draft Mode. * True when enabled, false when disabled. */ - enabled: boolean + isEnabled: boolean /** * Set the value of Draft Mode to true. */ diff --git a/test/e2e/app-dir/draft-mode/app/page.tsx b/test/e2e/app-dir/draft-mode/app/page.tsx index aa408718d721..65b59b64e32a 100644 --- a/test/e2e/app-dir/draft-mode/app/page.tsx +++ b/test/e2e/app-dir/draft-mode/app/page.tsx @@ -2,7 +2,7 @@ import React from 'react' import { draftMode } from 'next/headers' export default function Page() { - const { enabled } = draftMode() + const { isEnabled } = draftMode() return ( <> @@ -11,7 +11,7 @@ export default function Page() { Random: {Math.random()}

- State: {enabled ? 'ENABLED' : 'DISABLED'} + State: {isEnabled ? 'ENABLED' : 'DISABLED'}

) diff --git a/test/e2e/app-dir/draft-mode/app/state/route.ts b/test/e2e/app-dir/draft-mode/app/state/route.ts index c4081345262d..c5568ed06b89 100644 --- a/test/e2e/app-dir/draft-mode/app/state/route.ts +++ b/test/e2e/app-dir/draft-mode/app/state/route.ts @@ -1,6 +1,6 @@ import { draftMode } from 'next/headers' export function GET() { - const { enabled } = draftMode() - return new Response(enabled ? 'ENABLED' : 'DISABLED') + const { isEnabled } = draftMode() + return new Response(isEnabled ? 'ENABLED' : 'DISABLED') } diff --git a/test/e2e/app-dir/draft-mode/app/with-edge/page.tsx b/test/e2e/app-dir/draft-mode/app/with-edge/page.tsx index 84b5fb6f099d..bdcd910fa793 100644 --- a/test/e2e/app-dir/draft-mode/app/with-edge/page.tsx +++ b/test/e2e/app-dir/draft-mode/app/with-edge/page.tsx @@ -4,7 +4,7 @@ import { draftMode } from 'next/headers' export const runtime = 'experimental-edge' export default function Page() { - const { enabled } = draftMode() + const { isEnabled } = draftMode() return ( <> @@ -13,7 +13,7 @@ export default function Page() { Random: {Math.random()}

- State: {enabled ? 'ENABLED' : 'DISABLED'} + State: {isEnabled ? 'ENABLED' : 'DISABLED'}

) diff --git a/test/e2e/app-dir/draft-mode/app/with-edge/state/route.ts b/test/e2e/app-dir/draft-mode/app/with-edge/state/route.ts index 50426a2ec42c..04083518e8b6 100644 --- a/test/e2e/app-dir/draft-mode/app/with-edge/state/route.ts +++ b/test/e2e/app-dir/draft-mode/app/with-edge/state/route.ts @@ -3,6 +3,6 @@ import { draftMode } from 'next/headers' export const runtime = 'edge' export function GET() { - const { enabled } = draftMode() - return new Response(enabled ? 'ENABLED' : 'DISABLED') + const { isEnabled } = draftMode() + return new Response(isEnabled ? 'ENABLED' : 'DISABLED') } diff --git a/test/e2e/app-dir/hooks/app/hooks/use-draft-mode/page.js b/test/e2e/app-dir/hooks/app/hooks/use-draft-mode/page.js index 141d1afc7320..bf91e2ee399f 100644 --- a/test/e2e/app-dir/hooks/app/hooks/use-draft-mode/page.js +++ b/test/e2e/app-dir/hooks/app/hooks/use-draft-mode/page.js @@ -1,7 +1,7 @@ import { draftMode } from 'next/headers' export default function Page() { - const { enabled } = draftMode() + const { isEnabled } = draftMode() return ( <> @@ -9,7 +9,7 @@ export default function Page() {

Rand: {Math.random()}

-

{enabled ? 'ENABLED' : 'DISABLED'}

+

{isEnabled ? 'ENABLED' : 'DISABLED'}

) } From 8ac63c843df8b70a01ddbb183be2b786e9109e91 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 2 May 2023 11:12:22 -0400 Subject: [PATCH 2/5] Fix a test --- test/e2e/app-dir/app-static/app-static.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index 4496c3e3c55d..035028afb954 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -1327,7 +1327,7 @@ createNextDescribe( .elementByCss('#draft-mode') .text() - expect(content).toBe('{"result":{"enabled":false}}') + expect(content).toBe('{"result":{"isEnabled":false}}') }) it('should force SSR correctly for headers usage', async () => { From e93527d5512a5b4b3385b6834a78344b3ded8d9f Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 2 May 2023 13:27:01 -0400 Subject: [PATCH 3/5] Use a class instead --- .../next/src/client/components/draft-mode.ts | 24 +++++++++++++++++++ .../next/src/client/components/headers.ts | 22 +++-------------- .../components/request-async-storage.ts | 4 ++-- .../{draft-mode.ts => draft-mode-provider.ts} | 24 ++++++++++--------- .../request-async-storage-wrapper.ts | 6 ++--- packages/next/types/index.d.ts | 16 ------------- 6 files changed, 45 insertions(+), 51 deletions(-) create mode 100644 packages/next/src/client/components/draft-mode.ts rename packages/next/src/server/async-storage/{draft-mode.ts => draft-mode-provider.ts} (79%) diff --git a/packages/next/src/client/components/draft-mode.ts b/packages/next/src/client/components/draft-mode.ts new file mode 100644 index 000000000000..f0de773578ce --- /dev/null +++ b/packages/next/src/client/components/draft-mode.ts @@ -0,0 +1,24 @@ +import { RequestStore } from './request-async-storage' +import { staticGenerationBailout } from './static-generation-bailout' + +export class DraftMode { + #requestStore: RequestStore + constructor(requestStore: RequestStore) { + this.#requestStore = requestStore + } + get isEnabled() { + return this.#requestStore.draftMode.isEnabled + } + public enable() { + if (staticGenerationBailout('draftMode().enable()')) { + return + } + return this.#requestStore.draftMode.enable() + } + public disable() { + if (staticGenerationBailout('draftMode().disable()')) { + return + } + return this.#requestStore.draftMode.disable() + } +} diff --git a/packages/next/src/client/components/headers.ts b/packages/next/src/client/components/headers.ts index 48bde0d4907c..650849d95d69 100644 --- a/packages/next/src/client/components/headers.ts +++ b/packages/next/src/client/components/headers.ts @@ -7,7 +7,7 @@ import { RequestCookies } from '../../server/web/spec-extension/cookies' import { requestAsyncStorage } from './request-async-storage' import { actionAsyncStorage } from './action-async-storage' import { staticGenerationBailout } from './static-generation-bailout' -import { DraftMode } from '../../../types' +import { DraftMode } from './draft-mode' export function headers() { if (staticGenerationBailout('headers')) { @@ -49,28 +49,12 @@ export function cookies() { return requestStore.cookies } -export function draftMode(): DraftMode { +export function draftMode() { const requestStore = requestAsyncStorage.getStore() if (!requestStore) { throw new Error( `Invariant: Method expects to have requestAsyncStorage, none available` ) } - return { - get isEnabled() { - return requestStore.draftMode.isEnabled - }, - enable() { - if (staticGenerationBailout('draftMode().enable()')) { - return - } - return requestStore.draftMode.enable() - }, - disable() { - if (staticGenerationBailout('draftMode().disable()')) { - return - } - return requestStore.draftMode.disable() - }, - } + return new DraftMode(requestStore) } diff --git a/packages/next/src/client/components/request-async-storage.ts b/packages/next/src/client/components/request-async-storage.ts index d2879e12c6b0..a8a71c790662 100644 --- a/packages/next/src/client/components/request-async-storage.ts +++ b/packages/next/src/client/components/request-async-storage.ts @@ -1,6 +1,6 @@ import type { AsyncLocalStorage } from 'async_hooks' +import type { DraftModeProvider } from '../../server/async-storage/draft-mode-provider' import type { ResponseCookies } from '../../server/web/spec-extension/cookies' -import type { DraftMode } from '../../../types' import type { ReadonlyHeaders } from '../../server/web/spec-extension/adapters/headers' import type { ReadonlyRequestCookies } from '../../server/web/spec-extension/adapters/request-cookies' @@ -10,7 +10,7 @@ export interface RequestStore { readonly headers: ReadonlyHeaders readonly cookies: ReadonlyRequestCookies readonly mutableCookies: ResponseCookies - readonly draftMode: DraftMode + readonly draftMode: DraftModeProvider } export type RequestAsyncStorage = AsyncLocalStorage diff --git a/packages/next/src/server/async-storage/draft-mode.ts b/packages/next/src/server/async-storage/draft-mode-provider.ts similarity index 79% rename from packages/next/src/server/async-storage/draft-mode.ts rename to packages/next/src/server/async-storage/draft-mode-provider.ts index edf451338740..eb1d343cd8ab 100644 --- a/packages/next/src/server/async-storage/draft-mode.ts +++ b/packages/next/src/server/async-storage/draft-mode-provider.ts @@ -10,16 +10,17 @@ import { __ApiPreviewProps, } from '../api-utils' -export class DraftMode { +export class DraftModeProvider { public readonly isEnabled: boolean - private readonly previewModeId: string | undefined + #previewModeId: string | undefined + #mutableCookies: ResponseCookies constructor( previewProps: __ApiPreviewProps | undefined, req: IncomingMessage | BaseNextRequest | NextRequest, - private readonly cookies: ReadonlyRequestCookies, - private readonly mutableCookies: ResponseCookies + cookies: ReadonlyRequestCookies, + mutableCookies: ResponseCookies ) { // The logic for draftMode() is very similar to tryGetPreviewData() // but Draft Mode does not have any data associated with it. @@ -27,7 +28,7 @@ export class DraftMode { previewProps && checkIsOnDemandRevalidate(req, previewProps).isOnDemandRevalidate - const cookieValue = this.cookies.get(COOKIE_NAME_PRERENDER_BYPASS)?.value + const cookieValue = cookies.get(COOKIE_NAME_PRERENDER_BYPASS)?.value this.isEnabled = Boolean( !isOnDemandRevalidate && @@ -36,19 +37,20 @@ export class DraftMode { cookieValue === previewProps.previewModeId ) - this.previewModeId = previewProps?.previewModeId + this.#previewModeId = previewProps?.previewModeId + this.#mutableCookies = mutableCookies } enable() { - if (!this.previewModeId) { + if (!this.#previewModeId) { throw new Error( - 'Invariant: previewProps missing previewModeId this should not be hit' + 'Invariant: previewProps missing previewModeId this should never happen' ) } - this.mutableCookies.set({ + this.#mutableCookies.set({ name: COOKIE_NAME_PRERENDER_BYPASS, - value: this.previewModeId, + value: this.#previewModeId, httpOnly: true, sameSite: process.env.NODE_ENV !== 'development' ? 'none' : 'lax', secure: process.env.NODE_ENV !== 'development', @@ -60,7 +62,7 @@ export class DraftMode { // To delete a cookie, set `expires` to a date in the past: // https://tools.ietf.org/html/rfc6265#section-4.1.1 // `Max-Age: 0` is not valid, thus ignored, and the cookie is persisted. - this.mutableCookies.set({ + this.#mutableCookies.set({ name: COOKIE_NAME_PRERENDER_BYPASS, value: '', httpOnly: true, diff --git a/packages/next/src/server/async-storage/request-async-storage-wrapper.ts b/packages/next/src/server/async-storage/request-async-storage-wrapper.ts index 860de534258a..4d91f7f77806 100644 --- a/packages/next/src/server/async-storage/request-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/request-async-storage-wrapper.ts @@ -18,7 +18,7 @@ import { } from '../web/spec-extension/adapters/request-cookies' import { RequestCookies, ResponseCookies } from '../web/spec-extension/cookies' import { __ApiPreviewProps } from '../api-utils' -import { DraftMode } from './draft-mode' +import { DraftModeProvider } from './draft-mode-provider' function getHeaders(headers: Headers | IncomingHttpHeaders): ReadonlyHeaders { const cleaned = HeadersAdapter.from(headers) @@ -79,7 +79,7 @@ export const RequestAsyncStorageWrapper: AsyncStorageWrapper< headers?: ReadonlyHeaders cookies?: ReadonlyRequestCookies mutableCookies?: ResponseCookies - draftMode?: DraftMode + draftMode?: DraftModeProvider } = {} const store: RequestStore = { @@ -109,7 +109,7 @@ export const RequestAsyncStorageWrapper: AsyncStorageWrapper< }, get draftMode() { if (!cache.draftMode) { - cache.draftMode = new DraftMode( + cache.draftMode = new DraftModeProvider( previewProps, req, this.cookies, diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index 152e85800abc..297e169cd2b7 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -141,22 +141,6 @@ export { export type PreviewData = string | false | object | undefined -export type DraftMode = { - /** - * Get the current value of Draft Mode. - * True when enabled, false when disabled. - */ - isEnabled: boolean - /** - * Set the value of Draft Mode to true. - */ - enable: () => void - /** - * Set the value of Draft Mode to false. - */ - disable: () => void -} - /** * Context object passed into `getStaticProps`. * @link https://nextjs.org/docs/api-reference/data-fetching/get-static-props#context-parameter From 0311f217633fa27f09c590fa4c21e93d5d856dd1 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 2 May 2023 13:57:24 -0400 Subject: [PATCH 4/5] Fix test --- test/e2e/app-dir/app-static/app-static.test.ts | 2 +- .../app-static/app/ssg-draft-mode/[[...route]]/page.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index 9b55397fb871..a0e1f8a6759c 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -1356,7 +1356,7 @@ createNextDescribe( .elementByCss('#draft-mode') .text() - expect(content).toBe('{"result":{"isEnabled":false}}') + expect(content).toBe('{"isEnabled":false}') }) it('should force SSR correctly for headers usage', async () => { diff --git a/test/e2e/app-dir/app-static/app/ssg-draft-mode/[[...route]]/page.js b/test/e2e/app-dir/app-static/app/ssg-draft-mode/[[...route]]/page.js index 13a7ce2660f6..ad91464d34d6 100644 --- a/test/e2e/app-dir/app-static/app/ssg-draft-mode/[[...route]]/page.js +++ b/test/e2e/app-dir/app-static/app/ssg-draft-mode/[[...route]]/page.js @@ -1,11 +1,11 @@ import { draftMode } from 'next/headers' export default function Page() { - const result = draftMode() + const { isEnabled } = draftMode() return (
-
{JSON.stringify({ result })}
+
{JSON.stringify({ isEnabled })}
) } From 65f4000ee207f0b4933897621efcf0083bd7897b Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 2 May 2023 14:52:48 -0400 Subject: [PATCH 5/5] Swtich from js private to ts private --- .../next/src/client/components/draft-mode.ts | 18 +++++++++------ .../next/src/client/components/headers.ts | 2 +- .../async-storage/draft-mode-provider.ts | 23 ++++++++++++------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/next/src/client/components/draft-mode.ts b/packages/next/src/client/components/draft-mode.ts index f0de773578ce..b1af9a4c2d7b 100644 --- a/packages/next/src/client/components/draft-mode.ts +++ b/packages/next/src/client/components/draft-mode.ts @@ -1,24 +1,28 @@ -import { RequestStore } from './request-async-storage' +import { DraftModeProvider } from '../../server/async-storage/draft-mode-provider' import { staticGenerationBailout } from './static-generation-bailout' export class DraftMode { - #requestStore: RequestStore - constructor(requestStore: RequestStore) { - this.#requestStore = requestStore + /** + * @internal - this declaration is stripped via `tsc --stripInternal` + */ + private readonly _provider: DraftModeProvider + + constructor(provider: DraftModeProvider) { + this._provider = provider } get isEnabled() { - return this.#requestStore.draftMode.isEnabled + return this._provider.isEnabled } public enable() { if (staticGenerationBailout('draftMode().enable()')) { return } - return this.#requestStore.draftMode.enable() + return this._provider.enable() } public disable() { if (staticGenerationBailout('draftMode().disable()')) { return } - return this.#requestStore.draftMode.disable() + return this._provider.disable() } } diff --git a/packages/next/src/client/components/headers.ts b/packages/next/src/client/components/headers.ts index 650849d95d69..2b239c9b8763 100644 --- a/packages/next/src/client/components/headers.ts +++ b/packages/next/src/client/components/headers.ts @@ -56,5 +56,5 @@ export function draftMode() { `Invariant: Method expects to have requestAsyncStorage, none available` ) } - return new DraftMode(requestStore) + return new DraftMode(requestStore.draftMode) } diff --git a/packages/next/src/server/async-storage/draft-mode-provider.ts b/packages/next/src/server/async-storage/draft-mode-provider.ts index eb1d343cd8ab..06138db7dd16 100644 --- a/packages/next/src/server/async-storage/draft-mode-provider.ts +++ b/packages/next/src/server/async-storage/draft-mode-provider.ts @@ -13,8 +13,15 @@ import { export class DraftModeProvider { public readonly isEnabled: boolean - #previewModeId: string | undefined - #mutableCookies: ResponseCookies + /** + * @internal - this declaration is stripped via `tsc --stripInternal` + */ + private readonly _previewModeId: string | undefined + + /** + * @internal - this declaration is stripped via `tsc --stripInternal` + */ + private readonly _mutableCookies: ResponseCookies constructor( previewProps: __ApiPreviewProps | undefined, @@ -37,20 +44,20 @@ export class DraftModeProvider { cookieValue === previewProps.previewModeId ) - this.#previewModeId = previewProps?.previewModeId - this.#mutableCookies = mutableCookies + this._previewModeId = previewProps?.previewModeId + this._mutableCookies = mutableCookies } enable() { - if (!this.#previewModeId) { + if (!this._previewModeId) { throw new Error( 'Invariant: previewProps missing previewModeId this should never happen' ) } - this.#mutableCookies.set({ + this._mutableCookies.set({ name: COOKIE_NAME_PRERENDER_BYPASS, - value: this.#previewModeId, + value: this._previewModeId, httpOnly: true, sameSite: process.env.NODE_ENV !== 'development' ? 'none' : 'lax', secure: process.env.NODE_ENV !== 'development', @@ -62,7 +69,7 @@ export class DraftModeProvider { // To delete a cookie, set `expires` to a date in the past: // https://tools.ietf.org/html/rfc6265#section-4.1.1 // `Max-Age: 0` is not valid, thus ignored, and the cookie is persisted. - this.#mutableCookies.set({ + this._mutableCookies.set({ name: COOKIE_NAME_PRERENDER_BYPASS, value: '', httpOnly: true,