Skip to content

Commit

Permalink
Add RenderResult class (#28776)
Browse files Browse the repository at this point in the history
  • Loading branch information
devknoll authored Sep 4, 2021
1 parent 85366a0 commit 7f83e6d
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 122 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IncomingMessage, ServerResponse } from 'http'
import { parse as parseUrl, format as formatUrl, UrlWithParsedQuery } from 'url'
import { DecodeError, isResSent } from '../../../../shared/lib/utils'
import { sendPayload } from '../../../../server/send-payload'
import { sendRenderResult } from '../../../../server/send-payload'
import { getUtils, vercelHeader, ServerlessHandlerCtx } from './utils'

import { renderToHTML } from '../../../../server/render'
Expand All @@ -11,7 +11,7 @@ import { setLazyProp, getCookieParser } from '../../../../server/api-utils'
import { getRedirectStatus } from '../../../../lib/load-custom-routes'
import getRouteNoAssetPath from '../../../../shared/lib/router/utils/get-route-from-asset-path'
import { PERMANENT_REDIRECT_STATUS } from '../../../../shared/lib/constants'
import { resultsToString } from '../../../../server/utils'
import RenderResult from '../../../../server/render-result'

export function getPageHandler(ctx: ServerlessHandlerCtx) {
const {
Expand Down Expand Up @@ -335,22 +335,19 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
defaultLocale: i18n?.defaultLocale,
})
)
const html = result2 ? await resultsToString([result2]) : ''
sendPayload(
sendRenderResult({
req,
res,
html,
'html',
{
generateEtags,
poweredByHeader,
},
{
result: result2 ?? RenderResult.empty,
type: 'html',
generateEtags,
poweredByHeader,
options: {
private: isPreviewMode || page === '/404',
stateful: !!getServerSideProps,
revalidate: renderOpts.revalidate,
}
)
},
})
return null
} else if (renderOpts.isRedirect && !_nextData) {
const redirect = {
Expand All @@ -377,21 +374,21 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
res.end()
return null
} else {
sendPayload(
sendRenderResult({
req,
res,
_nextData ? JSON.stringify(renderOpts.pageData) : result,
_nextData ? 'json' : 'html',
{
generateEtags,
poweredByHeader,
},
{
result: _nextData
? RenderResult.fromStatic(JSON.stringify(renderOpts.pageData))
: result ?? RenderResult.empty,
type: _nextData ? 'json' : 'html',
generateEtags,
poweredByHeader,
options: {
private: isPreviewMode || renderOpts.is404Page,
stateful: !!getServerSideProps,
revalidate: renderOpts.revalidate,
}
)
},
})
return null
}
}
Expand All @@ -403,7 +400,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
}

if (renderMode) return { html: result, renderOpts }
return result ? await resultsToString([result]) : null
return result ? await result.toUnchunkedString() : null
} catch (err) {
if (!parsedUrl!) {
parsedUrl = parseUrl(req.url!, true)
Expand Down Expand Up @@ -465,7 +462,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
err: res.statusCode === 404 ? undefined : err,
})
)
return result2 ? await resultsToString([result2]) : null
return result2 ? result2.toUnchunkedString() : null
}
}

