mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-10 21:07:48 +00:00
Added getRequestHandlerWithMetadata export (#10753)
This adds a new `getRequestHandlerWithMetadata` export if enabled and available to the exported method. --------- Co-authored-by: Joe Haddad <timer@vercel.com> Co-authored-by: JJ Kasper <jj@jjsweb.site>
This commit is contained in:
5
.changeset/soft-days-repeat.md
Normal file
5
.changeset/soft-days-repeat.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@vercel/next": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Added `getRequestHandlerWithMetadata` export
|
||||||
@@ -1605,6 +1605,7 @@ export const build: BuildV2 = async ({
|
|||||||
// internal pages are already referenced in traces for serverless
|
// internal pages are already referenced in traces for serverless
|
||||||
// like builds
|
// like builds
|
||||||
internalPages: [],
|
internalPages: [],
|
||||||
|
experimentalPPRRoutes: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const initialApiLambdaGroups = await getPageLambdaGroups({
|
const initialApiLambdaGroups = await getPageLambdaGroups({
|
||||||
@@ -1620,6 +1621,7 @@ export const build: BuildV2 = async ({
|
|||||||
initialPseudoLayerUncompressed: 0,
|
initialPseudoLayerUncompressed: 0,
|
||||||
lambdaCompressedByteLimit,
|
lambdaCompressedByteLimit,
|
||||||
internalPages: [],
|
internalPages: [],
|
||||||
|
experimentalPPRRoutes: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const group of initialApiLambdaGroups) {
|
for (const group of initialApiLambdaGroups) {
|
||||||
@@ -2108,6 +2110,7 @@ export const build: BuildV2 = async ({
|
|||||||
static404Page,
|
static404Page,
|
||||||
pageLambdaMap,
|
pageLambdaMap,
|
||||||
lambdas,
|
lambdas,
|
||||||
|
experimentalStreamingLambdaPaths: undefined,
|
||||||
isServerMode,
|
isServerMode,
|
||||||
prerenders,
|
prerenders,
|
||||||
entryDirectory,
|
entryDirectory,
|
||||||
@@ -2141,20 +2144,41 @@ export const build: BuildV2 = async ({
|
|||||||
[
|
[
|
||||||
...Object.entries(prerenderManifest.fallbackRoutes),
|
...Object.entries(prerenderManifest.fallbackRoutes),
|
||||||
...Object.entries(prerenderManifest.blockingFallbackRoutes),
|
...Object.entries(prerenderManifest.blockingFallbackRoutes),
|
||||||
].forEach(([, { dataRouteRegex, dataRoute }]) => {
|
].forEach(
|
||||||
if (!dataRoute || !dataRouteRegex) return;
|
([
|
||||||
|
,
|
||||||
|
{
|
||||||
|
dataRouteRegex,
|
||||||
|
dataRoute,
|
||||||
|
prefetchDataRouteRegex,
|
||||||
|
prefetchDataRoute,
|
||||||
|
},
|
||||||
|
]) => {
|
||||||
|
if (!dataRoute || !dataRouteRegex) return;
|
||||||
|
|
||||||
dataRoutes.push({
|
dataRoutes.push({
|
||||||
// Next.js provided data route regex
|
// Next.js provided data route regex
|
||||||
src: dataRouteRegex.replace(
|
src: dataRouteRegex.replace(
|
||||||
/^\^/,
|
/^\^/,
|
||||||
`^${appMountPrefixNoTrailingSlash}`
|
`^${appMountPrefixNoTrailingSlash}`
|
||||||
),
|
),
|
||||||
// Location of lambda in builder output
|
// Location of lambda in builder output
|
||||||
dest: path.posix.join(entryDirectory, dataRoute),
|
dest: path.posix.join(entryDirectory, dataRoute),
|
||||||
check: true,
|
check: true,
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
if (!prefetchDataRoute || !prefetchDataRouteRegex) return;
|
||||||
|
|
||||||
|
dataRoutes.push({
|
||||||
|
src: prefetchDataRouteRegex.replace(
|
||||||
|
/^\^/,
|
||||||
|
`^${appMountPrefixNoTrailingSlash}`
|
||||||
|
),
|
||||||
|
dest: path.posix.join(entryDirectory, prefetchDataRoute),
|
||||||
|
check: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
Files,
|
Files,
|
||||||
Flag,
|
Flag,
|
||||||
BuildResultV2Typical as BuildResult,
|
BuildResultV2Typical as BuildResult,
|
||||||
|
NodejsLambda,
|
||||||
} from '@vercel/build-utils';
|
} from '@vercel/build-utils';
|
||||||
import { Route, RouteWithHandle } from '@vercel/routing-utils';
|
import { Route, RouteWithHandle } from '@vercel/routing-utils';
|
||||||
import { MAX_AGE_ONE_YEAR } from '.';
|
import { MAX_AGE_ONE_YEAR } from '.';
|
||||||
@@ -50,6 +51,7 @@ import {
|
|||||||
RSC_CONTENT_TYPE,
|
RSC_CONTENT_TYPE,
|
||||||
RSC_PREFETCH_SUFFIX,
|
RSC_PREFETCH_SUFFIX,
|
||||||
normalizePrefetches,
|
normalizePrefetches,
|
||||||
|
CreateLambdaFromPseudoLayersOptions,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import {
|
import {
|
||||||
nodeFileTrace,
|
nodeFileTrace,
|
||||||
@@ -182,6 +184,10 @@ export async function serverBuild({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const experimental = {
|
||||||
|
ppr: requiredServerFilesManifest.config.experimental?.ppr === true,
|
||||||
|
};
|
||||||
|
|
||||||
let appRscPrefetches: UnwrapPromise<ReturnType<typeof glob>> = {};
|
let appRscPrefetches: UnwrapPromise<ReturnType<typeof glob>> = {};
|
||||||
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
|
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
|
||||||
let appDir: string | null = null;
|
let appDir: string | null = null;
|
||||||
@@ -189,7 +195,11 @@ export async function serverBuild({
|
|||||||
if (appPathRoutesManifest) {
|
if (appPathRoutesManifest) {
|
||||||
appDir = path.join(pagesDir, '../app');
|
appDir = path.join(pagesDir, '../app');
|
||||||
appBuildTraces = await glob('**/*.js.nft.json', appDir);
|
appBuildTraces = await glob('**/*.js.nft.json', appDir);
|
||||||
appRscPrefetches = await glob(`**/*${RSC_PREFETCH_SUFFIX}`, appDir);
|
|
||||||
|
// TODO: maybe?
|
||||||
|
appRscPrefetches = experimental.ppr
|
||||||
|
? {}
|
||||||
|
: await glob(`**/*${RSC_PREFETCH_SUFFIX}`, appDir);
|
||||||
|
|
||||||
const rscContentTypeHeader =
|
const rscContentTypeHeader =
|
||||||
routesManifest?.rsc?.contentTypeHeader || RSC_CONTENT_TYPE;
|
routesManifest?.rsc?.contentTypeHeader || RSC_CONTENT_TYPE;
|
||||||
@@ -295,6 +305,18 @@ export async function serverBuild({
|
|||||||
internalPages.push('404.js');
|
internalPages.push('404.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const experimentalPPRRoutes = new Set<string>();
|
||||||
|
|
||||||
|
for (const [route, { experimentalPPR }] of [
|
||||||
|
...Object.entries(prerenderManifest.staticRoutes),
|
||||||
|
...Object.entries(prerenderManifest.blockingFallbackRoutes),
|
||||||
|
...Object.entries(prerenderManifest.fallbackRoutes),
|
||||||
|
]) {
|
||||||
|
if (!experimentalPPR) continue;
|
||||||
|
|
||||||
|
experimentalPPRRoutes.add(route);
|
||||||
|
}
|
||||||
|
|
||||||
const prerenderRoutes = new Set<string>([
|
const prerenderRoutes = new Set<string>([
|
||||||
...(canUsePreviewMode ? omittedPrerenderRoutes : []),
|
...(canUsePreviewMode ? omittedPrerenderRoutes : []),
|
||||||
...Object.keys(prerenderManifest.blockingFallbackRoutes),
|
...Object.keys(prerenderManifest.blockingFallbackRoutes),
|
||||||
@@ -305,6 +327,8 @@ export async function serverBuild({
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const experimentalStreamingLambdaPaths = new Map<string, string>();
|
||||||
|
|
||||||
if (hasLambdas) {
|
if (hasLambdas) {
|
||||||
const initialTracingLabel = 'Traced Next.js server files in';
|
const initialTracingLabel = 'Traced Next.js server files in';
|
||||||
|
|
||||||
@@ -619,8 +643,8 @@ export async function serverBuild({
|
|||||||
);
|
);
|
||||||
let launcher = launcherData
|
let launcher = launcherData
|
||||||
.replace(
|
.replace(
|
||||||
'conf: __NEXT_CONFIG__',
|
'const conf = __NEXT_CONFIG__',
|
||||||
`conf: ${JSON.stringify({
|
`const conf = ${JSON.stringify({
|
||||||
...requiredServerFilesManifest.config,
|
...requiredServerFilesManifest.config,
|
||||||
distDir: path.relative(
|
distDir: path.relative(
|
||||||
projectDir,
|
projectDir,
|
||||||
@@ -823,6 +847,7 @@ export async function serverBuild({
|
|||||||
prerenderRoutes,
|
prerenderRoutes,
|
||||||
pageTraces,
|
pageTraces,
|
||||||
compressedPages,
|
compressedPages,
|
||||||
|
experimentalPPRRoutes: undefined,
|
||||||
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
||||||
initialPseudoLayer,
|
initialPseudoLayer,
|
||||||
lambdaCompressedByteLimit,
|
lambdaCompressedByteLimit,
|
||||||
@@ -843,6 +868,7 @@ export async function serverBuild({
|
|||||||
prerenderRoutes,
|
prerenderRoutes,
|
||||||
pageTraces,
|
pageTraces,
|
||||||
compressedPages,
|
compressedPages,
|
||||||
|
experimentalPPRRoutes,
|
||||||
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
||||||
initialPseudoLayer,
|
initialPseudoLayer,
|
||||||
lambdaCompressedByteLimit,
|
lambdaCompressedByteLimit,
|
||||||
@@ -859,6 +885,7 @@ export async function serverBuild({
|
|||||||
prerenderRoutes,
|
prerenderRoutes,
|
||||||
pageTraces,
|
pageTraces,
|
||||||
compressedPages,
|
compressedPages,
|
||||||
|
experimentalPPRRoutes: undefined,
|
||||||
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
||||||
initialPseudoLayer,
|
initialPseudoLayer,
|
||||||
lambdaCompressedByteLimit,
|
lambdaCompressedByteLimit,
|
||||||
@@ -868,7 +895,7 @@ export async function serverBuild({
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const group of appRouterLambdaGroups) {
|
for (const group of appRouterLambdaGroups) {
|
||||||
if (!group.isPrerenders) {
|
if (!group.isPrerenders || group.isExperimentalPPR) {
|
||||||
group.isStreaming = true;
|
group.isStreaming = true;
|
||||||
}
|
}
|
||||||
group.isAppRouter = true;
|
group.isAppRouter = true;
|
||||||
@@ -890,6 +917,7 @@ export async function serverBuild({
|
|||||||
prerenderRoutes,
|
prerenderRoutes,
|
||||||
pageTraces,
|
pageTraces,
|
||||||
compressedPages,
|
compressedPages,
|
||||||
|
experimentalPPRRoutes: undefined,
|
||||||
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
||||||
initialPseudoLayer,
|
initialPseudoLayer,
|
||||||
initialPseudoLayerUncompressed: uncompressedInitialSize,
|
initialPseudoLayerUncompressed: uncompressedInitialSize,
|
||||||
@@ -1025,7 +1053,7 @@ export async function serverBuild({
|
|||||||
};
|
};
|
||||||
const operationType = getOperationType({ group, prerenderManifest });
|
const operationType = getOperationType({ group, prerenderManifest });
|
||||||
|
|
||||||
const lambda = await createLambdaFromPseudoLayers({
|
const options: CreateLambdaFromPseudoLayersOptions = {
|
||||||
files: {
|
files: {
|
||||||
...launcherFiles,
|
...launcherFiles,
|
||||||
...updatedManifestFiles,
|
...updatedManifestFiles,
|
||||||
@@ -1041,7 +1069,30 @@ export async function serverBuild({
|
|||||||
maxDuration: group.maxDuration,
|
maxDuration: group.maxDuration,
|
||||||
isStreaming: group.isStreaming,
|
isStreaming: group.isStreaming,
|
||||||
nextVersion,
|
nextVersion,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
const lambda = await createLambdaFromPseudoLayers(options);
|
||||||
|
|
||||||
|
// This is a PPR lambda if it's an App Page with the PPR experimental flag
|
||||||
|
// enabled.
|
||||||
|
const isPPR =
|
||||||
|
experimental.ppr && group.isAppRouter && !group.isAppRouteHandler;
|
||||||
|
|
||||||
|
// If PPR is enabled and this is an App Page, create the non-streaming
|
||||||
|
// lambda for the page for revalidation.
|
||||||
|
let revalidate: NodejsLambda | undefined;
|
||||||
|
if (isPPR) {
|
||||||
|
if (isPPR && !options.isStreaming) {
|
||||||
|
throw new Error("Invariant: PPR lambda isn't streaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the non-streaming version of the same Lambda, this will be
|
||||||
|
// used for revalidation.
|
||||||
|
revalidate = await createLambdaFromPseudoLayers({
|
||||||
|
...options,
|
||||||
|
isStreaming: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const page of group.pages) {
|
for (const page of group.pages) {
|
||||||
const pageNoExt = page.replace(/\.js$/, '');
|
const pageNoExt = page.replace(/\.js$/, '');
|
||||||
@@ -1057,11 +1108,35 @@ export async function serverBuild({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputName = normalizeIndexOutput(
|
let outputName = normalizeIndexOutput(
|
||||||
path.posix.join(entryDirectory, pageNoExt),
|
path.posix.join(entryDirectory, pageNoExt),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If this is a PPR page, then we should prefix the output name.
|
||||||
|
if (isPPR) {
|
||||||
|
if (!revalidate) {
|
||||||
|
throw new Error("Invariant: PPR lambda isn't set");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the get the base path prefixed route, without the index
|
||||||
|
// normalization.
|
||||||
|
outputName = path.posix.join(entryDirectory, pageNoExt);
|
||||||
|
lambdas[outputName] = revalidate;
|
||||||
|
|
||||||
|
const pprOutputName = path.posix.join(
|
||||||
|
entryDirectory,
|
||||||
|
'/_next/postponed/resume',
|
||||||
|
pageNoExt
|
||||||
|
);
|
||||||
|
lambdas[pprOutputName] = lambda;
|
||||||
|
|
||||||
|
// We want to add the `experimentalStreamingLambdaPath` to this
|
||||||
|
// output.
|
||||||
|
experimentalStreamingLambdaPaths.set(outputName, pprOutputName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// we add locale prefixed outputs for SSR pages,
|
// we add locale prefixed outputs for SSR pages,
|
||||||
// this is handled in onPrerenderRoute for SSG pages
|
// this is handled in onPrerenderRoute for SSG pages
|
||||||
if (
|
if (
|
||||||
@@ -1096,6 +1171,7 @@ export async function serverBuild({
|
|||||||
pagesDir,
|
pagesDir,
|
||||||
pageLambdaMap: {},
|
pageLambdaMap: {},
|
||||||
lambdas,
|
lambdas,
|
||||||
|
experimentalStreamingLambdaPaths,
|
||||||
prerenders,
|
prerenders,
|
||||||
entryDirectory,
|
entryDirectory,
|
||||||
routesManifest,
|
routesManifest,
|
||||||
@@ -1111,23 +1187,32 @@ export async function serverBuild({
|
|||||||
isEmptyAllowQueryForPrendered,
|
isEmptyAllowQueryForPrendered,
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.keys(prerenderManifest.staticRoutes).forEach(route =>
|
await Promise.all(
|
||||||
prerenderRoute(route, {})
|
Object.keys(prerenderManifest.staticRoutes).map(route =>
|
||||||
|
prerenderRoute(route, {})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
Object.keys(prerenderManifest.fallbackRoutes).forEach(route =>
|
await Promise.all(
|
||||||
prerenderRoute(route, { isFallback: true })
|
Object.keys(prerenderManifest.fallbackRoutes).map(route =>
|
||||||
|
prerenderRoute(route, { isFallback: true })
|
||||||
|
)
|
||||||
);
|
);
|
||||||
Object.keys(prerenderManifest.blockingFallbackRoutes).forEach(route =>
|
await Promise.all(
|
||||||
prerenderRoute(route, { isBlocking: true })
|
Object.keys(prerenderManifest.blockingFallbackRoutes).map(route =>
|
||||||
|
prerenderRoute(route, { isBlocking: true })
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (static404Page && canUsePreviewMode) {
|
if (static404Page && canUsePreviewMode) {
|
||||||
omittedPrerenderRoutes.forEach(route => {
|
await Promise.all(
|
||||||
prerenderRoute(route, { isOmitted: true });
|
[...omittedPrerenderRoutes].map(route => {
|
||||||
});
|
return prerenderRoute(route, { isOmitted: true });
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
prerenderRoutes.forEach(route => {
|
prerenderRoutes.forEach(route => {
|
||||||
|
if (experimentalPPRRoutes.has(route)) return;
|
||||||
if (routesManifest?.i18n) {
|
if (routesManifest?.i18n) {
|
||||||
route = normalizeLocalePath(route, routesManifest.i18n.locales).pathname;
|
route = normalizeLocalePath(route, routesManifest.i18n.locales).pathname;
|
||||||
}
|
}
|
||||||
@@ -1164,7 +1249,8 @@ export async function serverBuild({
|
|||||||
canUsePreviewMode,
|
canUsePreviewMode,
|
||||||
prerenderManifest.bypassToken || '',
|
prerenderManifest.bypassToken || '',
|
||||||
true,
|
true,
|
||||||
middleware.dynamicRouteMap
|
middleware.dynamicRouteMap,
|
||||||
|
experimental.ppr
|
||||||
).then(arr =>
|
).then(arr =>
|
||||||
localizeDynamicRoutes(
|
localizeDynamicRoutes(
|
||||||
arr,
|
arr,
|
||||||
@@ -1329,22 +1415,24 @@ export async function serverBuild({
|
|||||||
// __rsc__ header is present
|
// __rsc__ header is present
|
||||||
const edgeFunctions = middleware.edgeFunctions;
|
const edgeFunctions = middleware.edgeFunctions;
|
||||||
|
|
||||||
for (let route of Object.values(appPathRoutesManifest)) {
|
for (const route of Object.values(appPathRoutesManifest)) {
|
||||||
const ogRoute = inversedAppPathManifest[route];
|
const ogRoute = inversedAppPathManifest[route];
|
||||||
|
|
||||||
if (ogRoute.endsWith('/route')) {
|
if (ogRoute.endsWith('/route')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
route = normalizeIndexOutput(
|
|
||||||
|
const pathname = normalizeIndexOutput(
|
||||||
path.posix.join('./', entryDirectory, route === '/' ? '/index' : route),
|
path.posix.join('./', entryDirectory, route === '/' ? '/index' : route),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (lambdas[route]) {
|
if (lambdas[pathname]) {
|
||||||
lambdas[`${route}.rsc`] = lambdas[route];
|
lambdas[`${pathname}.rsc`] = lambdas[pathname];
|
||||||
}
|
}
|
||||||
if (edgeFunctions[route]) {
|
|
||||||
edgeFunctions[`${route}.rsc`] = edgeFunctions[route];
|
if (edgeFunctions[pathname]) {
|
||||||
|
edgeFunctions[`${pathname}.rsc`] = edgeFunctions[pathname];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1364,6 +1452,10 @@ export async function serverBuild({
|
|||||||
}))
|
}))
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
if (experimental.ppr && !rscPrefetchHeader) {
|
||||||
|
throw new Error("Invariant: cannot use PPR without 'rsc.prefetchHeader'");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
wildcard: wildcardConfig,
|
wildcard: wildcardConfig,
|
||||||
images: getImagesConfig(imagesManifest),
|
images: getImagesConfig(imagesManifest),
|
||||||
@@ -1718,7 +1810,7 @@ export async function serverBuild({
|
|||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
|
||||||
...(rscPrefetchHeader
|
...(rscPrefetchHeader && !experimental.ppr
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
src: path.posix.join(
|
src: path.posix.join(
|
||||||
@@ -1742,7 +1834,11 @@ export async function serverBuild({
|
|||||||
entryDirectory,
|
entryDirectory,
|
||||||
`/(.+?)${RSC_PREFETCH_SUFFIX}(?:/)?$`
|
`/(.+?)${RSC_PREFETCH_SUFFIX}(?:/)?$`
|
||||||
)}`,
|
)}`,
|
||||||
dest: path.posix.join('/', entryDirectory, '/$1.rsc'),
|
dest: path.posix.join(
|
||||||
|
'/',
|
||||||
|
entryDirectory,
|
||||||
|
`/$1${experimental.ppr ? RSC_PREFETCH_SUFFIX : '.rsc'}`
|
||||||
|
),
|
||||||
has: [
|
has: [
|
||||||
{
|
{
|
||||||
type: 'header',
|
type: 'header',
|
||||||
@@ -1955,8 +2051,6 @@ export async function serverBuild({
|
|||||||
important: true,
|
important: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: remove below workaround when `/` is allowed to be output
|
|
||||||
// different than `/index`
|
|
||||||
{
|
{
|
||||||
src: path.posix.join('/', entryDirectory, '/index'),
|
src: path.posix.join('/', entryDirectory, '/index'),
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -22,25 +22,44 @@ if (process.env.NODE_ENV !== 'production' && region !== 'dev1') {
|
|||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const NextServer = require('__NEXT_SERVER_PATH__').default;
|
const NextServer = require('__NEXT_SERVER_PATH__').default;
|
||||||
|
|
||||||
|
// __NEXT_CONFIG__ value is injected
|
||||||
|
declare const __NEXT_CONFIG__: any;
|
||||||
|
const conf = __NEXT_CONFIG__;
|
||||||
|
|
||||||
const nextServer = new NextServer({
|
const nextServer = new NextServer({
|
||||||
// @ts-ignore __NEXT_CONFIG__ value is injected
|
conf,
|
||||||
conf: __NEXT_CONFIG__,
|
|
||||||
dir: '.',
|
dir: '.',
|
||||||
minimalMode: true,
|
minimalMode: true,
|
||||||
customServer: false,
|
customServer: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const requestHandler = nextServer.getRequestHandler();
|
// Returns a wrapped handler that will crash the lambda if an error isn't
|
||||||
|
// caught.
|
||||||
|
const serve =
|
||||||
|
(handler: any) => async (req: IncomingMessage, res: ServerResponse) => {
|
||||||
|
try {
|
||||||
|
// @preserve entryDirectory handler
|
||||||
|
await handler(req, res);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
// crash the lambda immediately to clean up any bad module state,
|
||||||
|
// this was previously handled in ___vc_bridge on an unhandled rejection
|
||||||
|
// but we can do this quicker by triggering here
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = async (req: IncomingMessage, res: ServerResponse) => {
|
// The default handler method should be exported as a function on the module.
|
||||||
try {
|
module.exports = serve(nextServer.getRequestHandler());
|
||||||
// @preserve entryDirectory handler
|
|
||||||
await requestHandler(req, res);
|
// If available, add `getRequestHandlerWithMetadata` to the export if it's
|
||||||
} catch (err) {
|
// required by the configuration.
|
||||||
console.error(err);
|
if (
|
||||||
// crash the lambda immediately to clean up any bad module state,
|
conf.experimental?.ppr &&
|
||||||
// this was previously handled in ___vc_bridge on an unhandled rejection
|
'getRequestHandlerWithMetadata' in nextServer &&
|
||||||
// but we can do this quicker by triggering here
|
typeof nextServer.getRequestHandlerWithMetadata === 'function'
|
||||||
process.exit(1);
|
) {
|
||||||
}
|
module.exports.getRequestHandlerWithMetadata = (metadata: any) =>
|
||||||
};
|
serve(nextServer.getRequestHandlerWithMetadata(metadata));
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
NodejsLambda,
|
NodejsLambda,
|
||||||
EdgeFunction,
|
EdgeFunction,
|
||||||
Images,
|
Images,
|
||||||
|
File,
|
||||||
} from '@vercel/build-utils';
|
} from '@vercel/build-utils';
|
||||||
import { NodeFileTraceReasons } from '@vercel/nft';
|
import { NodeFileTraceReasons } from '@vercel/nft';
|
||||||
import type {
|
import type {
|
||||||
@@ -244,6 +245,7 @@ type RoutesManifestOld = {
|
|||||||
header: string;
|
header: string;
|
||||||
varyHeader: string;
|
varyHeader: string;
|
||||||
prefetchHeader?: string;
|
prefetchHeader?: string;
|
||||||
|
didPostponeHeader?: string;
|
||||||
contentTypeHeader: string;
|
contentTypeHeader: string;
|
||||||
};
|
};
|
||||||
skipMiddlewareUrlNormalize?: boolean;
|
skipMiddlewareUrlNormalize?: boolean;
|
||||||
@@ -312,7 +314,8 @@ export async function getDynamicRoutes(
|
|||||||
canUsePreviewMode?: boolean,
|
canUsePreviewMode?: boolean,
|
||||||
bypassToken?: string,
|
bypassToken?: string,
|
||||||
isServerMode?: boolean,
|
isServerMode?: boolean,
|
||||||
dynamicMiddlewareRouteMap?: Map<string, RouteWithSrc>
|
dynamicMiddlewareRouteMap?: Map<string, RouteWithSrc>,
|
||||||
|
experimentalPPR?: boolean
|
||||||
): Promise<RouteWithSrc[]> {
|
): Promise<RouteWithSrc[]> {
|
||||||
if (routesManifest) {
|
if (routesManifest) {
|
||||||
switch (routesManifest.version) {
|
switch (routesManifest.version) {
|
||||||
@@ -385,6 +388,24 @@ export async function getDynamicRoutes(
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (experimentalPPR) {
|
||||||
|
let dest = route.dest?.replace(/($|\?)/, '.prefetch.rsc$1');
|
||||||
|
|
||||||
|
if (page === '/' || page === '/index') {
|
||||||
|
dest = dest?.replace(/([^/]+\.prefetch\.rsc(\?.*|$))/, '__$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
routes.push({
|
||||||
|
...route,
|
||||||
|
src: route.src.replace(
|
||||||
|
new RegExp(escapeStringRegexp('(?:/)?$')),
|
||||||
|
'(?:\\.prefetch\\.rsc)(?:/)?$'
|
||||||
|
),
|
||||||
|
dest,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
routes.push({
|
routes.push({
|
||||||
...route,
|
...route,
|
||||||
src: route.src.replace(
|
src: route.src.replace(
|
||||||
@@ -395,8 +416,8 @@ export async function getDynamicRoutes(
|
|||||||
});
|
});
|
||||||
|
|
||||||
routes.push(route);
|
routes.push(route);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return routes;
|
return routes;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@@ -778,7 +799,8 @@ export async function createPseudoLayer(files: {
|
|||||||
return { pseudoLayer, pseudoLayerBytes };
|
return { pseudoLayer, pseudoLayerBytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateLambdaFromPseudoLayersOptions extends LambdaOptionsWithFiles {
|
export interface CreateLambdaFromPseudoLayersOptions
|
||||||
|
extends LambdaOptionsWithFiles {
|
||||||
layers: PseudoLayer[];
|
layers: PseudoLayer[];
|
||||||
isStreaming?: boolean;
|
isStreaming?: boolean;
|
||||||
nextVersion?: string;
|
nextVersion?: string;
|
||||||
@@ -858,10 +880,12 @@ export type NextPrerenderedRoutes = {
|
|||||||
[route: string]: {
|
[route: string]: {
|
||||||
initialRevalidate: number | false;
|
initialRevalidate: number | false;
|
||||||
dataRoute: string | null;
|
dataRoute: string | null;
|
||||||
|
prefetchDataRoute?: string | null;
|
||||||
srcRoute: string | null;
|
srcRoute: string | null;
|
||||||
initialStatus?: number;
|
initialStatus?: number;
|
||||||
initialHeaders?: Record<string, string>;
|
initialHeaders?: Record<string, string>;
|
||||||
experimentalBypassFor?: HasField;
|
experimentalBypassFor?: HasField;
|
||||||
|
experimentalPPR?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -870,7 +894,10 @@ export type NextPrerenderedRoutes = {
|
|||||||
routeRegex: string;
|
routeRegex: string;
|
||||||
dataRoute: string | null;
|
dataRoute: string | null;
|
||||||
dataRouteRegex: string | null;
|
dataRouteRegex: string | null;
|
||||||
|
prefetchDataRoute?: string | null;
|
||||||
|
prefetchDataRouteRegex?: string | null;
|
||||||
experimentalBypassFor?: HasField;
|
experimentalBypassFor?: HasField;
|
||||||
|
experimentalPPR?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -880,7 +907,10 @@ export type NextPrerenderedRoutes = {
|
|||||||
routeRegex: string;
|
routeRegex: string;
|
||||||
dataRoute: string | null;
|
dataRoute: string | null;
|
||||||
dataRouteRegex: string | null;
|
dataRouteRegex: string | null;
|
||||||
|
prefetchDataRoute?: string | null;
|
||||||
|
prefetchDataRouteRegex?: string | null;
|
||||||
experimentalBypassFor?: HasField;
|
experimentalBypassFor?: HasField;
|
||||||
|
experimentalPPR?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -889,7 +919,10 @@ export type NextPrerenderedRoutes = {
|
|||||||
routeRegex: string;
|
routeRegex: string;
|
||||||
dataRoute: string | null;
|
dataRoute: string | null;
|
||||||
dataRouteRegex: string | null;
|
dataRouteRegex: string | null;
|
||||||
|
prefetchDataRoute: string | null | undefined;
|
||||||
|
prefetchDataRouteRegex: string | null | undefined;
|
||||||
experimentalBypassFor?: HasField;
|
experimentalBypassFor?: HasField;
|
||||||
|
experimentalPPR?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1091,9 +1124,11 @@ export async function getPrerenderManifest(
|
|||||||
initialRevalidateSeconds: number | false;
|
initialRevalidateSeconds: number | false;
|
||||||
srcRoute: string | null;
|
srcRoute: string | null;
|
||||||
dataRoute: string | null;
|
dataRoute: string | null;
|
||||||
|
prefetchDataRoute: string | null | undefined;
|
||||||
initialStatus?: number;
|
initialStatus?: number;
|
||||||
initialHeaders?: Record<string, string>;
|
initialHeaders?: Record<string, string>;
|
||||||
experimentalBypassFor?: HasField;
|
experimentalBypassFor?: HasField;
|
||||||
|
experimentalPPR?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
dynamicRoutes: {
|
dynamicRoutes: {
|
||||||
@@ -1102,7 +1137,10 @@ export async function getPrerenderManifest(
|
|||||||
fallback: string | false;
|
fallback: string | false;
|
||||||
dataRoute: string | null;
|
dataRoute: string | null;
|
||||||
dataRouteRegex: string | null;
|
dataRouteRegex: string | null;
|
||||||
|
prefetchDataRoute: string | null | undefined;
|
||||||
|
prefetchDataRouteRegex: string | null | undefined;
|
||||||
experimentalBypassFor?: HasField;
|
experimentalBypassFor?: HasField;
|
||||||
|
experimentalPPR?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
preview: {
|
preview: {
|
||||||
@@ -1189,11 +1227,15 @@ export async function getPrerenderManifest(
|
|||||||
let initialStatus: undefined | number;
|
let initialStatus: undefined | number;
|
||||||
let initialHeaders: undefined | Record<string, string>;
|
let initialHeaders: undefined | Record<string, string>;
|
||||||
let experimentalBypassFor: undefined | HasField;
|
let experimentalBypassFor: undefined | HasField;
|
||||||
|
let experimentalPPR: undefined | boolean;
|
||||||
|
let prefetchDataRoute: undefined | string | null;
|
||||||
|
|
||||||
if (manifest.version === 4) {
|
if (manifest.version === 4) {
|
||||||
initialStatus = manifest.routes[route].initialStatus;
|
initialStatus = manifest.routes[route].initialStatus;
|
||||||
initialHeaders = manifest.routes[route].initialHeaders;
|
initialHeaders = manifest.routes[route].initialHeaders;
|
||||||
experimentalBypassFor = manifest.routes[route].experimentalBypassFor;
|
experimentalBypassFor = manifest.routes[route].experimentalBypassFor;
|
||||||
|
experimentalPPR = manifest.routes[route].experimentalPPR;
|
||||||
|
prefetchDataRoute = manifest.routes[route].prefetchDataRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.staticRoutes[route] = {
|
ret.staticRoutes[route] = {
|
||||||
@@ -1202,10 +1244,12 @@ export async function getPrerenderManifest(
|
|||||||
? false
|
? false
|
||||||
: Math.max(1, initialRevalidateSeconds),
|
: Math.max(1, initialRevalidateSeconds),
|
||||||
dataRoute,
|
dataRoute,
|
||||||
|
prefetchDataRoute,
|
||||||
srcRoute,
|
srcRoute,
|
||||||
initialStatus,
|
initialStatus,
|
||||||
initialHeaders,
|
initialHeaders,
|
||||||
experimentalBypassFor,
|
experimentalBypassFor,
|
||||||
|
experimentalPPR,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1213,35 +1257,52 @@ export async function getPrerenderManifest(
|
|||||||
const { routeRegex, fallback, dataRoute, dataRouteRegex } =
|
const { routeRegex, fallback, dataRoute, dataRouteRegex } =
|
||||||
manifest.dynamicRoutes[lazyRoute];
|
manifest.dynamicRoutes[lazyRoute];
|
||||||
let experimentalBypassFor: undefined | HasField;
|
let experimentalBypassFor: undefined | HasField;
|
||||||
|
let experimentalPPR: undefined | boolean;
|
||||||
|
let prefetchDataRoute: undefined | string | null;
|
||||||
|
let prefetchDataRouteRegex: undefined | string | null;
|
||||||
|
|
||||||
if (manifest.version === 4) {
|
if (manifest.version === 4) {
|
||||||
experimentalBypassFor =
|
experimentalBypassFor =
|
||||||
manifest.dynamicRoutes[lazyRoute].experimentalBypassFor;
|
manifest.dynamicRoutes[lazyRoute].experimentalBypassFor;
|
||||||
|
experimentalPPR = manifest.dynamicRoutes[lazyRoute].experimentalPPR;
|
||||||
|
prefetchDataRoute =
|
||||||
|
manifest.dynamicRoutes[lazyRoute].prefetchDataRoute;
|
||||||
|
prefetchDataRouteRegex =
|
||||||
|
manifest.dynamicRoutes[lazyRoute].prefetchDataRouteRegex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof fallback === 'string') {
|
if (typeof fallback === 'string') {
|
||||||
ret.fallbackRoutes[lazyRoute] = {
|
ret.fallbackRoutes[lazyRoute] = {
|
||||||
experimentalBypassFor,
|
experimentalBypassFor,
|
||||||
|
experimentalPPR,
|
||||||
routeRegex,
|
routeRegex,
|
||||||
fallback,
|
fallback,
|
||||||
dataRoute,
|
dataRoute,
|
||||||
dataRouteRegex,
|
dataRouteRegex,
|
||||||
|
prefetchDataRoute,
|
||||||
|
prefetchDataRouteRegex,
|
||||||
};
|
};
|
||||||
} else if (fallback === null) {
|
} else if (fallback === null) {
|
||||||
ret.blockingFallbackRoutes[lazyRoute] = {
|
ret.blockingFallbackRoutes[lazyRoute] = {
|
||||||
experimentalBypassFor,
|
experimentalBypassFor,
|
||||||
|
experimentalPPR,
|
||||||
routeRegex,
|
routeRegex,
|
||||||
dataRoute,
|
dataRoute,
|
||||||
dataRouteRegex,
|
dataRouteRegex,
|
||||||
|
prefetchDataRoute,
|
||||||
|
prefetchDataRouteRegex,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// Fallback behavior is disabled, all routes would've been provided
|
// Fallback behavior is disabled, all routes would've been provided
|
||||||
// in the top-level `routes` key (`staticRoutes`).
|
// in the top-level `routes` key (`staticRoutes`).
|
||||||
ret.omittedRoutes[lazyRoute] = {
|
ret.omittedRoutes[lazyRoute] = {
|
||||||
experimentalBypassFor,
|
experimentalBypassFor,
|
||||||
|
experimentalPPR,
|
||||||
routeRegex,
|
routeRegex,
|
||||||
dataRoute,
|
dataRoute,
|
||||||
dataRouteRegex,
|
dataRouteRegex,
|
||||||
|
prefetchDataRoute,
|
||||||
|
prefetchDataRouteRegex,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1417,6 +1478,7 @@ export type LambdaGroup = {
|
|||||||
isAppRouteHandler?: boolean;
|
isAppRouteHandler?: boolean;
|
||||||
isStreaming?: boolean;
|
isStreaming?: boolean;
|
||||||
isPrerenders?: boolean;
|
isPrerenders?: boolean;
|
||||||
|
isExperimentalPPR?: boolean;
|
||||||
isPages?: boolean;
|
isPages?: boolean;
|
||||||
isApiLambda: boolean;
|
isApiLambda: boolean;
|
||||||
pseudoLayer: PseudoLayer;
|
pseudoLayer: PseudoLayer;
|
||||||
@@ -1430,6 +1492,7 @@ export async function getPageLambdaGroups({
|
|||||||
functionsConfigManifest,
|
functionsConfigManifest,
|
||||||
pages,
|
pages,
|
||||||
prerenderRoutes,
|
prerenderRoutes,
|
||||||
|
experimentalPPRRoutes,
|
||||||
pageTraces,
|
pageTraces,
|
||||||
compressedPages,
|
compressedPages,
|
||||||
tracedPseudoLayer,
|
tracedPseudoLayer,
|
||||||
@@ -1444,6 +1507,7 @@ export async function getPageLambdaGroups({
|
|||||||
functionsConfigManifest?: FunctionsConfigManifestV1;
|
functionsConfigManifest?: FunctionsConfigManifestV1;
|
||||||
pages: string[];
|
pages: string[];
|
||||||
prerenderRoutes: Set<string>;
|
prerenderRoutes: Set<string>;
|
||||||
|
experimentalPPRRoutes: Set<string> | undefined;
|
||||||
pageTraces: {
|
pageTraces: {
|
||||||
[page: string]: {
|
[page: string]: {
|
||||||
[key: string]: FileFsRef;
|
[key: string]: FileFsRef;
|
||||||
@@ -1465,6 +1529,7 @@ export async function getPageLambdaGroups({
|
|||||||
const newPages = [...internalPages, page];
|
const newPages = [...internalPages, page];
|
||||||
const routeName = normalizePage(page.replace(/\.js$/, ''));
|
const routeName = normalizePage(page.replace(/\.js$/, ''));
|
||||||
const isPrerenderRoute = prerenderRoutes.has(routeName);
|
const isPrerenderRoute = prerenderRoutes.has(routeName);
|
||||||
|
const isExperimentalPPR = experimentalPPRRoutes?.has(routeName) ?? false;
|
||||||
|
|
||||||
let opts: { memory?: number; maxDuration?: number } = {};
|
let opts: { memory?: number; maxDuration?: number } = {};
|
||||||
|
|
||||||
@@ -1494,7 +1559,8 @@ export async function getPageLambdaGroups({
|
|||||||
const matches =
|
const matches =
|
||||||
group.maxDuration === opts.maxDuration &&
|
group.maxDuration === opts.maxDuration &&
|
||||||
group.memory === opts.memory &&
|
group.memory === opts.memory &&
|
||||||
group.isPrerenders === isPrerenderRoute;
|
group.isPrerenders === isPrerenderRoute &&
|
||||||
|
group.isExperimentalPPR === isExperimentalPPR;
|
||||||
|
|
||||||
if (matches) {
|
if (matches) {
|
||||||
let newTracedFilesSize = group.pseudoLayerBytes;
|
let newTracedFilesSize = group.pseudoLayerBytes;
|
||||||
@@ -1533,6 +1599,7 @@ export async function getPageLambdaGroups({
|
|||||||
pages: [page],
|
pages: [page],
|
||||||
...opts,
|
...opts,
|
||||||
isPrerenders: isPrerenderRoute,
|
isPrerenders: isPrerenderRoute,
|
||||||
|
isExperimentalPPR,
|
||||||
isApiLambda: !!isApiPage(page),
|
isApiLambda: !!isApiPage(page),
|
||||||
pseudoLayerBytes: initialPseudoLayer.pseudoLayerBytes,
|
pseudoLayerBytes: initialPseudoLayer.pseudoLayerBytes,
|
||||||
pseudoLayerUncompressedBytes: initialPseudoLayerUncompressed,
|
pseudoLayerUncompressedBytes: initialPseudoLayerUncompressed,
|
||||||
@@ -1831,7 +1898,8 @@ type OnPrerenderRouteArgs = {
|
|||||||
isServerMode: boolean;
|
isServerMode: boolean;
|
||||||
canUsePreviewMode: boolean;
|
canUsePreviewMode: boolean;
|
||||||
lambdas: { [key: string]: Lambda };
|
lambdas: { [key: string]: Lambda };
|
||||||
prerenders: { [key: string]: Prerender | FileFsRef };
|
experimentalStreamingLambdaPaths: Map<string, string> | undefined;
|
||||||
|
prerenders: { [key: string]: Prerender | File };
|
||||||
pageLambdaMap: { [key: string]: string };
|
pageLambdaMap: { [key: string]: string };
|
||||||
routesManifest?: RoutesManifest;
|
routesManifest?: RoutesManifest;
|
||||||
isCorrectNotFoundRoutes?: boolean;
|
isCorrectNotFoundRoutes?: boolean;
|
||||||
@@ -1841,7 +1909,7 @@ let prerenderGroup = 1;
|
|||||||
|
|
||||||
export const onPrerenderRoute =
|
export const onPrerenderRoute =
|
||||||
(prerenderRouteArgs: OnPrerenderRouteArgs) =>
|
(prerenderRouteArgs: OnPrerenderRouteArgs) =>
|
||||||
(
|
async (
|
||||||
routeKey: string,
|
routeKey: string,
|
||||||
{
|
{
|
||||||
isBlocking,
|
isBlocking,
|
||||||
@@ -1866,6 +1934,7 @@ export const onPrerenderRoute =
|
|||||||
isServerMode,
|
isServerMode,
|
||||||
canUsePreviewMode,
|
canUsePreviewMode,
|
||||||
lambdas,
|
lambdas,
|
||||||
|
experimentalStreamingLambdaPaths,
|
||||||
prerenders,
|
prerenders,
|
||||||
pageLambdaMap,
|
pageLambdaMap,
|
||||||
routesManifest,
|
routesManifest,
|
||||||
@@ -1926,9 +1995,11 @@ export const onPrerenderRoute =
|
|||||||
let initialRevalidate: false | number;
|
let initialRevalidate: false | number;
|
||||||
let srcRoute: string | null;
|
let srcRoute: string | null;
|
||||||
let dataRoute: string | null;
|
let dataRoute: string | null;
|
||||||
|
let prefetchDataRoute: string | null | undefined;
|
||||||
let initialStatus: number | undefined;
|
let initialStatus: number | undefined;
|
||||||
let initialHeaders: Record<string, string> | undefined;
|
let initialHeaders: Record<string, string> | undefined;
|
||||||
let experimentalBypassFor: HasField | undefined;
|
let experimentalBypassFor: HasField | undefined;
|
||||||
|
let experimentalPPR: boolean | undefined;
|
||||||
|
|
||||||
if (isFallback || isBlocking) {
|
if (isFallback || isBlocking) {
|
||||||
const pr = isFallback
|
const pr = isFallback
|
||||||
@@ -1946,12 +2017,18 @@ export const onPrerenderRoute =
|
|||||||
srcRoute = null;
|
srcRoute = null;
|
||||||
dataRoute = pr.dataRoute;
|
dataRoute = pr.dataRoute;
|
||||||
experimentalBypassFor = pr.experimentalBypassFor;
|
experimentalBypassFor = pr.experimentalBypassFor;
|
||||||
|
experimentalPPR = pr.experimentalPPR;
|
||||||
|
prefetchDataRoute = pr.prefetchDataRoute;
|
||||||
} else if (isOmitted) {
|
} else if (isOmitted) {
|
||||||
initialRevalidate = false;
|
initialRevalidate = false;
|
||||||
srcRoute = routeKey;
|
srcRoute = routeKey;
|
||||||
dataRoute = prerenderManifest.omittedRoutes[routeKey].dataRoute;
|
dataRoute = prerenderManifest.omittedRoutes[routeKey].dataRoute;
|
||||||
experimentalBypassFor =
|
experimentalBypassFor =
|
||||||
prerenderManifest.omittedRoutes[routeKey].experimentalBypassFor;
|
prerenderManifest.omittedRoutes[routeKey].experimentalBypassFor;
|
||||||
|
experimentalPPR =
|
||||||
|
prerenderManifest.omittedRoutes[routeKey].experimentalPPR;
|
||||||
|
prefetchDataRoute =
|
||||||
|
prerenderManifest.omittedRoutes[routeKey].prefetchDataRoute;
|
||||||
} else {
|
} else {
|
||||||
const pr = prerenderManifest.staticRoutes[routeKey];
|
const pr = prerenderManifest.staticRoutes[routeKey];
|
||||||
({
|
({
|
||||||
@@ -1961,19 +2038,71 @@ export const onPrerenderRoute =
|
|||||||
initialHeaders,
|
initialHeaders,
|
||||||
initialStatus,
|
initialStatus,
|
||||||
experimentalBypassFor,
|
experimentalBypassFor,
|
||||||
|
experimentalPPR,
|
||||||
|
prefetchDataRoute,
|
||||||
} = pr);
|
} = pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
let isAppPathRoute = false;
|
let isAppPathRoute = false;
|
||||||
|
|
||||||
// TODO: leverage manifest to determine app paths more accurately
|
// TODO: leverage manifest to determine app paths more accurately
|
||||||
if (appDir && srcRoute && (!dataRoute || dataRoute?.endsWith('.rsc'))) {
|
if (appDir && srcRoute && (!dataRoute || dataRoute?.endsWith('.rsc'))) {
|
||||||
isAppPathRoute = true;
|
isAppPathRoute = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isOmittedOrNotFound = isOmitted || isNotFound;
|
const isOmittedOrNotFound = isOmitted || isNotFound;
|
||||||
let htmlFsRef: FileFsRef | null;
|
let htmlFsRef: File | null;
|
||||||
|
|
||||||
if (appDir && !dataRoute && isAppPathRoute && !(isBlocking || isFallback)) {
|
// If enabled, try to get the postponed route information from the file
|
||||||
|
// system and use it to assemble the prerender.
|
||||||
|
let prerender: string | undefined;
|
||||||
|
if (experimentalPPR && appDir) {
|
||||||
|
const htmlPath = path.join(appDir, `${routeFileNoExt}.html`);
|
||||||
|
const metaPath = path.join(appDir, `${routeFileNoExt}.meta`);
|
||||||
|
if (fs.existsSync(htmlPath) && fs.existsSync(metaPath)) {
|
||||||
|
const meta = JSON.parse(await fs.readFile(metaPath, 'utf8'));
|
||||||
|
if ('postponed' in meta && typeof meta.postponed === 'string') {
|
||||||
|
prerender = meta.postponed;
|
||||||
|
|
||||||
|
// Assign the headers Content-Type header to the prerendered type.
|
||||||
|
initialHeaders ??= {};
|
||||||
|
initialHeaders[
|
||||||
|
'content-type'
|
||||||
|
] = `application/x-nextjs-pre-render; state-length=${meta.postponed.length}`;
|
||||||
|
|
||||||
|
// Read the HTML file and append it to the prerendered content.
|
||||||
|
const html = await fs.readFileSync(htmlPath, 'utf8');
|
||||||
|
prerender += html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataRoute?.endsWith('.rsc')) {
|
||||||
|
throw new Error(
|
||||||
|
`Invariant: unexpected output path for ${dataRoute} and PPR`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prefetchDataRoute?.endsWith('.prefetch.rsc')) {
|
||||||
|
throw new Error(
|
||||||
|
`Invariant: unexpected output path for ${prefetchDataRoute} and PPR`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prerender) {
|
||||||
|
const contentType = initialHeaders?.['content-type'];
|
||||||
|
if (!contentType) {
|
||||||
|
throw new Error("Invariant: contentType can't be undefined");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble the prerendered file.
|
||||||
|
htmlFsRef = new FileBlob({ contentType, data: prerender });
|
||||||
|
} else if (
|
||||||
|
appDir &&
|
||||||
|
!dataRoute &&
|
||||||
|
isAppPathRoute &&
|
||||||
|
!(isBlocking || isFallback)
|
||||||
|
) {
|
||||||
const contentType = initialHeaders?.['content-type'];
|
const contentType = initialHeaders?.['content-type'];
|
||||||
htmlFsRef = new FileFsRef({
|
htmlFsRef = new FileFsRef({
|
||||||
fsPath: path.join(appDir, `${routeFileNoExt}.body`),
|
fsPath: path.join(appDir, `${routeFileNoExt}.body`),
|
||||||
@@ -2023,7 +2152,7 @@ export const onPrerenderRoute =
|
|||||||
? addLocaleOrDefault('/404.html', routesManifest, locale)
|
? addLocaleOrDefault('/404.html', routesManifest, locale)
|
||||||
: '/404.html'
|
: '/404.html'
|
||||||
: isAppPathRoute
|
: isAppPathRoute
|
||||||
? dataRoute
|
? prefetchDataRoute || dataRoute
|
||||||
: routeFileNoExt + '.json'
|
: routeFileNoExt + '.json'
|
||||||
}`
|
}`
|
||||||
),
|
),
|
||||||
@@ -2054,13 +2183,12 @@ export const onPrerenderRoute =
|
|||||||
);
|
);
|
||||||
|
|
||||||
let lambda: undefined | Lambda;
|
let lambda: undefined | Lambda;
|
||||||
let outputPathData: null | string = null;
|
|
||||||
|
|
||||||
if (dataRoute) {
|
function normalizeDataRoute(route: string) {
|
||||||
outputPathData = path.posix.join(entryDirectory, dataRoute);
|
let normalized = path.posix.join(entryDirectory, route);
|
||||||
|
|
||||||
if (nonDynamicSsg || isFallback || isOmitted) {
|
if (nonDynamicSsg || isFallback || isOmitted) {
|
||||||
outputPathData = outputPathData.replace(
|
normalized = normalized.replace(
|
||||||
new RegExp(`${escapeStringRegexp(origRouteFileNoExt)}.json$`),
|
new RegExp(`${escapeStringRegexp(origRouteFileNoExt)}.json$`),
|
||||||
// ensure we escape "$" correctly while replacing as "$" is a special
|
// ensure we escape "$" correctly while replacing as "$" is a special
|
||||||
// character, we need to do double escaping as first is for the initial
|
// character, we need to do double escaping as first is for the initial
|
||||||
@@ -2068,8 +2196,32 @@ export const onPrerenderRoute =
|
|||||||
`${routeFileNoExt.replace(/\$/g, '$$$$')}.json`
|
`${routeFileNoExt.replace(/\$/g, '$$$$')}.json`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let outputPathData: null | string = null;
|
||||||
|
if (dataRoute) {
|
||||||
|
outputPathData = normalizeDataRoute(dataRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
let outputPathPrefetchData: null | string = null;
|
||||||
|
if (prefetchDataRoute) {
|
||||||
|
if (!experimentalPPR) {
|
||||||
|
throw new Error(
|
||||||
|
"Invariant: prefetchDataRoute can't be set without PPR"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
outputPathPrefetchData = normalizeDataRoute(prefetchDataRoute);
|
||||||
|
} else if (experimentalPPR) {
|
||||||
|
throw new Error('Invariant: expected to find prefetch data route PPR');
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the prefetch data path is available, use it for the prerender,
|
||||||
|
// otherwise use the data path.
|
||||||
|
const outputPrerenderPathData = outputPathPrefetchData || outputPathData;
|
||||||
|
|
||||||
if (isSharedLambdas) {
|
if (isSharedLambdas) {
|
||||||
const outputSrcPathPage = normalizeIndexOutput(
|
const outputSrcPathPage = normalizeIndexOutput(
|
||||||
path.join(
|
path.join(
|
||||||
@@ -2117,8 +2269,8 @@ export const onPrerenderRoute =
|
|||||||
htmlFsRef.contentType = htmlContentType;
|
htmlFsRef.contentType = htmlContentType;
|
||||||
prerenders[outputPathPage] = htmlFsRef;
|
prerenders[outputPathPage] = htmlFsRef;
|
||||||
|
|
||||||
if (outputPathData) {
|
if (outputPrerenderPathData) {
|
||||||
prerenders[outputPathData] = jsonFsRef;
|
prerenders[outputPrerenderPathData] = jsonFsRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2188,12 +2340,32 @@ export const onPrerenderRoute =
|
|||||||
'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
|
'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
|
||||||
const rscContentTypeHeader =
|
const rscContentTypeHeader =
|
||||||
routesManifest?.rsc?.contentTypeHeader || RSC_CONTENT_TYPE;
|
routesManifest?.rsc?.contentTypeHeader || RSC_CONTENT_TYPE;
|
||||||
|
const rscDidPostponeHeader = routesManifest?.rsc?.didPostponeHeader;
|
||||||
|
|
||||||
let sourcePath: string | undefined;
|
let sourcePath: string | undefined;
|
||||||
if (`/${outputPathPage}` !== srcRoute && srcRoute) {
|
if (`/${outputPathPage}` !== srcRoute && srcRoute) {
|
||||||
sourcePath = srcRoute;
|
sourcePath = srcRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The `experimentalStreamingLambdaPaths` stores the page without the
|
||||||
|
// leading `/` and with the `/` rewritten to be `index`. We should
|
||||||
|
// normalize the key so that it matches that key in the map.
|
||||||
|
let key = srcRoute || routeKey;
|
||||||
|
if (key === '/') {
|
||||||
|
key = 'index';
|
||||||
|
} else {
|
||||||
|
if (!key.startsWith('/')) {
|
||||||
|
throw new Error("Invariant: key doesn't start with /");
|
||||||
|
}
|
||||||
|
|
||||||
|
key = key.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
key = path.posix.join(entryDirectory, key);
|
||||||
|
|
||||||
|
const experimentalStreamingLambdaPath =
|
||||||
|
experimentalStreamingLambdaPaths?.get(key);
|
||||||
|
|
||||||
prerenders[outputPathPage] = new Prerender({
|
prerenders[outputPathPage] = new Prerender({
|
||||||
expiration: initialRevalidate,
|
expiration: initialRevalidate,
|
||||||
lambda,
|
lambda,
|
||||||
@@ -2205,6 +2377,7 @@ export const onPrerenderRoute =
|
|||||||
initialStatus,
|
initialStatus,
|
||||||
initialHeaders,
|
initialHeaders,
|
||||||
sourcePath,
|
sourcePath,
|
||||||
|
experimentalStreamingLambdaPath,
|
||||||
|
|
||||||
...(isNotFound
|
...(isNotFound
|
||||||
? {
|
? {
|
||||||
@@ -2222,8 +2395,21 @@ export const onPrerenderRoute =
|
|||||||
: {}),
|
: {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (outputPathData) {
|
if (outputPrerenderPathData) {
|
||||||
prerenders[outputPathData] = new Prerender({
|
let normalizedPathData = outputPrerenderPathData;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(srcRoute === '/' || srcRoute == '/index') &&
|
||||||
|
outputPrerenderPathData.endsWith(RSC_PREFETCH_SUFFIX)
|
||||||
|
) {
|
||||||
|
delete lambdas[normalizedPathData];
|
||||||
|
normalizedPathData = normalizedPathData.replace(
|
||||||
|
/([^/]+\.prefetch\.rsc)$/,
|
||||||
|
'__$1'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
prerenders[normalizedPathData] = new Prerender({
|
||||||
expiration: initialRevalidate,
|
expiration: initialRevalidate,
|
||||||
lambda,
|
lambda,
|
||||||
allowQuery,
|
allowQuery,
|
||||||
@@ -2243,6 +2429,9 @@ export const onPrerenderRoute =
|
|||||||
initialHeaders: {
|
initialHeaders: {
|
||||||
'content-type': rscContentTypeHeader,
|
'content-type': rscContentTypeHeader,
|
||||||
vary: rscVaryHeader,
|
vary: rscVaryHeader,
|
||||||
|
...(experimentalPPR && rscDidPostponeHeader
|
||||||
|
? { [rscDidPostponeHeader]: '1' }
|
||||||
|
: {}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
afterAll(() => fs.remove(fixtureDir));
|
afterAll(() => fs.remove(fixtureDir));
|
||||||
|
|
||||||
it('should deploy and pass probe checks', async () => {
|
it('should deploy and pass probe checks', async () => {
|
||||||
await fs.copy(path.join(__dirname, '../00-app-dir'), fixtureDir);
|
await fs.copy(path.join(__dirname, '../00-app-dir-no-ppr'), fixtureDir);
|
||||||
const nextConfigPath = path.join(fixtureDir, 'next.config.js');
|
const nextConfigPath = path.join(fixtureDir, 'next.config.js');
|
||||||
|
|
||||||
await fs.writeFile(
|
await fs.writeFile(
|
||||||
|
|||||||
8
packages/next/test/fixtures/00-app-dir-no-ppr/package.json
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir-no-ppr/package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"next": "13.5.6",
|
||||||
|
"react": "experimental",
|
||||||
|
"react-dom": "experimental"
|
||||||
|
},
|
||||||
|
"ignoreNextjsUpdates": true
|
||||||
|
}
|
||||||
9
packages/next/test/fixtures/00-app-dir-ppr/app/(newroot)/dashboard/another-edge/page.js
vendored
Normal file
9
packages/next/test/fixtures/00-app-dir-ppr/app/(newroot)/dashboard/another-edge/page.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export const runtime = 'experimental-edge'
|
||||||
|
|
||||||
|
export default function AnotherPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from newroot/dashboard/another</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/(newroot)/dashboard/another/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/(newroot)/dashboard/another/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function AnotherPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from newroot/dashboard/another</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
packages/next/test/fixtures/00-app-dir-ppr/app/(newroot)/layout.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir-ppr/app/(newroot)/layout.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default function Root({ children }) {
|
||||||
|
return (
|
||||||
|
<html className="this-is-another-document-html">
|
||||||
|
<head>
|
||||||
|
<title>{`hello world`}</title>
|
||||||
|
</head>
|
||||||
|
<body className="this-is-another-document-body">{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/(rootonly)/dashboard/changelog/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/(rootonly)/dashboard/changelog/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function ChangelogPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/changelog</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
packages/next/test/fixtures/00-app-dir-ppr/app/(rootonly)/dashboard/hello/page.js
vendored
Normal file
9
packages/next/test/fixtures/00-app-dir-ppr/app/(rootonly)/dashboard/hello/page.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
export default function HelloPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/rootonly/hello</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
4
packages/next/test/fixtures/00-app-dir-ppr/app/api/hello-again/route.js
vendored
Normal file
4
packages/next/test/fixtures/00-app-dir-ppr/app/api/hello-again/route.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const GET = req => {
|
||||||
|
console.log(req.url);
|
||||||
|
return new Response('hello world');
|
||||||
|
};
|
||||||
16
packages/next/test/fixtures/00-app-dir-ppr/app/catch-all/[[...slug]]/page.js
vendored
Normal file
16
packages/next/test/fixtures/00-app-dir-ppr/app/catch-all/[[...slug]]/page.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export default function Page(props) {
|
||||||
|
return (
|
||||||
|
<p>catch-all {JSON.stringify(props.params || {})}</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
slug: ['']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: ['first']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
20
packages/next/test/fixtures/00-app-dir-ppr/app/client-component-route/page.js
vendored
Normal file
20
packages/next/test/fixtures/00-app-dir-ppr/app/client-component-route/page.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import style from './style.module.css';
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
|
export default function ClientComponentRoute() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
useEffect(() => {
|
||||||
|
setCount(1);
|
||||||
|
}, [count]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className={style.red}>
|
||||||
|
hello from app/client-component-route. <b>count: {count}</b>
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-component-route/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-component-route/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
b {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-component-route/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-component-route/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.red {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
20
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/layout.js
vendored
Normal file
20
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/layout.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import styles from './style.module.css';
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
|
export default function ClientNestedLayout({ children }) {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
useEffect(() => {
|
||||||
|
setCount(1);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1 className={styles.red}>Client Nested. Count: {count}</h1>
|
||||||
|
<button onClick={() => setCount(count + 1)}>{count}</button>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/page.js
vendored
Normal file
9
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/page.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
export default function ClientPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/client-nested</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
button {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-ppr/app/client-nested/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.red {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export default function DeploymentsBreakdownPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/(custom)/deployments/breakdown</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/(custom)/layout.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/(custom)/layout.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default function CustomDashboardRootLayout({ children }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>Custom dashboard</h2>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/[id]/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/[id]/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function DeploymentsPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/deployments/[id]. ID is: {props.params.id}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/[id]/settings/page.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/[id]/settings/page.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default function DeploymentsPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
hello from app/dashboard/deployments/[id]/settings. ID is:{' '}
|
||||||
|
{props.params.id}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export default function Page() {
|
||||||
|
return <p>catchall</p>;
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/info/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/info/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function DeploymentsInfoPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/deployments/info</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/layout.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/deployments/layout.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default function DeploymentsLayout({ message, children }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>Deployments hello</h2>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/integrations/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/integrations/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function IntegrationsPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/integrations</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/layout.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/layout.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default function DashboardLayout(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Dashboard</h1>
|
||||||
|
{props.children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/dashboard/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function DashboardPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/[category]/[id]/layout.js
vendored
Normal file
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/[category]/[id]/layout.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default function IdLayout({ children, params }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h3>
|
||||||
|
Id Layout. Params:{' '}
|
||||||
|
<span id="id-layout-params">{JSON.stringify(params)}</span>
|
||||||
|
</h3>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/[category]/[id]/page.js
vendored
Normal file
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/[category]/[id]/page.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default function IdPage({ children, params }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
Id Page. Params:{' '}
|
||||||
|
<span id="id-page-params">{JSON.stringify(params)}</span>
|
||||||
|
</p>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/[category]/layout.js
vendored
Normal file
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/[category]/layout.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default function CategoryLayout({ children, params }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>
|
||||||
|
Category Layout. Params:{' '}
|
||||||
|
<span id="category-layout-params">{JSON.stringify(params)}</span>{' '}
|
||||||
|
</h2>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/layout.js
vendored
Normal file
11
packages/next/test/fixtures/00-app-dir-ppr/app/dynamic/layout.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default function DynamicLayout({ children, params }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>
|
||||||
|
Dynamic Layout. Params:{' '}
|
||||||
|
<span id="dynamic-layout-params">{JSON.stringify(params)}</span>
|
||||||
|
</h1>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/edge-route-handler/route.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/edge-route-handler/route.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export const runtime = 'experimental-edge';
|
||||||
|
|
||||||
|
export const GET = req => {
|
||||||
|
// use query to trigger dynamic usage
|
||||||
|
console.log('query', Object.fromEntries(req.nextUrl.searchParams));
|
||||||
|
return new Response('hello world');
|
||||||
|
};
|
||||||
16
packages/next/test/fixtures/00-app-dir-ppr/app/gsp/[text]/page.js
vendored
Normal file
16
packages/next/test/fixtures/00-app-dir-ppr/app/gsp/[text]/page.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export default async function DynamicPage({ params }) {
|
||||||
|
return (
|
||||||
|
<main>
|
||||||
|
<h1>Dynamic page</h1>
|
||||||
|
<p>Param: {params.text}</p>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateStaticParams() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: 'one',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
10
packages/next/test/fixtures/00-app-dir-ppr/app/layout.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir-ppr/app/layout.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default function Root({ children }) {
|
||||||
|
return (
|
||||||
|
<html className="this-is-the-document-html">
|
||||||
|
<head>
|
||||||
|
<title>{`hello world`}</title>
|
||||||
|
</head>
|
||||||
|
<body className="this-is-the-document-body">{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
packages/next/test/fixtures/00-app-dir-ppr/app/page.js
vendored
Normal file
5
packages/next/test/fixtures/00-app-dir-ppr/app/page.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <p>index app page {Date.now()}</p>;
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/partial-match-[id]/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/partial-match-[id]/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function DeploymentsPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/partial-match-[id]. ID is: {props.params.id}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-ppr/app/shared-component-route/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-ppr/app/shared-component-route/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function SharedComponentRoute() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/shared-component-route</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user