Skip to content

Commit

Permalink
Fix RenderOpts in next-server (#10776)
Browse files Browse the repository at this point in the history
* Correctly pass preview data

* remove todo

* re-do change

* fix types

* Prevent regression
  • Loading branch information
Timer committed Mar 2, 2020
1 parent 9400942 commit 8f01a4a
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 11 deletions.
10 changes: 10 additions & 0 deletions packages/next/next-server/server/api-utils.ts
Expand Up @@ -260,6 +260,7 @@ const COOKIE_NAME_PRERENDER_BYPASS = `__prerender_bypass`
const COOKIE_NAME_PRERENDER_DATA = `__next_preview_data`

export const SYMBOL_PREVIEW_DATA = Symbol(COOKIE_NAME_PRERENDER_DATA)
const SYMBOL_CLEARED_COOKIES = Symbol(COOKIE_NAME_PRERENDER_BYPASS)

export function tryGetPreviewData(
req: IncomingMessage,
Expand Down Expand Up @@ -405,6 +406,10 @@ function setPreviewData<T>(
}

function clearPreviewData<T>(res: NextApiResponse<T>): NextApiResponse<T> {
if (SYMBOL_CLEARED_COOKIES in res) {
return res
}

const { serialize } = require('cookie') as typeof import('cookie')
const previous = res.getHeader('Set-Cookie')
res.setHeader(`Set-Cookie`, [
Expand Down Expand Up @@ -432,6 +437,11 @@ function clearPreviewData<T>(res: NextApiResponse<T>): NextApiResponse<T> {
path: '/',
}),
])

Object.defineProperty(res, SYMBOL_CLEARED_COOKIES, {
value: true,
enumerable: false,
})
return res
}

Expand Down
25 changes: 15 additions & 10 deletions packages/next/next-server/server/next-server.ts
Expand Up @@ -41,7 +41,7 @@ import pathMatch from './lib/path-match'
import { recursiveReadDirSync } from './lib/recursive-readdir-sync'
import { loadComponents, LoadComponentsReturnType } from './load-components'
import { normalizePagePath } from './normalize-page-path'
import { renderToHTML } from './render'
import { RenderOpts, RenderOptsPartial, renderToHTML } from './render'
import { getPagePath } from './require'
import Router, {
DynamicRoutes,
Expand Down Expand Up @@ -115,6 +115,7 @@ export default class Server {
documentMiddlewareEnabled: boolean
hasCssMode: boolean
dev?: boolean
previewProps: __ApiPreviewProps
}
private compression?: Middleware
private onErrorMiddleware?: ({ err }: { err: Error }) => Promise<void>
Expand Down Expand Up @@ -165,6 +166,7 @@ export default class Server {
staticMarkup,
buildId: this.buildId,
generateEtags,
previewProps: this.getPreviewProps(),
}

// Only the `publicRuntimeConfig` key is exposed to the client side
Expand Down Expand Up @@ -668,13 +670,12 @@ export default class Server {
}
}

const previewProps = this.getPreviewProps()
await apiResolver(
req,
res,
query,
pageModule,
{ ...previewProps },
this.renderOpts.previewProps,
this.onErrorMiddleware
)
return true
Expand Down Expand Up @@ -869,7 +870,7 @@ export default class Server {
res: ServerResponse,
pathname: string,
{ components, query }: FindComponentsResult,
opts: any
opts: RenderOptsPartial
): Promise<string | false | null> {
// we need to ensure the status code if /404 is visited directly
if (pathname === '/404') {
Expand All @@ -890,7 +891,7 @@ export default class Server {
const hasStaticPaths = !!components.getStaticPaths

// Toggle whether or not this is a Data request
const isDataReq = query._nextDataReq
const isDataReq = !!query._nextDataReq
delete query._nextDataReq

// Serverless requests need its URL transformed back into the original
Expand Down Expand Up @@ -958,8 +959,11 @@ export default class Server {
})
}

const previewProps = this.getPreviewProps()
const previewData = tryGetPreviewData(req, res, { ...previewProps })
const previewData = tryGetPreviewData(
req,
res,
this.renderOpts.previewProps
)
const isPreviewMode = previewData !== false

// Compute the SPR cache key
Expand Down Expand Up @@ -1017,15 +1021,16 @@ export default class Server {
pageData = renderResult.renderOpts.pageData
sprRevalidate = renderResult.renderOpts.revalidate
} else {
const renderOpts = {
const renderOpts: RenderOpts = {
...components,
...opts,
}
renderResult = await renderToHTML(req, res, pathname, query, renderOpts)

html = renderResult
pageData = renderOpts.pageData
sprRevalidate = renderOpts.revalidate
// TODO: change this to a different passing mechanism
pageData = (renderOpts as any).pageData
sprRevalidate = (renderOpts as any).revalidate
}

return { html, pageData, sprRevalidate }
Expand Down
5 changes: 4 additions & 1 deletion packages/next/next-server/server/render.tsx
Expand Up @@ -124,7 +124,7 @@ function render(
return { html, head }
}

type RenderOpts = LoadComponentsReturnType & {
export type RenderOptsPartial = {
staticMarkup: boolean
buildId: string
canonicalBase: string
Expand All @@ -147,6 +147,8 @@ type RenderOpts = LoadComponentsReturnType & {
previewProps: __ApiPreviewProps
}

export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial

function renderDocument(
Document: DocumentType,
{
Expand Down Expand Up @@ -517,6 +519,7 @@ export async function renderToHTML(

props.pageProps = data.props
// pass up revalidate and props for export
// TODO: change this to a different passing mechanism
;(renderOpts as any).revalidate = data.revalidate
;(renderOpts as any).pageData = props
}
Expand Down
61 changes: 61 additions & 0 deletions test/integration/prerender-preview/test/index.test.js
Expand Up @@ -8,6 +8,7 @@ import {
findPort,
initNextServerScript,
killApp,
launchApp,
nextBuild,
nextStart,
renderViaHTTP,
Expand Down Expand Up @@ -201,6 +202,66 @@ const startServerlessEmulator = async (dir, port) => {
}

describe('Prerender Preview Mode', () => {
describe('Development Mode', () => {
beforeAll(async () => {
await fs.remove(nextConfigPath)
})

let appPort, app
it('should start development application', async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort)
})

let previewCookieString
it('should enable preview mode', async () => {
const res = await fetchViaHTTP(appPort, '/api/preview', { lets: 'goooo' })
expect(res.status).toBe(200)

const cookies = res.headers
.get('set-cookie')
.split(',')
.map(cookie.parse)

expect(cookies.length).toBe(2)
previewCookieString =
cookie.serialize('__prerender_bypass', cookies[0].__prerender_bypass) +
'; ' +
cookie.serialize('__next_preview_data', cookies[1].__next_preview_data)
})

it('should return cookies to be expired after dev server reboot', async () => {
await killApp(app)
app = await launchApp(appDir, appPort)

const res = await fetchViaHTTP(
appPort,
'/',
{},
{ headers: { Cookie: previewCookieString } }
)
expect(res.status).toBe(200)

const body = await res.text()
// "err":{"name":"TypeError","message":"Cannot read property 'previewModeId' of undefined"
expect(body).not.toContain('err')
expect(body).not.toContain('TypeError')
expect(body).not.toContain('previewModeId')

const cookies = res.headers
.get('set-cookie')
.replace(/(=\w{3}),/g, '$1')
.split(',')
.map(cookie.parse)

expect(cookies.length).toBe(2)
})

afterAll(async () => {
await killApp(app)
})
})

describe('Server Mode', () => {
beforeAll(async () => {
await fs.remove(nextConfigPath)
Expand Down

0 comments on commit 8f01a4a

Please sign in to comment.