rsnext/packages/next/build/babel/plugins/next-page-config.ts

215 lines
7.3 KiB
TypeScript
Raw Normal View History

import {
NodePath,
PluginObj,
PluginPass,
types as BabelTypes,
Visitor,
} from 'next/dist/compiled/babel/core'
import { PageConfig } from 'next/types'
import { STRING_LITERAL_DROP_BUNDLE } from '../../../shared/lib/constants'
const CONFIG_KEY = 'config'
// replace program path with just a variable with the drop identifier
function replaceBundle(path: any, t: typeof BabelTypes): void {
path.parentPath.replaceWith(
t.program(
[
t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(STRING_LITERAL_DROP_BUNDLE),
t.stringLiteral(`${STRING_LITERAL_DROP_BUNDLE} ${Date.now()}`)
),
]),
],
[]
)
)
}
function errorMessage(state: any, details: string): string {
const pageName =
(state.filename || '').split(state.cwd || '').pop() || 'unknown'
return `Invalid page config export found. ${details} in file ${pageName}. See: https://nextjs.org/docs/messages/invalid-page-config`
}
interface ConfigState extends PluginPass {
bundleDropped?: boolean
}
Add experimental SPR support (#8832) * initial commit for SPRv2 * Add initial SPR cache handling * update SPR handling * Implement SPR handling in render * Update tests, handle caching with serverless next start, add TODOs, and update manifest generating * Handle no prerender-manifest from not being used * Fix url.parse error * Apply suggestions from code review Co-Authored-By: Joe Haddad <joe.haddad@zeit.co> * Replace set with constants in next-page-config * simplify sprStatus.used * Add error if getStaticProps is used with getInitialProps * Remove stale TODO * Update revalidate values in SPR cache for non-seeded routes * Apply suggestions from code review * Remove concurrency type * Rename variable for clarity * Add copying prerender files during export * Add comment for clarity * Fix exporting * Update comment * Add additional note * Rename variable * Update to not re-export SPR pages from build * Hard navigate when fetching data fails * Remove default extension * Add brackets * Add checking output files to prerender tests * Adjust export move logic * Clarify behavior of export aggregation * Update variable names for clarity * Update tests * Add comment * s/an oxymoron/contradictory/ * rename * Extract error case * Add tests for exporting SPR pages and update /_next/data endpoint to end with .json * Relocate variable * Adjust route building * Rename to unstable * Rename unstable_getStaticParams * Fix linting * Only add this when a data request * Update prerender data tests * s/isServerless/isLikeServerless/ * Don't rely on query for `next start` in serverless mode * Rename var * Update renderedDuringBuild check * Add test for dynamic param with bracket * Fix serverless next start handling * remove todo * Adjust comment * Update calculateRevalidate * Remove cache logic from render.tsx * Remove extra imports * Move SPR cache logic to next-server * Remove old isDynamic prop * Add calling App getInitialProps for SPR pages * Update revalidate logic * Add isStale to SprCacheValue * Update headers for SPR * add awaiting pendingRevalidation * Dont return null for revalidation render * Adjust logic * Be sure to remove coalesced render * Fix data for serverless * Create a method coalescing utility * Remove TODO * Extract send payload helper * Wrap in-line * Move around some code * Add tests for de-duping and revalidating * Update prerender manifest test
2019-09-24 10:50:04 +02:00
// config to parsing pageConfig for client bundles
export default function nextPageConfig({
types: t,
}: {
types: typeof BabelTypes
}): PluginObj {
return {
visitor: {
Program: {
enter(path, state) {
path.traverse(
{
ExportDeclaration(exportPath, exportState) {
if (
BabelTypes.isExportNamedDeclaration(exportPath) &&
(
exportPath.node as BabelTypes.ExportNamedDeclaration
).specifiers?.some((specifier) => {
return (
(t.isIdentifier(specifier.exported)
? specifier.exported.name
: specifier.exported.value) === CONFIG_KEY
)
}) &&
BabelTypes.isStringLiteral(
(exportPath.node as BabelTypes.ExportNamedDeclaration)
.source
)
) {
throw new Error(
errorMessage(
exportState,
'Expected object but got export from'
)
)
}
},
ExportNamedDeclaration(
exportPath: NodePath<BabelTypes.ExportNamedDeclaration>,
exportState: any
) {
if (
exportState.bundleDropped ||
(!exportPath.node.declaration &&
exportPath.node.specifiers.length === 0)
) {
Add experimental SPR support (#8832) * initial commit for SPRv2 * Add initial SPR cache handling * update SPR handling * Implement SPR handling in render * Update tests, handle caching with serverless next start, add TODOs, and update manifest generating * Handle no prerender-manifest from not being used * Fix url.parse error * Apply suggestions from code review Co-Authored-By: Joe Haddad <joe.haddad@zeit.co> * Replace set with constants in next-page-config * simplify sprStatus.used * Add error if getStaticProps is used with getInitialProps * Remove stale TODO * Update revalidate values in SPR cache for non-seeded routes * Apply suggestions from code review * Remove concurrency type * Rename variable for clarity * Add copying prerender files during export * Add comment for clarity * Fix exporting * Update comment * Add additional note * Rename variable * Update to not re-export SPR pages from build * Hard navigate when fetching data fails * Remove default extension * Add brackets * Add checking output files to prerender tests * Adjust export move logic * Clarify behavior of export aggregation * Update variable names for clarity * Update tests * Add comment * s/an oxymoron/contradictory/ * rename * Extract error case * Add tests for exporting SPR pages and update /_next/data endpoint to end with .json * Relocate variable * Adjust route building * Rename to unstable * Rename unstable_getStaticParams * Fix linting * Only add this when a data request * Update prerender data tests * s/isServerless/isLikeServerless/ * Don't rely on query for `next start` in serverless mode * Rename var * Update renderedDuringBuild check * Add test for dynamic param with bracket * Fix serverless next start handling * remove todo * Adjust comment * Update calculateRevalidate * Remove cache logic from render.tsx * Remove extra imports * Move SPR cache logic to next-server * Remove old isDynamic prop * Add calling App getInitialProps for SPR pages * Update revalidate logic * Add isStale to SprCacheValue * Update headers for SPR * add awaiting pendingRevalidation * Dont return null for revalidation render * Adjust logic * Be sure to remove coalesced render * Fix data for serverless * Create a method coalescing utility * Remove TODO * Extract send payload helper * Wrap in-line * Move around some code * Add tests for de-duping and revalidating * Update prerender manifest test
2019-09-24 10:50:04 +02:00
return
}
const config: PageConfig = {}
const declarations: BabelTypes.VariableDeclarator[] = [
...((
exportPath.node
.declaration as BabelTypes.VariableDeclaration
)?.declarations || []),
exportPath.scope.getBinding(CONFIG_KEY)?.path
.node as BabelTypes.VariableDeclarator,
].filter(Boolean)
for (const specifier of exportPath.node.specifiers) {
if (
(t.isIdentifier(specifier.exported)
? specifier.exported.name
: specifier.exported.value) === CONFIG_KEY
) {
// export {} from 'somewhere'
if (BabelTypes.isStringLiteral(exportPath.node.source)) {
throw new Error(
errorMessage(
exportState,
`Expected object but got import`
)
)
// import hello from 'world'
// export { hello as config }
} else if (
BabelTypes.isIdentifier(
(specifier as BabelTypes.ExportSpecifier).local
)
) {
if (
BabelTypes.isImportSpecifier(
exportPath.scope.getBinding(
(specifier as BabelTypes.ExportSpecifier).local.name
)?.path.node
)
) {
throw new Error(
errorMessage(
exportState,
`Expected object but got import`
)
)
}
}
}
}
for (const declaration of declarations) {
if (
!BabelTypes.isIdentifier(declaration.id, {
name: CONFIG_KEY,
})
) {
Add experimental SPR support (#8832) * initial commit for SPRv2 * Add initial SPR cache handling * update SPR handling * Implement SPR handling in render * Update tests, handle caching with serverless next start, add TODOs, and update manifest generating * Handle no prerender-manifest from not being used * Fix url.parse error * Apply suggestions from code review Co-Authored-By: Joe Haddad <joe.haddad@zeit.co> * Replace set with constants in next-page-config * simplify sprStatus.used * Add error if getStaticProps is used with getInitialProps * Remove stale TODO * Update revalidate values in SPR cache for non-seeded routes * Apply suggestions from code review * Remove concurrency type * Rename variable for clarity * Add copying prerender files during export * Add comment for clarity * Fix exporting * Update comment * Add additional note * Rename variable * Update to not re-export SPR pages from build * Hard navigate when fetching data fails * Remove default extension * Add brackets * Add checking output files to prerender tests * Adjust export move logic * Clarify behavior of export aggregation * Update variable names for clarity * Update tests * Add comment * s/an oxymoron/contradictory/ * rename * Extract error case * Add tests for exporting SPR pages and update /_next/data endpoint to end with .json * Relocate variable * Adjust route building * Rename to unstable * Rename unstable_getStaticParams * Fix linting * Only add this when a data request * Update prerender data tests * s/isServerless/isLikeServerless/ * Don't rely on query for `next start` in serverless mode * Rename var * Update renderedDuringBuild check * Add test for dynamic param with bracket * Fix serverless next start handling * remove todo * Adjust comment * Update calculateRevalidate * Remove cache logic from render.tsx * Remove extra imports * Move SPR cache logic to next-server * Remove old isDynamic prop * Add calling App getInitialProps for SPR pages * Update revalidate logic * Add isStale to SprCacheValue * Update headers for SPR * add awaiting pendingRevalidation * Dont return null for revalidation render * Adjust logic * Be sure to remove coalesced render * Fix data for serverless * Create a method coalescing utility * Remove TODO * Extract send payload helper * Wrap in-line * Move around some code * Add tests for de-duping and revalidating * Update prerender manifest test
2019-09-24 10:50:04 +02:00
continue
}
let { init } = declaration
if (BabelTypes.isTSAsExpression(init)) {
init = init.expression
}
if (!BabelTypes.isObjectExpression(init)) {
const got = init ? init.type : 'undefined'
throw new Error(
errorMessage(
exportState,
`Expected object but got ${got}`
)
)
}
for (const prop of init.properties) {
if (BabelTypes.isSpreadElement(prop)) {
throw new Error(
errorMessage(
exportState,
`Property spread is not allowed`
)
)
}
const { name } = prop.key as BabelTypes.Identifier
if (BabelTypes.isIdentifier(prop.key, { name: 'amp' })) {
if (!BabelTypes.isObjectProperty(prop)) {
throw new Error(
errorMessage(
exportState,
`Invalid property "${name}"`
)
)
}
if (
!BabelTypes.isBooleanLiteral(prop.value) &&
!BabelTypes.isStringLiteral(prop.value)
) {
throw new Error(
errorMessage(
exportState,
`Invalid value for "${name}"`
)
)
}
config.amp = prop.value.value as PageConfig['amp']
}
}
}
if (config.amp === true) {
if (!exportState.file?.opts?.caller.isDev) {
// don't replace bundle in development so HMR can track
// dependencies and trigger reload when they are changed
replaceBundle(exportPath, t)
}
exportState.bundleDropped = true
return
}
},
},
state
)
},
},
} as Visitor<ConfigState>,
}
}