Handle getStaticProps.redirect (vercel/turbo#3497)
This PR adds support for returning `redirect: { destination, permanent, statusCode }` from `getStaticProps`.
This commit is contained in:
parent
0cf02c89ed
commit
822bb5d15c
3 changed files with 52 additions and 14 deletions
|
@ -8,6 +8,8 @@ import "@vercel/turbopack-next/internal/shims";
|
|||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
|
||||
import { renderToHTML, RenderOpts } from "next/dist/server/render";
|
||||
import { getRedirectStatus } from "next/dist/lib/redirect-status";
|
||||
import { PERMANENT_REDIRECT_STATUS } from "next/dist/shared/lib/constants";
|
||||
import type { BuildManifest } from "next/dist/server/get-page-files";
|
||||
import type { ReactLoadableManifest } from "next/dist/server/load-components";
|
||||
|
||||
|
@ -27,7 +29,7 @@ type IpcOutgoingMessage =
|
|||
| {
|
||||
type: "response";
|
||||
statusCode: number;
|
||||
contentType: string;
|
||||
headers: Array<[string, string]>;
|
||||
body: string;
|
||||
}
|
||||
| { type: "rewrite"; path: string };
|
||||
|
@ -197,7 +199,7 @@ export default function startHandler({
|
|||
renderOpts
|
||||
);
|
||||
|
||||
// This is set when `getStaticProps` returns `notFound: true`.
|
||||
// Set when `getStaticProps` returns `notFound: true`.
|
||||
const isNotFound = (renderOpts as any).isNotFound;
|
||||
|
||||
if (isNotFound) {
|
||||
|
@ -206,7 +208,7 @@ export default function startHandler({
|
|||
type: "response",
|
||||
statusCode,
|
||||
body: '{"notFound":true}',
|
||||
contentType: MIME_APPLICATION_JAVASCRIPT,
|
||||
headers: [["Content-Type", MIME_APPLICATION_JAVASCRIPT]],
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -218,13 +220,49 @@ export default function startHandler({
|
|||
};
|
||||
}
|
||||
|
||||
// Set when `getStaticProps` returns `redirect: { destination, permanent, statusCode }`.
|
||||
const isRedirect = (renderOpts as any).isRedirect;
|
||||
|
||||
if (isRedirect && !isDataReq) {
|
||||
const pageProps = (renderOpts as any).pageData.pageProps;
|
||||
const redirect = {
|
||||
destination: pageProps.__N_REDIRECT,
|
||||
statusCode: pageProps.__N_REDIRECT_STATUS,
|
||||
basePath: pageProps.__N_REDIRECT_BASE_PATH,
|
||||
};
|
||||
const statusCode = getRedirectStatus(redirect);
|
||||
|
||||
// TODO(alexkirsz) Handle basePath.
|
||||
// if (
|
||||
// basePath &&
|
||||
// redirect.basePath !== false &&
|
||||
// redirect.destination.startsWith("/")
|
||||
// ) {
|
||||
// redirect.destination = `${basePath}${redirect.destination}`;
|
||||
// }
|
||||
|
||||
const headers: Array<[string, string]> = [
|
||||
["Location", redirect.destination],
|
||||
];
|
||||
if (statusCode === PERMANENT_REDIRECT_STATUS) {
|
||||
headers.push(["Refresh", `0;url=${redirect.destination}`]);
|
||||
}
|
||||
|
||||
return {
|
||||
type: "response",
|
||||
statusCode,
|
||||
headers,
|
||||
body: redirect.destination,
|
||||
};
|
||||
}
|
||||
|
||||
if (isDataReq) {
|
||||
// TODO(from next.js): change this to a different passing mechanism
|
||||
const pageData = (renderOpts as any).pageData;
|
||||
return {
|
||||
type: "response",
|
||||
statusCode,
|
||||
contentType: MIME_APPLICATION_JAVASCRIPT,
|
||||
headers: [["Content-Type", MIME_APPLICATION_JAVASCRIPT]],
|
||||
// Page data is only returned if the page had getXxyProps.
|
||||
body: JSON.stringify(pageData === undefined ? {} : pageData),
|
||||
};
|
||||
|
@ -235,14 +273,16 @@ export default function startHandler({
|
|||
}
|
||||
|
||||
const body = renderResult.toUnchunkedString();
|
||||
// TODO: handle these
|
||||
|
||||
// TODO: handle revalidate
|
||||
// const sprRevalidate = (renderOpts as any).revalidate;
|
||||
// const isRedirect = (renderOpts as any).isRedirect;
|
||||
|
||||
return {
|
||||
type: "response",
|
||||
statusCode,
|
||||
contentType: renderResult.contentType() ?? MIME_TEXT_HTML_UTF8,
|
||||
headers: [
|
||||
["Content-Type", renderResult.contentType() ?? MIME_TEXT_HTML_UTF8],
|
||||
],
|
||||
body,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ use turbo_tasks::primitives::StringsVc;
|
|||
use turbo_tasks_fs::File;
|
||||
use turbopack_core::asset::AssetContentVc;
|
||||
use turbopack_dev_server::source::{
|
||||
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceResultVc, ContentSourceVc,
|
||||
ContentSource, ContentSourceContentVc, ContentSourceData, ContentSourceResultVc,
|
||||
ContentSourceVc,
|
||||
};
|
||||
use turbopack_node::render::{
|
||||
node_api_source::NodeApiContentSourceVc, rendered_source::NodeRenderContentSourceVc,
|
||||
|
@ -77,9 +78,7 @@ impl ContentSource for DevManifestContentSource {
|
|||
let file = File::from(manifest_content).with_content_type(APPLICATION_JSON);
|
||||
|
||||
Ok(ContentSourceResultVc::exact(
|
||||
ContentSourceContent::Static(AssetContentVc::from(file).into())
|
||||
.cell()
|
||||
.into(),
|
||||
ContentSourceContentVc::static_content(AssetContentVc::from(file).into()).into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use turbo_tasks_memory::{
|
|||
};
|
||||
use turbopack_core::asset::AssetContentVc;
|
||||
use turbopack_dev_server::source::{
|
||||
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter,
|
||||
ContentSource, ContentSourceContentVc, ContentSourceData, ContentSourceDataFilter,
|
||||
ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, NeededData,
|
||||
};
|
||||
|
||||
|
@ -106,10 +106,9 @@ impl ContentSource for TurboTasksSource {
|
|||
_ => return Ok(ContentSourceResultVc::not_found()),
|
||||
};
|
||||
Ok(ContentSourceResultVc::exact(
|
||||
ContentSourceContent::Static(
|
||||
ContentSourceContentVc::static_content(
|
||||
AssetContentVc::from(File::from(html).with_content_type(TEXT_HTML_UTF_8)).into(),
|
||||
)
|
||||
.cell()
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue