Skip to content

Commit

Permalink
fix: conditional cookies in draft mode (#50660)
Browse files Browse the repository at this point in the history
  • Loading branch information
styfle committed Jun 2, 2023
1 parent e657741 commit d13fe04
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 7 deletions.
3 changes: 2 additions & 1 deletion packages/next/src/client/components/draft-mode.ts
@@ -1,4 +1,5 @@
import { DraftModeProvider } from '../../server/async-storage/draft-mode-provider'
import type { DraftModeProvider } from '../../server/async-storage/draft-mode-provider'

import { staticGenerationBailout } from './static-generation-bailout'

export class DraftMode {
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/app-render/types.ts
Expand Up @@ -132,6 +132,7 @@ export type RenderOptsPartial = {
nextConfigOutput?: 'standalone' | 'export'
appDirDevErrorLogger?: (err: any) => Promise<void>
originalPathname?: string
isDraftMode?: boolean
deploymentId?: string
}

Expand Down
Expand Up @@ -14,6 +14,7 @@ export type StaticGenerationContext = {
isBot?: boolean
nextExport?: boolean
fetchCache?: StaticGenerationStore['fetchCache']
isDraftMode?: boolean

/**
* A hack around accessing the store value outside the context of the
Expand Down Expand Up @@ -46,11 +47,15 @@ export const StaticGenerationAsyncStorageWrapper: AsyncStorageWrapper<
* 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.
*
* 3.) If the request is in draft mode, we must generate dynamic HTML.
*
* These rules help ensure that other existing features like request caching,
* coalescing, and ISR continue working as intended.
*/
const isStaticGeneration =
!renderOpts.supportsDynamicHTML && !renderOpts.isBot
!renderOpts.supportsDynamicHTML &&
!renderOpts.isBot &&
!renderOpts.isDraftMode

const store: StaticGenerationStore = {
isStaticGeneration,
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/base-server.ts
Expand Up @@ -1744,6 +1744,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {

supportsDynamicHTML,
isOnDemandRevalidate,
isDraftMode: isPreviewMode,
}

const renderResult = await this.renderHTML(
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/render.tsx
Expand Up @@ -268,6 +268,7 @@ export type RenderOptsPartial = {
largePageDataBytes?: number
isOnDemandRevalidate?: boolean
strictNextHead: boolean
isDraftMode?: boolean
deploymentId?: string
}

Expand Down
25 changes: 25 additions & 0 deletions test/e2e/app-dir/draft-mode/app/with-cookies/page.tsx
@@ -0,0 +1,25 @@
import React from 'react'
import { cookies, draftMode } from 'next/headers'

export default function Page() {
const { isEnabled } = draftMode()
let data: string | undefined
if (isEnabled) {
data = cookies().get('data')?.value
}

return (
<>
<h1>Draft Mode with dynamic cookie</h1>
<p>
Random: <em id="rand">{Math.random()}</em>
</p>
<p>
State: <strong id="mode">{isEnabled ? 'ENABLED' : 'DISABLED'}</strong>
</p>
<p>
Data: <em id="data">{data}</em>
</p>
</>
)
}
35 changes: 30 additions & 5 deletions test/e2e/app-dir/draft-mode/draft-mode-node.test.ts
Expand Up @@ -6,21 +6,38 @@ createNextDescribe(
files: __dirname,
},
({ next, isNextDev }) => {
let initialRand = 'unintialized'
let origRandHome = 'unintialized'
let origRandWithCookies = 'unintialized'
let Cookie = ''

it('should use initial rand when draft mode is disabled', async () => {
it('should use initial rand when draft mode is disabled on /index', async () => {
const $ = await next.render$('/')
expect($('#mode').text()).toBe('DISABLED')
expect($('#rand').text()).toBeDefined()
initialRand = $('#rand').text()
origRandHome = $('#rand').text()
})

it('should use initial rand when draft mode is disabled on /with-cookies', async () => {
const $ = await next.render$('/with-cookies')
expect($('#mode').text()).toBe('DISABLED')
expect($('#rand').text()).toBeDefined()
expect($('#data').text()).toBe('')
origRandWithCookies = $('#rand').text()
})

if (!isNextDev) {
it('should not generate rand when draft mode disabled during next start', async () => {
const $ = await next.render$('/')
expect($('#mode').text()).toBe('DISABLED')
expect($('#rand').text()).toBe(initialRand)
expect($('#rand').text()).toBe(origRandHome)
})

it('should not read other cookies when draft mode disabled during next start', async () => {
const opts = { headers: { Cookie: `data=cool` } }
const $ = await next.render$('/with-cookies', {}, opts)
expect($('#mode').text()).toBe('DISABLED')
expect($('#rand').text()).toBe(origRandWithCookies)
expect($('#data').text()).toBe('')
})
}

Expand Down Expand Up @@ -51,7 +68,15 @@ createNextDescribe(
const opts = { headers: { Cookie } }
const $ = await next.render$('/', {}, opts)
expect($('#mode').text()).toBe('ENABLED')
expect($('#rand').text()).not.toBe(initialRand)
expect($('#rand').text()).not.toBe(origRandHome)
})

it('should read other cookies when draft mode enabled', async () => {
const opts = { headers: { Cookie: `${Cookie};data=cool` } }
const $ = await next.render$('/with-cookies', {}, opts)
expect($('#mode').text()).toBe('ENABLED')
expect($('#rand').text()).not.toBe(origRandWithCookies)
expect($('#data').text()).toBe('cool')
})

it('should be enabled from api route handler when draft mode enabled', async () => {
Expand Down

0 comments on commit d13fe04

Please sign in to comment.