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

Add initial support for unstable_getServerProps #10077

Merged
merged 41 commits into from Jan 27, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
440d855
Add support for unstable_getServerProps
ijjk Jan 13, 2020
8a2d304
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 14, 2020
1ebb040
Apply suggestions from review
ijjk Jan 14, 2020
2cc40cf
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 14, 2020
576572b
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 15, 2020
6c0ac34
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 15, 2020
def1507
Add no-cache header and update types
ijjk Jan 17, 2020
30ad22f
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 17, 2020
40b3e68
Revert sharing of load-components type
ijjk Jan 17, 2020
7397571
Add catchall test and update routes-manifest field
ijjk Jan 17, 2020
8fcab0b
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 17, 2020
25be5ef
Update header check
ijjk Jan 17, 2020
83c89a8
Update to pass query for getServerProps data requests
ijjk Jan 17, 2020
351d424
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 17, 2020
9a5bf52
Update to not cache getServerProps requests
ijjk Jan 17, 2020
2c77127
Merge remote-tracking branch 'upstream/canary' into add/getserverprops
ijjk Jan 19, 2020
931d86c
Rename server side props identifier
ijjk Jan 19, 2020
3c17711
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 20, 2020
65d3634
Merge branch 'canary' into add/getServerProps
ijjk Jan 21, 2020
e4ad30c
Merge branch 'canary' into add/getServerProps
ijjk Jan 21, 2020
d456df1
Update to nest props for getServerProps
ijjk Jan 22, 2020
9ed63e5
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 22, 2020
fea16ca
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 24, 2020
55e05fc
Merge branch 'canary' into add/getServerProps
ijjk Jan 24, 2020
1ad34d7
Add no-cache header in serverless-loader also
ijjk Jan 24, 2020
7a1cc60
Update to throw error for mixed SSG/serverProps earlier
ijjk Jan 24, 2020
ff69a10
Add comment explaining params chosing in serverless-loader
ijjk Jan 24, 2020
862a617
Update invalidKeysMsg to return a string and inline throwing
ijjk Jan 24, 2020
9a2a4de
Inline throwing mixed SSG/serverProps error
ijjk Jan 24, 2020
a3c2576
Update setting cache header in serverless-loader
ijjk Jan 24, 2020
bb290f1
Add separate getServerData method in router
ijjk Jan 24, 2020
43a88b4
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 24, 2020
aadac7e
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 24, 2020
300d354
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 25, 2020
95fd2d8
Merge remote-tracking branch 'upstream/canary' into add/getServerProps
ijjk Jan 27, 2020
15bf407
Update checkIsSSG -> isDataIdentifier
ijjk Jan 27, 2020
1d8752b
Refactor router getData back to ternary
ijjk Jan 27, 2020
27bbb2b
Apply suggestions to build/index.ts
ijjk Jan 27, 2020
d9ee71c
drop return
ijjk Jan 27, 2020
2e8ef84
De-dupe extra escape regex
ijjk Jan 27, 2020
4fe847a
Add param test
ijjk Jan 27, 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 packages/next/build/babel/plugins/next-ssg-transform.ts
Expand Up @@ -6,10 +6,12 @@ const prerenderId = '__NEXT_SPR'

export const EXPORT_NAME_GET_STATIC_PROPS = 'unstable_getStaticProps'
export const EXPORT_NAME_GET_STATIC_PATHS = 'unstable_getStaticPaths'
export const EXPORT_NAME_GET_SERVER_PROPS = 'unstable_getServerProps'

const ssgExports = new Set([
EXPORT_NAME_GET_STATIC_PROPS,
EXPORT_NAME_GET_STATIC_PATHS,
EXPORT_NAME_GET_SERVER_PROPS,
])

type PluginState = {
Expand Down
57 changes: 42 additions & 15 deletions packages/next/build/index.ts
Expand Up @@ -254,22 +254,23 @@ export default async function build(dir: string, conf = null): Promise<void> {
}
}

const routesManifestPath = path.join(distDir, ROUTES_MANIFEST)
const routesManifest: any = {
version: 1,
basePath: config.experimental.basePath,
redirects: redirects.map(r => buildCustomRoute(r, 'redirect')),
rewrites: rewrites.map(r => buildCustomRoute(r, 'rewrite')),
headers: headers.map(r => buildCustomRoute(r, 'header')),
dynamicRoutes: getSortedRoutes(dynamicRoutes).map(page => ({
page,
regex: getRouteRegex(page).re.source,
})),
}

