Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSG Preview Mode #10459

Merged
merged 50 commits into from Feb 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
2da8ae5
checkpoint: api impl
Timer Feb 8, 2020
d69d764
Add support for tryGetPreviewData
Timer Feb 8, 2020
c9c2bd5
snapshot: server(less) support
Timer Feb 8, 2020
db1cc37
Add X-Prerender-Bypass-Mode header support
Timer Feb 8, 2020
030d3c6
Pass preview data to getStaticProps call
Timer Feb 8, 2020
7c30d49
add TODO
Timer Feb 8, 2020
c747bb0
setPreviewData
Timer Feb 10, 2020
f0c78f3
100k iterations
Timer Feb 10, 2020
ae0a187
Handle jwt error
Timer Feb 10, 2020
4742eed
Write out preview values
Timer Feb 10, 2020
f408f9b
forgot file
Timer Feb 10, 2020
2b4b81d
set preview props
Timer Feb 10, 2020
7209c8c
Send preview props
Timer Feb 10, 2020
f013553
add preview props
Timer Feb 10, 2020
198db73
Pass around more data
Timer Feb 10, 2020
4aa8031
update yarn lock
Timer Feb 10, 2020
f25da29
Fail on Invalid Prerender Manifest
Timer Feb 10, 2020
4ff60c7
Make Missing Prerender Manifest Fatal
Timer Feb 10, 2020
974d6fd
Merge branch 'make-fatal' into ssg-preview-mode
Timer Feb 10, 2020
ecc173d
fix ts errors
Timer Feb 10, 2020
e70c14f
fix test
Timer Feb 10, 2020
9da537f
Merge branch 'make-fatal' into ssg-preview-mode
Timer Feb 10, 2020
933ca9a
Merge remote-tracking branch 'upstream/canary' into ssg-preview-mode
Timer Feb 10, 2020
fe45201
Fix setting cookies + maxage
Timer Feb 11, 2020
c8d7863
Secure is not needed as we encrypt necessary data
Timer Feb 11, 2020
eb0f26e
Set on domain root
Timer Feb 11, 2020
1257048
Set cookie max ages
Timer Feb 11, 2020
436d824
Render a fallback on-demand for non-dynamic pages
Timer Feb 11, 2020
70daa78
Test preview mode
Timer Feb 11, 2020
c23824c
Merge remote-tracking branch 'upstream/canary' into ssg-preview-mode
Timer Feb 11, 2020
21192dc
remove old build
Timer Feb 11, 2020
c804c50
remove snapshots
Timer Feb 11, 2020
aba14d9
Add serverless tests
Timer Feb 11, 2020
7c38381
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
653749b
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
4af9b63
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
5deaccf
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
baa0cdb
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
a4845e7
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
83c9445
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
795f67d
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
2dd57db
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
3ba7fb9
use afterAll
Timer Feb 11, 2020
da4450f
Merge branch 'ssg-preview-mode' of github.com:Timer/next.js into ssg-…
Timer Feb 11, 2020
6820807
Merge branch 'canary' into ssg-preview-mode
Timer Feb 11, 2020
b94b9ab
Remove object assigns
Timer Feb 11, 2020
1fa3281
Merge branch 'canary' into ssg-preview-mode
Timer Feb 12, 2020
be60da8
fix cookie spread
Timer Feb 12, 2020
03c0213
Merge branch 'ssg-preview-mode' of github.com:Timer/next.js into ssg-…
Timer Feb 12, 2020
76590a7
add comment
Timer Feb 12, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -40,6 +40,7 @@
"@babel/preset-react": "7.7.0",
"@fullhuman/postcss-purgecss": "1.3.0",
"@mdx-js/loader": "0.18.0",
"@types/cheerio": "0.22.16",
"@types/http-proxy": "1.17.3",
"@types/jest": "24.0.13",
"@types/string-hash": "1.1.1",
Expand All @@ -59,6 +60,7 @@
"caniuse-lite": "^1.0.30001019",
"cheerio": "0.22.0",
"clone": "2.1.2",
"cookie": "0.4.0",
"coveralls": "3.0.3",
"cross-env": "6.0.3",
"cross-spawn": "6.0.5",
Expand Down
6 changes: 4 additions & 2 deletions packages/next/build/entries.ts
@@ -1,12 +1,12 @@
import chalk from 'chalk'
import { join } from 'path'
import { stringify } from 'querystring'

import { API_ROUTE, DOT_NEXT_ALIAS, PAGES_DIR_ALIAS } from '../lib/constants'
import { __ApiPreviewProps } from '../next-server/server/api-utils'
import { isTargetLikeServerless } from '../next-server/server/config'
import { normalizePagePath } from '../next-server/server/normalize-page-path'
import { warn } from './output/log'
import { ServerlessLoaderQuery } from './webpack/loaders/next-serverless-loader'
import { normalizePagePath } from '../next-server/server/normalize-page-path'

type PagesMapping = {
[page: string]: string
Expand Down Expand Up @@ -63,6 +63,7 @@ export function createEntrypoints(
pages: PagesMapping,
target: 'server' | 'serverless' | 'experimental-serverless-trace',
buildId: string,
previewMode: __ApiPreviewProps,
config: any
): Entrypoints {
const client: WebpackEntrypoints = {}
Expand All @@ -88,6 +89,7 @@ export function createEntrypoints(
serverRuntimeConfig: config.serverRuntimeConfig,
})
: '',
previewProps: JSON.stringify(previewMode),
}

Object.keys(pages).forEach(page => {
Expand Down
21 changes: 19 additions & 2 deletions packages/next/build/index.ts
@@ -1,5 +1,6 @@
import chalk from 'chalk'
import ciEnvironment from 'ci-info'
import crypto from 'crypto'
import escapeStringRegexp from 'escape-string-regexp'
import findUp from 'find-up'
import fs from 'fs'
Expand Down Expand Up @@ -41,9 +42,11 @@ import {
getSortedRoutes,
isDynamicRoute,
} from '../next-server/lib/router/utils'
import { __ApiPreviewProps } from '../next-server/server/api-utils'
import loadConfig, {
isTargetLikeServerless,
} from '../next-server/server/config'
import { normalizePagePath } from '../next-server/server/normalize-page-path'
import {
eventBuildCompleted,
eventBuildOptimize,
Expand All @@ -67,7 +70,6 @@ import {
} from './utils'
import getBaseWebpackConfig from './webpack-config'
import { writeBuildId } from './write-build-id'
import { normalizePagePath } from '../next-server/server/normalize-page-path'

const fsAccess = promisify(fs.access)
const fsUnlink = promisify(fs.unlink)
Expand Down Expand Up @@ -97,6 +99,7 @@ export type PrerenderManifest = {
version: number
routes: { [route: string]: SsgRoute }
dynamicRoutes: { [route: string]: DynamicSsgRoute }
preview: __ApiPreviewProps
}

export default async function build(dir: string, conf = null): Promise<void> {
Expand Down Expand Up @@ -198,8 +201,20 @@ export default async function build(dir: string, conf = null): Promise<void> {
const allStaticPages = new Set<string>()
let allPageInfos = new Map<string, PageInfo>()

const previewProps: __ApiPreviewProps = {
previewModeId: crypto.randomBytes(16).toString('hex'),
previewModeSigningKey: crypto.randomBytes(32).toString('hex'),
previewModeEncryptionKey: crypto.randomBytes(32).toString('hex'),
}

const mappedPages = createPagesMapping(pagePaths, config.pageExtensions)
const entrypoints = createEntrypoints(mappedPages, target, buildId, config)
const entrypoints = createEntrypoints(
mappedPages,
target,
buildId,
previewProps,
config
)
const pageKeys = Object.keys(mappedPages)
const dynamicRoutes = pageKeys.filter(page => isDynamicRoute(page))
const conflictingPublicFiles: string[] = []
Expand Down Expand Up @@ -802,6 +817,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
version: 1,
routes: finalPrerenderRoutes,
dynamicRoutes: finalDynamicRoutes,
preview: previewProps,
}

await fsWriteFile(
Expand All @@ -814,6 +830,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
version: 1,
routes: {},
dynamicRoutes: {},
preview: previewProps,
}
await fsWriteFile(
path.join(distDir, PRERENDER_MANIFEST),
Expand Down
18 changes: 14 additions & 4 deletions packages/next/build/webpack/loaders/next-serverless-loader.ts
@@ -1,14 +1,16 @@
import { loader } from 'webpack'
import devalue from 'devalue'
import escapeRegexp from 'escape-string-regexp'
import { join } from 'path'
import { parse } from 'querystring'
import { loader } from 'webpack'
import { API_ROUTE } from '../../../lib/constants'
import {
BUILD_MANIFEST,
ROUTES_MANIFEST,
REACT_LOADABLE_MANIFEST,
ROUTES_MANIFEST,
} from '../../../next-server/lib/constants'
import { isDynamicRoute } from '../../../next-server/lib/router/utils'
import { API_ROUTE } from '../../../lib/constants'
import escapeRegexp from 'escape-string-regexp'
import { __ApiPreviewProps } from '../../../next-server/server/api-utils'

export type ServerlessLoaderQuery = {
page: string
Expand All @@ -23,6 +25,7 @@ export type ServerlessLoaderQuery = {
canonicalBase: string
basePath: string
runtimeConfig: string
previewProps: string
}

const nextServerlessLoader: loader.Loader = function() {
Expand All @@ -39,6 +42,7 @@ const nextServerlessLoader: loader.Loader = function() {
generateEtags,
basePath,
runtimeConfig,
previewProps,
}: ServerlessLoaderQuery =
typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query

Expand All @@ -52,6 +56,10 @@ const nextServerlessLoader: loader.Loader = function() {
const escapedBuildId = escapeRegexp(buildId)
const pageIsDynamicRoute = isDynamicRoute(page)

const encodedPreviewProps = devalue(
JSON.parse(previewProps) as __ApiPreviewProps
)
ijjk marked this conversation as resolved.
Show resolved Hide resolved

const runtimeConfigImports = runtimeConfig
? `
const { setConfig } = require('next/dist/next-server/lib/runtime-config')
Expand Down Expand Up @@ -176,6 +184,7 @@ const nextServerlessLoader: loader.Loader = function() {
res,
Object.assign({}, parsedUrl.query, params ),
resolver,
${encodedPreviewProps},
onError
)
} catch (err) {
Expand Down Expand Up @@ -243,6 +252,7 @@ const nextServerlessLoader: loader.Loader = function() {
buildId: "${buildId}",
assetPrefix: "${assetPrefix}",
runtimeConfig: runtimeConfig.publicRuntimeConfig || {},
previewProps: ${encodedPreviewProps},
..._renderOpts
}
let _nextData = false
Expand Down
18 changes: 17 additions & 1 deletion packages/next/next-server/lib/utils.ts
Expand Up @@ -2,7 +2,6 @@ import { IncomingMessage, ServerResponse } from 'http'
import { ParsedUrlQuery } from 'querystring'
import { ComponentType } from 'react'
import { format, URLFormatOptions, UrlObject } from 'url'

import { ManifestItem } from '../server/load-components'
import { NextRouter } from './router/router'

Expand Down Expand Up @@ -201,6 +200,23 @@ export type NextApiResponse<T = any> = ServerResponse & {
*/
json: Send<T>
status: (statusCode: number) => NextApiResponse<T>

/**
* Set preview data for Next.js' prerender mode
*/
setPreviewData: (
data: object | string,
options?: {
/**
* Specifies the number (in seconds) for the preview session to last for.
* The given number will be converted to an integer by rounding down.
* By default, no maximum age is set and the preview session finishes
* when the client shuts down (browser is closed).
*/
maxAge?: number
}
) => NextApiResponse<T>
clearPreviewData: () => NextApiResponse<T>
}

/**
Expand Down