Support for App.getInitialProps/Page.getInitialProps (vercel/turbo#464)

This is a very simplified version of what Next.js does. It adds support for `App` and page components defining `getInitialProps`.

fixes vercel/web-tooling-internal#38
This commit is contained in:
Alex Kirszenberg 2022-10-10 11:03:25 +02:00 committed by GitHub
parent 4851e09ca8
commit ed769521f9
6 changed files with 58 additions and 12 deletions

View file

@ -40,6 +40,13 @@ pub fn get_next_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc {
)
.into(),
);
let internal_shared_utils_import_mapping = asset_to_import_mapping(
VirtualAssetVc::new(
pages_dir.root().join("next_js/internal/shared-utils.js"),
embed_next_file!("internal/shared-utils.js").into(),
)
.into(),
);
insert_alias_to_alternatives(
&mut import_map,
@ -59,6 +66,12 @@ pub fn get_next_import_map(pages_dir: FileSystemPathVc) -> ImportMapVc {
"@vercel/turbopack-next/internal/html-context",
internal_html_context_import_mapping,
);
insert_alias(
&mut import_map,
"@vercel/turbopack-next/internal/shared-utils",
internal_shared_utils_import_mapping,
);
insert_alias(&mut import_map, "next/app", pages_app_asset_import_mapping);
insert_alias(
&mut import_map,
"next/document",

View file

@ -3,4 +3,4 @@ import Component from ".";
import { hydrateRoot } from "react-dom/client";
const data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent);
hydrateRoot(document.getElementById("__next"), <App Component={Component} pageProps={data.props} />);
hydrateRoot(document.getElementById("__next"), <App {...data.props} Component={Component} />);

View file

@ -3,6 +3,7 @@ const END_OF_OPERATION = process.argv[2];
import App from "@vercel/turbopack-next/pages/_app";
import Document from "@vercel/turbopack-next/pages/_document";
import { HtmlContext } from "@vercel/turbopack-next/internal/html-context";
import { loadGetInitialProps } from "@vercel/turbopack-next/internal/shared-utils";
import Component, * as otherExports from ".";
import { renderToString, renderToStaticMarkup } from "react-dom/server";
("TURBOPACK { transition: next-client }");
@ -46,17 +47,24 @@ async function operation(data) {
}
}
const initialProps = await loadGetInitialProps(App, {
Component,
// TODO(alexkirsz) Pass in `context`
ctx: {},
});
const props = { ...initialProps, ...data.props, pageProps: { ...initialProps.pageProps, ...data.props } };
const urls = chunkGroup.map((p) => `/${p}`);
const scripts = urls.filter((url) => url.endsWith(".js"));
const styles = urls.filter((url) => url.endsWith(".css"));
const htmlProps = {
scripts,
styles,
__NEXT_DATA__: { props },
};
const documentHTML = renderToStaticMarkup(
<HtmlContext.Provider
value={{
scripts,
styles,
data,
}}
>
<HtmlContext.Provider value={htmlProps}>
<Document />
</HtmlContext.Provider>
);
@ -70,11 +78,12 @@ async function operation(data) {
result.push(DOCTYPE);
}
result.push(renderTargetPrefix);
// TODO capture meta info during rendering
result.push(
// TODO capture meta info during rendering
renderToString(
<Body>
<App Component={Component} pageProps={data} />
<App {...props} Component={Component} />
</Body>
)
);

View file

@ -0,0 +1,15 @@
// Originally defined in https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/utils.ts
export async function loadGetInitialProps(App, ctx) {
if (!App.getInitialProps) {
if (ctx.ctx && ctx.Component) {
return {
pageProps: await loadGetInitialProps(ctx.Component, ctx.ctx),
};
}
return {};
}
const props = await App.getInitialProps(ctx);
return props;
}

View file

@ -1,6 +1,15 @@
// The full definition of the default _app.js file is in
// https://github.com/vercel/next.js/blob/canary/packages/next/pages/_app.tsx
import { loadGetInitialProps } from "@vercel/turbopack-next/internal/shared-utils";
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}
async function appGetInitialProps({ Component, ctx }) {
const pageProps = await loadGetInitialProps(Component, ctx);
return { pageProps };
}
App.getInitialProps = appGetInitialProps;

View file

@ -42,7 +42,7 @@ export function htmlEscapeJsonString(str) {
}
export function NextScript() {
const { scripts, data } = React.useContext(HtmlContext);
const { scripts, __NEXT_DATA__ } = React.useContext(HtmlContext);
return (
<>
@ -50,7 +50,7 @@ export function NextScript() {
id="__NEXT_DATA__"
type="application/json"
dangerouslySetInnerHTML={{
__html: htmlEscapeJsonString(JSON.stringify(data)),
__html: htmlEscapeJsonString(JSON.stringify(__NEXT_DATA__)),
}}
></script>
{scripts.map((url) => (