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:
parent
4851e09ca8
commit
ed769521f9
6 changed files with 58 additions and 12 deletions
|
@ -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",
|
||||
|
|
|
@ -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} />);
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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) => (
|
||||
|
|
Loading…
Reference in a new issue