125 lines
5.4 KiB
JavaScript
125 lines
5.4 KiB
JavaScript
import { INFINITE_CACHE, NEXT_BODY_SUFFIX, NEXT_CACHE_TAGS_HEADER, NEXT_META_SUFFIX } from '../../lib/constants';
|
|
import { NodeNextRequest } from '../../server/base-http/node';
|
|
import { NextRequestAdapter, signalFromNodeResponse } from '../../server/web/spec-extension/adapters/next-request';
|
|
import { toNodeOutgoingHttpHeaders } from '../../server/web/utils';
|
|
import { isDynamicUsageError } from '../helpers/is-dynamic-usage-error';
|
|
import { hasNextSupport } from '../../server/ci-info';
|
|
import { isStaticGenEnabled } from '../../server/route-modules/app-route/helpers/is-static-gen-enabled';
|
|
import { isMetadataRoute } from '../../lib/metadata/is-metadata-route';
|
|
import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths';
|
|
import { AfterRunner } from '../../server/after/run-with-after';
|
|
export var ExportedAppRouteFiles = /*#__PURE__*/ function(ExportedAppRouteFiles) {
|
|
ExportedAppRouteFiles["BODY"] = "BODY";
|
|
ExportedAppRouteFiles["META"] = "META";
|
|
return ExportedAppRouteFiles;
|
|
}({});
|
|
export async function exportAppRoute(req, res, params, page, module, incrementalCache, cacheLifeProfiles, htmlFilepath, fileWriter, experimental, buildId) {
|
|
// Ensure that the URL is absolute.
|
|
req.url = `http://localhost:3000${req.url}`;
|
|
// Adapt the request and response to the Next.js request and response.
|
|
const request = NextRequestAdapter.fromNodeNextRequest(new NodeNextRequest(req), signalFromNodeResponse(res));
|
|
const afterRunner = new AfterRunner();
|
|
// Create the context for the handler. This contains the params from
|
|
// the route and the context for the request.
|
|
const context = {
|
|
params,
|
|
prerenderManifest: {
|
|
version: 4,
|
|
routes: {},
|
|
dynamicRoutes: {},
|
|
preview: {
|
|
previewModeEncryptionKey: '',
|
|
previewModeId: '',
|
|
previewModeSigningKey: ''
|
|
},
|
|
notFoundRoutes: []
|
|
},
|
|
renderOpts: {
|
|
experimental,
|
|
nextExport: true,
|
|
supportsDynamicResponse: false,
|
|
incrementalCache,
|
|
waitUntil: afterRunner.context.waitUntil,
|
|
onClose: afterRunner.context.onClose,
|
|
onAfterTaskError: afterRunner.context.onTaskError,
|
|
cacheLifeProfiles
|
|
},
|
|
sharedContext: {
|
|
buildId
|
|
}
|
|
};
|
|
if (hasNextSupport) {
|
|
context.renderOpts.isRevalidate = true;
|
|
}
|
|
try {
|
|
const userland = module.userland;
|
|
// we don't bail from the static optimization for
|
|
// metadata routes, since it's app-route we can always append /route suffix.
|
|
const routePath = normalizeAppPath(page) + '/route';
|
|
const isPageMetadataRoute = isMetadataRoute(routePath);
|
|
if (!isStaticGenEnabled(userland) && !isPageMetadataRoute && // We don't disable static gen when dynamicIO is enabled because we
|
|
// expect that anything dynamic in the GET handler will make it dynamic
|
|
// and thus avoid the cache surprises that led to us removing static gen
|
|
// unless specifically opted into
|
|
experimental.dynamicIO !== true) {
|
|
return {
|
|
cacheControl: {
|
|
revalidate: 0,
|
|
expire: undefined
|
|
}
|
|
};
|
|
}
|
|
const response = await module.handle(request, context);
|
|
const isValidStatus = response.status < 400 || response.status === 404;
|
|
if (!isValidStatus) {
|
|
return {
|
|
cacheControl: {
|
|
revalidate: 0,
|
|
expire: undefined
|
|
}
|
|
};
|
|
}
|
|
const blob = await response.blob();
|
|
// TODO(after): if we abort a prerender because of an error in an after-callback
|
|
// we should probably communicate that better (and not log the error twice)
|
|
await afterRunner.executeAfter();
|
|
const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate;
|
|
const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire;
|
|
const headers = toNodeOutgoingHttpHeaders(response.headers);
|
|
const cacheTags = context.renderOpts.collectedTags;
|
|
if (cacheTags) {
|
|
headers[NEXT_CACHE_TAGS_HEADER] = cacheTags;
|
|
}
|
|
if (!headers['content-type'] && blob.type) {
|
|
headers['content-type'] = blob.type;
|
|
}
|
|
// Writing response body to a file.
|
|
const body = Buffer.from(await blob.arrayBuffer());
|
|
fileWriter.append(htmlFilepath.replace(/\.html$/, NEXT_BODY_SUFFIX), body);
|
|
// Write the request metadata to a file.
|
|
const meta = {
|
|
status: response.status,
|
|
headers
|
|
};
|
|
fileWriter.append(htmlFilepath.replace(/\.html$/, NEXT_META_SUFFIX), JSON.stringify(meta));
|
|
return {
|
|
cacheControl: {
|
|
revalidate,
|
|
expire
|
|
},
|
|
metadata: meta
|
|
};
|
|
} catch (err) {
|
|
if (!isDynamicUsageError(err)) {
|
|
throw err;
|
|
}
|
|
return {
|
|
cacheControl: {
|
|
revalidate: 0,
|
|
expire: undefined
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
//# sourceMappingURL=app-route.js.map
|