await mkdirp(distDir)
await fsWriteFile(
path.join(distDir, ROUTES_MANIFEST),
JSON.stringify({
version: 1,
basePath: config.experimental.basePath,
redirects: redirects.map(r => buildCustomRoute(r, 'redirect')),
rewrites: rewrites.map(r => buildCustomRoute(r, 'rewrite')),
headers: headers.map(r => buildCustomRoute(r, 'header')),
dynamicRoutes: getSortedRoutes(dynamicRoutes).map(page => ({
page,
regex: getRouteRegex(page).re.source,
})),
}),
'utf8'
)
// We need to write the manifest with rewrites before build
// so serverless can import the manifest
await fsWriteFile(routesManifestPath, JSON.stringify(routesManifest), 'utf8')

const configs = await Promise.all([
getBaseWebpackConfig(dir, {
Expand Down Expand Up @@ -401,6 +402,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
const staticPages = new Set<string>()
const invalidPages = new Set<string>()
const hybridAmpPages = new Set<string>()
const serverPropsPages = new Set<string>()
const additionalSprPaths = new Map<string, Array<string>>()
const pageInfos = new Map<string, PageInfo>()
const pagesManifest = JSON.parse(await fsReadFile(manifestPath, 'utf8'))
Expand Down Expand Up @@ -500,6 +502,8 @@ export default async function build(dir: string, conf = null): Promise<void> {
} else if (result.static && customAppGetInitialProps === false) {
staticPages.add(page)
isStatic = true
} else if (result.serverProps) {
ijjk marked this conversation as resolved.
Show resolved Hide resolved
serverPropsPages.add(page)
}
} catch (err) {
if (err.message !== 'INVALID_DEFAULT_EXPORT') throw err
Expand All @@ -520,6 +524,29 @@ export default async function build(dir: string, conf = null): Promise<void> {
)
staticCheckWorkers.end()

if (serverPropsPages.size > 0) {
// We update the routes manifest after the build with the
// serverProps routes since we can't determine this until after build
routesManifest.serverPropsRoutes = {}

for (const page of serverPropsPages) {
routesManifest.serverPropsRoutes[page] = {
page,
dataRoute: path.posix.join(
'/_next/data',
buildId,
`${page === '/' ? '/index' : page}.json`
),
}
}

await fsWriteFile(
routesManifestPath,
JSON.stringify(routesManifest),
'utf8'
)
}

if (invalidPages.size > 0) {
throw new Error(
`Build optimization failed: found page${
Expand Down
19 changes: 17 additions & 2 deletions packages/next/build/utils.ts
Expand Up @@ -5,7 +5,11 @@ import path from 'path'
import { isValidElementType } from 'react-is'
import stripAnsi from 'strip-ansi'
import { Redirect, Rewrite } from '../lib/check-custom-routes'
import { SPR_GET_INITIAL_PROPS_CONFLICT } from '../lib/constants'
import {
SPR_GET_INITIAL_PROPS_CONFLICT,
SERVER_PROPS_GET_INIT_PROPS_CONFLICT,
SERVER_PROPS_SPR_CONFLICT,
} from '../lib/constants'
import prettyBytes from '../lib/pretty-bytes'
import { recursiveReadDir } from '../lib/recursive-readdir'
import { DEFAULT_REDIRECT_STATUS } from '../next-server/lib/constants'
Expand Down Expand Up @@ -482,6 +486,7 @@ export async function isPageStatic(
static?: boolean
prerender?: boolean
isHybridAmp?: boolean
serverProps?: boolean
prerenderRoutes?: string[] | undefined
}> {
try {
Expand All @@ -496,6 +501,7 @@ export async function isPageStatic(
const hasGetInitialProps = !!(Comp as any).getInitialProps
const hasStaticProps = !!mod.unstable_getStaticProps
const hasStaticPaths = !!mod.unstable_getStaticPaths
const hasServerProps = !!mod.unstable_getServerProps
const hasLegacyStaticParams = !!mod.unstable_getStaticParams

if (hasLegacyStaticParams) {
Expand All @@ -510,6 +516,14 @@ export async function isPageStatic(
throw new Error(SPR_GET_INITIAL_PROPS_CONFLICT)
}

if (hasGetInitialProps && hasServerProps) {
throw new Error(SERVER_PROPS_GET_INIT_PROPS_CONFLICT)
}

if (hasStaticProps && hasServerProps) {
throw new Error(SERVER_PROPS_SPR_CONFLICT)
}

// A page cannot have static parameters if it is not a dynamic page.
if (hasStaticProps && hasStaticPaths && !isDynamicRoute(page)) {
throw new Error(
Expand Down Expand Up @@ -579,9 +593,10 @@ export async function isPageStatic(

const config = mod.config || {}
return {
static: !hasStaticProps && !hasGetInitialProps,
static: !hasStaticProps && !hasGetInitialProps && !hasServerProps,
ijjk marked this conversation as resolved.
Show resolved Hide resolved
ijjk marked this conversation as resolved.
Show resolved Hide resolved
isHybridAmp: config.amp === 'hybrid',
prerenderRoutes: prerenderPaths,
serverProps: hasServerProps,
ijjk marked this conversation as resolved.
Show resolved Hide resolved
prerender: hasStaticProps,
ijjk marked this conversation as resolved.
Show resolved Hide resolved
}
} catch (err) {
Expand Down
23 changes: 14 additions & 9 deletions packages/next/build/webpack/loaders/next-serverless-loader.ts
Expand Up @@ -185,6 +185,7 @@ const nextServerlessLoader: loader.Loader = function() {
export const unstable_getStaticProps = ComponentInfo['unstable_getStaticProp' + 's']
export const unstable_getStaticParams = ComponentInfo['unstable_getStaticParam' + 's']
export const unstable_getStaticPaths = ComponentInfo['unstable_getStaticPath' + 's']
export const unstable_getServerProps = ComponentInfo['unstable_getServerProp' + 's']

${dynamicRouteMatcher}
${handleRewrites}
Expand All @@ -206,17 +207,18 @@ const nextServerlessLoader: loader.Loader = function() {
Document,
buildManifest,
unstable_getStaticProps,
unstable_getServerProps,
unstable_getStaticPaths,
reactLoadableManifest,
canonicalBase: "${canonicalBase}",
buildId: "${buildId}",
assetPrefix: "${assetPrefix}",
..._renderOpts
}
let sprData = false
let _nextData = false

if (req.url.match(/_next\\/data/)) {
sprData = true
_nextData = true
req.url = req.url
.replace(new RegExp('/_next/data/${escapedBuildId}/'), '/')
.replace(/\\.json$/, '')
Expand All @@ -235,7 +237,7 @@ const nextServerlessLoader: loader.Loader = function() {
${page === '/_error' ? `res.statusCode = 404` : ''}
${
pageIsDynamicRoute
? `const params = fromExport && !unstable_getStaticProps ? {} : dynamicRouteMatcher(parsedUrl.pathname) || {};`
? `const params = fromExport && !unstable_getStaticProps && !unstable_getServerProps ? {} : dynamicRouteMatcher(parsedUrl.pathname) || {};`
: `const params = {};`
}
${
Expand Down Expand Up @@ -273,14 +275,17 @@ const nextServerlessLoader: loader.Loader = function() {
}
let result = await renderToHTML(req, res, "${page}", Object.assign({}, unstable_getStaticProps ? {} : parsedUrl.query, nowParams ? nowParams : params, _params), renderOpts)

if (sprData && !fromExport) {
const payload = JSON.stringify(renderOpts.sprData)
if (_nextData && !fromExport) {
const payload = JSON.stringify(renderOpts.pageData)
res.setHeader('Content-Type', 'application/json')
res.setHeader('Content-Length', Buffer.byteLength(payload))
res.setHeader(
'Cache-Control',
\`s-maxage=\${renderOpts.revalidate}, stale-while-revalidate\`
)

if (renderOpts.revalidate) {
ijjk marked this conversation as resolved.
Show resolved Hide resolved
res.setHeader(
'Cache-Control',
\`s-maxage=\${renderOpts.revalidate}, stale-while-revalidate\`
)
}
res.end(payload)
return null
}
Expand Down
6 changes: 3 additions & 3 deletions packages/next/export/index.ts
Expand Up @@ -276,7 +276,7 @@ export default async function(
}

const progress = !options.silent && createProgress(filteredPaths.length)
const sprDataDir = options.buildExport
const pageDataDir = options.buildExport
? outDir
: join(outDir, '_next/data', buildId)

Expand Down Expand Up @@ -318,7 +318,7 @@ export default async function(
distDir,
buildId,
outDir,
sprDataDir,
pageDataDir,
renderOpts,
serverRuntimeConfig,
subFolders,
Expand Down Expand Up @@ -360,7 +360,7 @@ export default async function(
subFolders && route !== '/index' ? `${sep}index` : ''
}.html`
)
const jsonDest = join(sprDataDir, `${route}.json`)
const jsonDest = join(pageDataDir, `${route}.json`)

await mkdirp(dirname(htmlDest))
await mkdirp(dirname(jsonDest))
Expand Down
8 changes: 4 additions & 4 deletions packages/next/export/worker.js
Expand Up @@ -25,7 +25,7 @@ export default async function({
distDir,
buildId,
outDir,
sprDataDir,
pageDataDir,
renderOpts,
buildExport,
serverRuntimeConfig,
Expand Down Expand Up @@ -234,14 +234,14 @@ export default async function({
}
}

if (curRenderOpts.sprData) {
if (curRenderOpts.pageData) {
const dataFile = join(
sprDataDir,
pageDataDir,
htmlFilename.replace(/\.html$/, '.json')
)

await mkdirp(dirname(dataFile))
await writeFileP(dataFile, JSON.stringify(curRenderOpts.sprData), 'utf8')
await writeFileP(dataFile, JSON.stringify(curRenderOpts.pageData), 'utf8')
}
results.fromBuildExportRevalidate = curRenderOpts.revalidate

Expand Down
4 changes: 4 additions & 0 deletions packages/next/lib/constants.ts
Expand Up @@ -25,3 +25,7 @@ export const DOT_NEXT_ALIAS = 'private-dot-next'
export const PUBLIC_DIR_MIDDLEWARE_CONFLICT = `You can not have a '_next' folder inside of your public folder. This conflicts with the internal '/_next' route. https://err.sh/zeit/next.js/public-next-folder-conflict`

export const SPR_GET_INITIAL_PROPS_CONFLICT = `You can not use getInitialProps with unstable_getStaticProps. To use SPR, please remove your getInitialProps`
ijjk marked this conversation as resolved.
Show resolved Hide resolved

export const SERVER_PROPS_GET_INIT_PROPS_CONFLICT = `You can not use getInitialProps with unstable_getServerProps. Please remove one or the other`

export const SERVER_PROPS_SPR_CONFLICT = `You can not use unstable_getStaticProps with unstable_getServerProps. To use SPR, please remove your unstable_getServerProps`
ijjk marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 8 additions & 0 deletions packages/next/next-server/server/load-components.ts
@@ -1,3 +1,5 @@
import { IncomingMessage, ServerResponse } from 'http'
import { ParsedUrlQuery } from 'querystring'
import {
BUILD_MANIFEST,
CLIENT_STATIC_FILES_PATH,
Expand All @@ -22,6 +24,11 @@ export type LoadComponentsReturnType = {
revalidate?: number | boolean
}
unstable_getStaticPaths?: () => void
unstable_getServerProps?: (context: {
req: IncomingMessage
res: ServerResponse
query: ParsedUrlQuery
ijjk marked this conversation as resolved.
Show resolved Hide resolved
}) => Promise<{ [key: string]: any }>
buildManifest?: any
reactLoadableManifest?: any
Document?: any
Expand Down Expand Up @@ -90,6 +97,7 @@ export async function loadComponents(
DocumentMiddleware,
reactLoadableManifest,
pageConfig: ComponentMod.config || {},
unstable_getServerProps: ComponentMod.unstable_getServerProps,
unstable_getStaticProps: ComponentMod.unstable_getStaticProps,
unstable_getStaticPaths: ComponentMod.unstable_getStaticPaths,
}
Expand Down