Expand All @@ -475,7 +472,11 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
try {
const html = await renderReqToHTML(req, res)
if (html) {
sendPayload(req, res, html, 'html', {
sendRenderResult({
req,
res,
result: RenderResult.fromStatic(html as any),
type: 'html',
generateEtags,
poweredByHeader,
})
Expand Down
11 changes: 5 additions & 6 deletions packages/next/export/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { extname, join, dirname, sep } from 'path'
import { renderToHTML } from '../server/render'
import { promises } from 'fs'
import AmpHtmlValidator from 'next/dist/compiled/amphtml-validator'
import Observable from 'next/dist/compiled/zen-observable'
import { loadComponents } from '../server/load-components'
import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic'
import { getRouteMatcher } from '../shared/lib/router/utils/route-matcher'
Expand All @@ -19,9 +18,9 @@ import { FontManifest } from '../server/font-utils'
import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path'
import { trace } from '../telemetry/trace'
import { isInAmpMode } from '../shared/lib/amp'
import { resultsToString } from '../server/utils'
import { NextConfigComplete } from '../server/config-shared'
import { setHttpAgentOptions } from '../server/config'
import RenderResult from '../server/render-result'

const envConfig = require('../shared/lib/runtime-config')

Expand Down Expand Up @@ -275,7 +274,7 @@ export default async function exportPage({

// if it was auto-exported the HTML is loaded here
if (typeof mod === 'string') {
renderResult = Observable.of(mod)
renderResult = RenderResult.fromStatic(mod)
queryWithAutoExportWarn()
} else {
// for non-dynamic SSG pages we should have already
Expand Down Expand Up @@ -353,7 +352,7 @@ export default async function exportPage({
}

if (typeof components.Component === 'string') {
renderResult = Observable.of(components.Component)
renderResult = RenderResult.fromStatic(components.Component)
queryWithAutoExportWarn()
} else {
/**
Expand Down Expand Up @@ -418,7 +417,7 @@ export default async function exportPage({
}
}

const html = renderResult ? await resultsToString([renderResult]) : ''
const html = renderResult ? await renderResult.toUnchunkedString() : ''
if (inAmpMode && !curRenderOpts.ampSkipValidation) {
if (!results.ssgNotFound) {
await validateAmp(html, path, curRenderOpts.ampValidatorPath)
Expand Down Expand Up @@ -461,7 +460,7 @@ export default async function exportPage({
}

const ampHtml = ampRenderResult
? await resultsToString([ampRenderResult])
? await ampRenderResult.toUnchunkedString()
: ''
if (!curRenderOpts.ampSkipValidation) {
await validateAmp(ampHtml, page + '?amp=1')
Expand Down
27 changes: 15 additions & 12 deletions packages/next/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
ParsedUrlQuery,
} from 'querystring'
import { format as formatUrl, parse as parseUrl, UrlWithParsedQuery } from 'url'
import Observable from 'next/dist/compiled/zen-observable'
import { PrerenderManifest } from '../build'
import {
getRedirectStatus,
Expand Down Expand Up @@ -77,7 +76,8 @@ import { sendRenderResult, setRevalidateHeaders } from './send-payload'
import { serveStatic } from './serve-static'
import { IncrementalCache } from './incremental-cache'
import { execOnce } from '../shared/lib/utils'
import { isBlockedPage, RenderResult, resultsToString } from './utils'
import { isBlockedPage } from './utils'
import RenderResult from './render-result'
import { loadEnvConfig } from '@next/env'
import './node-polyfill-fetch'
import { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'
Expand Down Expand Up @@ -1274,9 +1274,7 @@ export default class Server {
return sendRenderResult({
req,
res,
resultOrPayload: requireStaticHTML
? await resultsToString([body])
: body,
result: body,
type,
generateEtags,
poweredByHeader,
Expand Down Expand Up @@ -1304,7 +1302,12 @@ export default class Server {
if (payload === null) {
return null
}
return resultsToString([payload.body])
if (payload.body.isDynamic()) {
throw new Error(
'invariant: expected a static result. This is a bug in Next.js'
)
}
return payload.body.toUnchunkedString()
}

public async render(
Expand Down Expand Up @@ -1478,8 +1481,8 @@ export default class Server {
if (typeof components.Component === 'string') {
return {
type: 'html',
// TODO: Static pages should be written as chunks
body: Observable.of(components.Component),
// TODO: Static pages should be serialized as RenderResult
body: RenderResult.fromStatic(components.Component),
}
}

Expand Down Expand Up @@ -1758,7 +1761,7 @@ export default class Server {
return {
value: {
kind: 'PAGE',
html: Observable.of(html),
html: RenderResult.fromStatic(html),
pageData: {},
},
}
Expand Down Expand Up @@ -1837,7 +1840,7 @@ export default class Server {
if (isDataReq) {
return {
type: 'json',
body: Observable.of(JSON.stringify(cachedData.props)),
body: RenderResult.fromStatic(JSON.stringify(cachedData.props)),
revalidateOptions,
}
} else {
Expand All @@ -1848,7 +1851,7 @@ export default class Server {
return {
type: isDataReq ? 'json' : 'html',
body: isDataReq
? Observable.of(JSON.stringify(cachedData.pageData))
? RenderResult.fromStatic(JSON.stringify(cachedData.pageData))
: cachedData.html,
revalidateOptions,
}
Expand Down Expand Up @@ -2088,7 +2091,7 @@ export default class Server {
}
return {
type: 'html',
body: Observable.of('Internal Server Error'),
body: RenderResult.fromStatic('Internal Server Error'),
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions packages/next/server/render-result.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Observable from 'next/dist/compiled/zen-observable'

export default class RenderResult {
_response: string | Observable<string>
_dynamic: boolean

constructor(response: string | Observable<string>, dynamic: boolean) {
this._response = response
this._dynamic = dynamic
}

async toUnchunkedString(): Promise<string> {
if (typeof this._response === 'string') {
return this._response
}
const chunks: string[] = []
await this._response.forEach((chunk) => chunks.push(chunk))
return chunks.join('')
}

forEach(fn: (chunk: string) => void): Promise<void> {
if (typeof this._response === 'string') {
const value = this._response
return new Promise((resolve) => {
fn(value)
resolve()
})
}
return this._response.forEach(fn)
}

isDynamic(): boolean {
return this._dynamic
}

static fromStatic(value: string): RenderResult {
return new RenderResult(value, false)
}

static empty = RenderResult.fromStatic('')
}
Loading

0 comments on commit 7f83e6d

Please sign in to comment.