Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1602c03
Revert "Remove Old Prerender Implementation (#8218)"
Timer Aug 2, 2019
8f15c42
Add contentHandler for page config
ijjk Jul 15, 2019
c6a70a4
Rename config from contentHandler to re-use
ijjk Jul 15, 2019
e624335
Remove un-needed changes
ijjk Jul 15, 2019
ca7874c
Replace backslashes for manifest
ijjk Jul 15, 2019
5ad4a3d
Update manifest output format
ijjk Jul 16, 2019
8edc0b9
Make prerender: true enable SPR behavior and update
ijjk Jul 25, 2019
a67719d
Fix output path for / prerender file
ijjk Jul 25, 2019
acd4f68
Add dynamic routes to test suite
ijjk Jul 28, 2019
9703dd6
Add generating and previewing of skeletons
ijjk Jul 28, 2019
485921b
remove inline prerender option
ijjk Jul 29, 2019
e9c1b49
update to not replace getInitialProps which allows
ijjk Jul 30, 2019
1de7911
Apply suggestions from code review
ijjk Aug 2, 2019
b0a039e
Remove legacy prerender option
ijjk Aug 2, 2019
3bf1059
Apply suggestions from review
ijjk Aug 3, 2019
56989d2
Merge remote-tracking branch 'upstream/canary' into update/prerender
ijjk Aug 3, 2019
c5517a6
Apply more suggestions from review
ijjk Aug 3, 2019
41ae8e0
Merge branch 'canary' into update/prerender
Timer Aug 4, 2019
76a8c8f
Apply suggestions from code review
ijjk Aug 5, 2019
39c045b
Add handling of error when parsing json
ijjk Aug 5, 2019
d8671fb
Merge remote-tracking branch 'upstream/canary' into update/prerender
ijjk Aug 5, 2019
6ed8182
Merge remote-tracking branch 'upstream/canary' into update/prerender
ijjk Aug 6, 2019
df4b71a
Update handling of moving exported pages
ijjk Aug 6, 2019
3a4b46c
Merge remote-tracking branch 'upstream/canary' into update/prerender
ijjk Aug 6, 2019
9e9afe2
Rename nextPreviewSkeleton to _nextPreviewSkeleton
ijjk Aug 6, 2019
6ce96cc
bump
ijjk Aug 6, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/next-server/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const PHASE_PRODUCTION_SERVER = 'phase-production-server'
export const PHASE_DEVELOPMENT_SERVER = 'phase-development-server'
export const PAGES_MANIFEST = 'pages-manifest.json'
export const BUILD_MANIFEST = 'build-manifest.json'
export const PRERENDER_MANIFEST = 'prerender-manifest.json'
export const REACT_LOADABLE_MANIFEST = 'react-loadable-manifest.json'
export const CHUNK_GRAPH_MANIFEST = 'compilation-modules.json'
export const SERVER_DIRECTORY = 'server'
Expand Down
30 changes: 23 additions & 7 deletions packages/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// tslint:disable:no-console
import { ParsedUrlQuery } from 'querystring'
import { ComponentType } from 'react'
import { parse, UrlObject } from 'url'
import { parse, UrlObject, format } from 'url'

import mitt, { MittEmitter } from '../mitt'
import {
Expand Down Expand Up @@ -579,13 +579,29 @@ export default class Router implements BaseRouter {
}
this.clc = cancel
const { Component: App } = this.components['/_app']
let props

const props = await loadGetInitialProps<AppContextType<Router>>(App, {
AppTree: this._wrapApp(App),
Component,
router: this,
ctx,
})
if ((Component as any).__NEXT_PRERENDER) {
const url = format({
pathname: ctx.asPath,
query: ctx.query,
})
const res = await fetch(url, {
headers: { 'content-type': 'application/json' },
})
props = {
pageProps: res.ok
? await res.json().catch(err => ({ error: err.message }))
: { error: 'failed to load prerender', statusCode: res.status },
}
} else {
props = await loadGetInitialProps<AppContextType<Router>>(App, {
AppTree: this._wrapApp(App),
Component,
router: this,
ctx,
})
}

if (cancel === this.clc) {
this.clc = null
Expand Down
1 change: 1 addition & 0 deletions packages/next-server/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export type NEXT_DATA = {
assetPrefix?: string
runtimeConfig?: { [key: string]: any }
nextExport?: boolean
skeleton?: boolean
dynamicIds?: string[]
err?: Error & { statusCode?: number }
}
Expand Down
49 changes: 35 additions & 14 deletions packages/next-server/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ type RenderOpts = {
assetPrefix?: string
err?: Error | null
nextExport?: boolean
skeleton?: boolean
dev?: boolean
ampMode?: any
ampPath?: string
Expand Down Expand Up @@ -164,6 +165,7 @@ function renderDocument(
assetPrefix,
runtimeConfig,
nextExport,
skeleton,
dynamicImportsIds,
dangerousAsPath,
err,
Expand Down Expand Up @@ -208,6 +210,7 @@ function renderDocument(
assetPrefix: assetPrefix === '' ? undefined : assetPrefix, // send assetPrefix to the client side when configured, otherwise don't sent in the resulting HTML
runtimeConfig, // runtimeConfig if provided, otherwise don't sent in the resulting HTML
nextExport, // If this is a page exported by `next export`
skeleton, // If this is a skeleton page for experimentalPrerender
dynamicIds:
dynamicImportsIds.length === 0 ? undefined : dynamicImportsIds,
err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML
Expand Down Expand Up @@ -255,7 +258,8 @@ export async function renderToHTML(
} = renderOpts

await Loadable.preloadAll() // Make sure all dynamic imports are loaded
let isStaticPage = false
let isStaticPage = pageConfig.experimentalPrerender === true
let isSkeleton = false

if (dev) {
const { isValidElementType } = require('react-is')
Expand Down Expand Up @@ -290,6 +294,11 @@ export async function renderToHTML(
renderOpts.nextExport = true
}
}
// might want to change previewing of skeleton from `?_nextPreviewSkeleton=(truthy)`
isSkeleton =
pageConfig.experimentalPrerender === true && !!query._nextPreviewSkeleton
// remove from query so it doesn't end up in document
delete query._nextPreviewSkeleton

// @ts-ignore url will always be set
const asPath: string = req.url
Expand Down Expand Up @@ -336,25 +345,36 @@ export async function renderToHTML(
)

try {
props = await loadGetInitialProps(App, {
Component,
AppTree: (props: any) => {
const appProps = { ...props, Component, router }
return (
<AppContainer>
<App {...appProps} />
</AppContainer>
)
},
router,
ctx,
})
props = isSkeleton
? { pageProps: {} }
: await loadGetInitialProps(App, {
Component,
AppTree: (props: any) => {
const appProps = { ...props, Component, router }
return (
<AppContainer>
<App {...appProps} />
</AppContainer>
)
},
router,
ctx,
})
} catch (err) {
if (!dev || !err) throw err
ctx.err = err
renderOpts.err = err
}

if (
pageConfig.experimentalPrerender === true &&
req.headers['content-type'] === 'application/json'
) {
res.setHeader('content-type', 'application/json')
res.end(JSON.stringify(props.pageProps || {}))
return null
}

// the response might be finished on the getInitialProps call
if (isResSent(res)) return null

Expand Down Expand Up @@ -499,6 +519,7 @@ export async function renderToHTML(
// update renderOpts so export knows current state
renderOpts.inAmpMode = inAmpMode
renderOpts.hybridAmp = hybridAmp
if (isSkeleton) renderOpts.skeleton = true

let html = renderDocument(Document, {
...renderOpts,
Expand Down
1 change: 1 addition & 0 deletions packages/next-server/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export type PageConfig = {
*/
bodyParser?: { sizeLimit?: number | string } | false
}
experimentalPrerender?: boolean
}
38 changes: 36 additions & 2 deletions packages/next/build/babel/plugins/next-page-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { NodePath } from '@babel/traverse'
import * as BabelTypes from '@babel/types'
import { PageConfig } from 'next-server/types'

const configKeys = new Set(['amp'])
export const dropBundleIdentifier = '__NEXT_DROP_CLIENT_FILE__'

// replace progam path with just a variable with the drop identifier
const configKeys = new Set(['amp', 'experimentalPrerender'])
const pageComponentVar = '__NEXT_COMP'
const prerenderId = '__NEXT_PRERENDER'

// replace program path with just a variable with the drop identifier
function replaceBundle(path: any, t: typeof BabelTypes) {
path.parentPath.replaceWith(
t.program(
Expand All @@ -28,6 +31,7 @@ function replaceBundle(path: any, t: typeof BabelTypes) {
}

interface ConfigState {
isPrerender?: boolean
bundleDropped?: boolean
}

Expand Down Expand Up @@ -84,12 +88,42 @@ export default function nextPageConfig({
state.bundleDropped = true
return
}

state.isPrerender = config.experimentalPrerender === true
},
},
state
)
},
},
ExportDefaultDeclaration(path, state: ConfigState) {
if (!state.isPrerender) {
return
}
const prev = t.cloneDeep(path.node.declaration)

// workaround to allow assigning a ClassDeclaration to a variable
// babel throws error without
if (prev.type.endsWith('Declaration')) {
prev.type = prev.type.replace(/Declaration$/, 'Expression') as any
}

path.insertBefore([
t.variableDeclaration('const', [
t.variableDeclarator(t.identifier(pageComponentVar), prev as any),
]),
t.assignmentExpression(
'=',
t.memberExpression(
t.identifier(pageComponentVar),
t.identifier(prerenderId)
),
t.booleanLiteral(true)
),
])

path.node.declaration = t.identifier(pageComponentVar)
},
},
}
}
81 changes: 53 additions & 28 deletions packages/next/build/flying-shuttle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Sema } from 'async-sema'
import crypto from 'crypto'
import fs from 'fs'
import mkdirpModule from 'mkdirp'
import { CHUNK_GRAPH_MANIFEST } from 'next-server/constants'
import { CHUNK_GRAPH_MANIFEST, PRERENDER_MANIFEST } from 'next-server/constants'
import { EOL } from 'os'
import path from 'path'
import { promisify } from 'util'
Expand All @@ -11,11 +11,16 @@ import { recursiveDelete } from '../lib/recursive-delete'
import { fileExists } from '../lib/file-exists'
import * as Log from './output/log'
import { PageInfo } from './utils'
import { PrerenderRoute } from '.'

const FILE_BUILD_ID = 'HEAD_BUILD_ID'
const FILE_UPDATED_AT = 'UPDATED_AT'
const DIR_FILES_NAME = 'files'
const MAX_SHUTTLES = 3
const SAVED_MANIFESTS = [
'serverless/pages-manifest.json',
'prerender-manifest.json',
]

const mkdirp = promisify(mkdirpModule)
const fsReadFile = promisify(fs.readFile)
Expand Down Expand Up @@ -304,28 +309,50 @@ export class FlyingShuttle {
return unchangedPages
}

mergePagesManifest = async (): Promise<void> => {
const savedPagesManifest = path.join(
this.shuttleDirectory,
DIR_FILES_NAME,
'serverless/pages-manifest.json'
)
if (!(await fileExists(savedPagesManifest))) return
mergeManifests = async (): Promise<void> => {
for (const manifestPath of SAVED_MANIFESTS) {
const savedPagesManifest = path.join(
this.shuttleDirectory,
DIR_FILES_NAME,
manifestPath
)
if (!(await fileExists(savedPagesManifest))) return

const saved = JSON.parse(await fsReadFile(savedPagesManifest, 'utf8'))
const currentPagesManifest = path.join(
this.distDirectory,
'serverless/pages-manifest.json'
)
const current = JSON.parse(await fsReadFile(currentPagesManifest, 'utf8'))
const saved = JSON.parse(await fsReadFile(savedPagesManifest, 'utf8'))
const currentPagesManifest = path.join(this.distDirectory, manifestPath)
const current = JSON.parse(await fsReadFile(currentPagesManifest, 'utf8'))

await fsWriteFile(
currentPagesManifest,
JSON.stringify({
...saved,
...current,
})
)
if (manifestPath === PRERENDER_MANIFEST) {
const prerenderRoutes = new Map<string, PrerenderRoute>()

if (Array.isArray(saved.prerenderRoutes)) {
saved.prerenderRoutes.forEach((route: PrerenderRoute) => {
prerenderRoutes.set(route.path, route)
})
}

if (Array.isArray(current.prerenderRoutes)) {
current.prerenderRoutes.forEach((route: PrerenderRoute) => {
prerenderRoutes.set(route.path, route)
})
}

await fsWriteFile(
currentPagesManifest,
JSON.stringify({
prerenderRoutes: [...prerenderRoutes.values()],
})
)
} else {
await fsWriteFile(
currentPagesManifest,
JSON.stringify({
...saved,
...current,
})
)
}
}
}

restorePage = async (
Expand Down Expand Up @@ -518,14 +545,12 @@ export class FlyingShuttle {
})
)

await fsCopyFile(
path.join(this.distDirectory, 'serverless/pages-manifest.json'),
path.join(
this.shuttleDirectory,
DIR_FILES_NAME,
'serverless/pages-manifest.json'
for (const manifestPath of SAVED_MANIFESTS) {
await fsCopyFile(
path.join(this.distDirectory, manifestPath),
path.join(this.shuttleDirectory, DIR_FILES_NAME, manifestPath)
)
)
}

Log.info(`flying shuttle payload: ${usedChunks.size + 2} files`)
Log.ready('flying shuttle docked')
Expand Down
Loading