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

Update method for attaching GS(S)P identifier to page #10859

Merged
merged 3 commits into from Mar 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
76 changes: 26 additions & 50 deletions packages/next/build/babel/plugins/next-ssg-transform.ts
Expand Up @@ -6,8 +6,6 @@ import {
SERVER_PROPS_ID,
} from '../../../next-server/lib/constants'

const pageComponentVar = '__NEXT_COMP'

export const EXPORT_NAME_GET_STATIC_PROPS = 'getStaticProps'
export const EXPORT_NAME_GET_STATIC_PATHS = 'getStaticPaths'
export const EXPORT_NAME_GET_SERVER_PROPS = 'getServerSideProps'
Expand Down Expand Up @@ -37,64 +35,42 @@ function decorateSsgExport(
path: NodePath<BabelTypes.Program>,
state: PluginState
) {
path.traverse({
ExportDefaultDeclaration(path) {
if (state.done) {
return
}
state.done = true
const gsspName = state.isPrerender ? STATIC_PROPS_ID : SERVER_PROPS_ID
const gsspId = t.identifier(gsspName)

const prev = path.node.declaration
if (prev.type.endsWith('Declaration')) {
prev.type = prev.type.replace(/Declaration$/, 'Expression') as any
}
const addGsspExport = (
path: NodePath<
BabelTypes.ExportDefaultDeclaration | BabelTypes.ExportNamedDeclaration
>
) => {
if (state.done) {
return
}
state.done = true

// @ts-ignore invalid return type
const [pageCompPath] = path.replaceWithMultiple([
// @ts-ignore invalid return type
const [pageCompPath] = path.replaceWithMultiple([
t.exportNamedDeclaration(
t.variableDeclaration(
// We use 'var' instead of 'let' or 'const' for ES5 support. Since
// this runs in `Program#exit`, no ES2015 transforms (preset env)
// will be ran against this code.
'var',
[t.variableDeclarator(t.identifier(pageComponentVar), prev as any)]
),
t.assignmentExpression(
'=',
t.memberExpression(
t.identifier(pageComponentVar),
t.identifier(state.isPrerender ? STATIC_PROPS_ID : SERVER_PROPS_ID)
),
t.booleanLiteral(true)
[t.variableDeclarator(gsspId, t.booleanLiteral(true))]
),
t.exportDefaultDeclaration(t.identifier(pageComponentVar)),
])
path.scope.registerDeclaration(pageCompPath)
[t.exportSpecifier(gsspId, gsspId)]
),
path.node,
])
path.scope.registerDeclaration(pageCompPath)
}

path.traverse({
ExportDefaultDeclaration(path) {
addGsspExport(path)
},
ExportNamedDeclaration(path) {
if (state.done) {
return
}

// Look for a `export { _ as default }` specifier
const defaultSpecifier = path.node.specifiers.find(s => {
return s.exported.name === 'default'
})
if (!defaultSpecifier) {
return
}
state.done = true

path.replaceWithMultiple([
t.assignmentExpression(
'=',
t.memberExpression(
t.identifier((defaultSpecifier as any).local.name),
t.identifier(state.isPrerender ? STATIC_PROPS_ID : SERVER_PROPS_ID)
),
t.booleanLiteral(true)
),
path.node,
])
addGsspExport(path)
},
})
}
Expand Down
7 changes: 3 additions & 4 deletions packages/next/client/index.js
Expand Up @@ -100,7 +100,7 @@ class Container extends React.Component {
(isFallback ||
(data.nextExport &&
(isDynamicRoute(router.pathname) || location.search)) ||
(Component && Component.__N_SSG && location.search))
(props.__N_SSG && location.search))
) {
// update query on mount for exported pages
router.replace(
Expand Down Expand Up @@ -180,7 +180,7 @@ export default async ({ webpackHMR: passedWebpackHMR } = {}) => {
let initialErr = err

try {
Component = await pageLoader.loadPage(page)
;({ page: Component } = await pageLoader.loadPage(page))

if (process.env.NODE_ENV !== 'production') {
const { isValidElementType } = require('react-is')
Expand Down Expand Up @@ -273,8 +273,7 @@ export async function renderError(props) {

// Make sure we log the error to the console, otherwise users can't track down issues.
console.error(err)

ErrorComponent = await pageLoader.loadPage('/_error')
;({ page: ErrorComponent } = await pageLoader.loadPage('/_error'))

// In production we do a normal render with the `ErrorComponent` as component.
// If we've gotten here upon initial render, we can use the props from the server.
Expand Down
2 changes: 1 addition & 1 deletion packages/next/client/page-loader.js
Expand Up @@ -175,7 +175,7 @@ export default class PageLoader {
}

loadPage(route) {
return this.loadPageScript(route).then(v => v.page)
return this.loadPageScript(route)
}

loadPageScript(route) {
Expand Down
41 changes: 31 additions & 10 deletions packages/next/next-server/lib/router/router.ts
Expand Up @@ -31,6 +31,8 @@ const prepareRoute = (path: string) =>

type Url = UrlObject | string

type ComponentRes = { page: ComponentType; mod: any }

export type BaseRouter = {
route: string
pathname: string
Expand All @@ -57,6 +59,8 @@ export type PrefetchOptions = {

type RouteInfo = {
Component: ComponentType
__N_SSG?: boolean
__N_SSP?: boolean
props?: any
err?: Error
error?: any
Expand Down Expand Up @@ -179,7 +183,13 @@ export default class Router implements BaseRouter {
// Otherwise, this cause issues when when going back and
// come again to the errored page.
if (pathname !== '/_error') {
this.components[this.route] = { Component, props: initialProps, err }
this.components[this.route] = {
Component,
props: initialProps,
err,
__N_SSG: initialProps && initialProps.__N_SSG,
__N_SSP: initialProps && initialProps.__N_SSP,
}
}

this.components['/_app'] = { Component: App }
Expand Down Expand Up @@ -284,7 +294,12 @@ export default class Router implements BaseRouter {
throw new Error(`Cannot update unavailable route: ${route}`)
}

const newData = { ...data, Component }
const newData = {
...data,
Component,
__N_SSG: mod.__N_SSG,
__N_SSP: mod.__N_SSP,
}
this.components[route] = newData

// pages/_app.js updated
Expand Down Expand Up @@ -542,7 +557,8 @@ export default class Router implements BaseRouter {

resolve(
this.fetchComponent('/_error')
.then(Component => {
.then(res => {
const { page: Component } = res
const routeInfo: RouteInfo = { Component, err }
return new Promise(resolve => {
this.getInitialProps(Component, {
Expand Down Expand Up @@ -578,12 +594,17 @@ export default class Router implements BaseRouter {
}

this.fetchComponent(route).then(
Component => resolve({ Component }),
res =>
resolve({
Component: res.page,
__N_SSG: res.mod.__N_SSG,
__N_SSP: res.mod.__N_SSP,
}),
reject
)
}) as Promise<RouteInfo>)
.then((routeInfo: RouteInfo) => {
const { Component } = routeInfo
const { Component, __N_SSG, __N_SSP } = routeInfo

if (process.env.NODE_ENV !== 'production') {
const { isValidElementType } = require('react-is')
Expand All @@ -595,9 +616,9 @@ export default class Router implements BaseRouter {
}

return this._getData<RouteInfo>(() =>
(Component as any).__N_SSG
__N_SSG
? this._getStaticData(as)
: (Component as any).__N_SSP
: __N_SSP
? this._getServerData(as)
: this.getInitialProps(
Component,
Expand Down Expand Up @@ -726,13 +747,13 @@ export default class Router implements BaseRouter {
})
}

async fetchComponent(route: string): Promise<ComponentType> {
async fetchComponent(route: string): Promise<ComponentRes> {
let cancelled = false
const cancel = (this.clc = () => {
cancelled = true
})

const Component = await this.pageLoader.loadPage(route)
const componentResult = await this.pageLoader.loadPage(route)

if (cancelled) {
const error: any = new Error(
Expand All @@ -746,7 +767,7 @@ export default class Router implements BaseRouter {
this.clc = null
}

return Component
return componentResult
}

_getData<T>(fn: () => Promise<T>): Promise<T> {
Expand Down
2 changes: 2 additions & 0 deletions packages/next/next-server/lib/utils.ts
Expand Up @@ -134,6 +134,8 @@ export type AppPropsType<
> = AppInitialProps & {
Component: NextComponentType<NextPageContext, any, P>
router: R
__N_SSG?: boolean
__N_SSP?: boolean
}

export type DocumentContext = NextPageContext & {
Expand Down
20 changes: 0 additions & 20 deletions packages/next/next-server/server/load-components.ts
Expand Up @@ -3,8 +3,6 @@ import {
CLIENT_STATIC_FILES_PATH,
REACT_LOADABLE_MANIFEST,
SERVER_DIRECTORY,
STATIC_PROPS_ID,
SERVER_PROPS_ID,
} from '../lib/constants'
import { join } from 'path'
import { requirePage } from './require'
Expand All @@ -22,20 +20,6 @@ export function interopDefault(mod: any) {
return mod.default || mod
}

function addComponentPropsId(
Component: any,
getStaticProps: any,
getServerSideProps: any
) {
// Mark the component with the SSG or SSP id here since we don't run
// the SSG babel transform for server mode
if (getStaticProps) {
Component[STATIC_PROPS_ID] = true
} else if (getServerSideProps) {
Component[SERVER_PROPS_ID] = true
}
}

export type ManifestItem = {
id: number | string
name: string
Expand Down Expand Up @@ -68,8 +52,6 @@ export async function loadComponents(
const Component = await requirePage(pathname, distDir, serverless)
const { getStaticProps, getStaticPaths, getServerSideProps } = Component

addComponentPropsId(Component, getStaticProps, getServerSideProps)

return {
Component,
pageConfig: Component.config || {},
Expand Down Expand Up @@ -118,8 +100,6 @@ export async function loadComponents(

const { getServerSideProps, getStaticProps, getStaticPaths } = ComponentMod

addComponentPropsId(Component, getStaticProps, getServerSideProps)

return {
App,
Document,
Expand Down
15 changes: 14 additions & 1 deletion packages/next/next-server/server/render.tsx
Expand Up @@ -10,7 +10,11 @@ import {
} from '../../lib/constants'
import { isInAmpMode } from '../lib/amp'
import { AmpStateContext } from '../lib/amp-context'
import { AMP_RENDER_TARGET } from '../lib/constants'
import {
AMP_RENDER_TARGET,
STATIC_PROPS_ID,
SERVER_PROPS_ID,
} from '../lib/constants'
import Head, { defaultHead } from '../lib/head'
import Loadable from '../lib/loadable'
import { LoadableContext } from '../lib/loadable-context'
Expand Down Expand Up @@ -471,6 +475,11 @@ export async function renderToHTML(
router,
ctx,
})

if (isSSG) {
props[STATIC_PROPS_ID] = true
}

let previewData: string | false | object | undefined

if ((isSSG || getServerSideProps) && !isFallback) {
Expand Down Expand Up @@ -534,6 +543,10 @@ export async function renderToHTML(
;(renderOpts as any).pageData = props
}

if (getServerSideProps) {
props[SERVER_PROPS_ID] = true
}

if (getServerSideProps && !isFallback) {
const data = await getServerSideProps({
req,
Expand Down
7 changes: 3 additions & 4 deletions packages/next/pages/_app.tsx
Expand Up @@ -41,17 +41,16 @@ export default class App<P = {}, CP = {}, S = {}> extends React.Component<
}

render() {
const { router, Component, pageProps } = this.props as AppProps<CP>
const { router, Component, pageProps, __N_SSG, __N_SSP } = this
.props as AppProps<CP>

return (
<Component
{...pageProps}
{
// we don't add the legacy URL prop if it's using non-legacy
// methods like getStaticProps and getServerSideProps
...(!((Component as any).__N_SSG || (Component as any).__N_SSP)
? { url: createUrl(router) }
: {})
...(!(__N_SSG || __N_SSP) ? { url: createUrl(router) } : {})
}
/>
)
Expand Down