/// globalThis.global = globalThis; globalThis.Bun_disableCSSImports = true; import * as React from "react"; var onlyChildPolyfill = React.Children.only; React.Children.only = function only( children: React.ReactNode | React.ReactNode[] ) { if ( children && typeof children === "object" && (children as any).length == 1 ) { return onlyChildPolyfill(children[0]); } return onlyChildPolyfill(children); }; import * as ReactDOM from "react-dom"; import NextApp from "next/app"; import mitt, { MittEmitter } from "next/dist/shared/lib/mitt"; import { RouterContext } from "next/dist/shared/lib/router-context"; import Router, { AppComponent, AppProps, delBasePath, hasBasePath, PrivateRouteInfo, } from "next/dist/shared/lib/router/router"; import NextRouteLoader from "next/dist/client/route-loader"; import { isDynamicRoute } from "next/dist/shared/lib/router/utils/is-dynamic"; import { urlQueryToSearchParams, assign, } from "next/dist/shared/lib/router/utils/querystring"; import { setConfig } from "next/dist/shared/lib/runtime-config"; import { getURL, NEXT_DATA } from "next/dist/shared/lib/utils"; import initHeadManager from "next/dist/client/head-manager"; import { HeadManagerContext } from "next/dist/shared/lib/head-manager-context"; import PageLoader from "./page-loader"; import { createRouter, makePublicRouterInstance, } from "next/dist/client/router"; export const emitter: MittEmitter = mitt(); declare global { interface Window { /* test fns */ __NEXT_HYDRATED?: boolean; __NEXT_HYDRATED_CB?: () => void; /* prod */ __NEXT_PRELOADREADY?: (ids?: (string | number)[]) => void; __NEXT_DATA__: NEXT_DATA; __NEXT_P: any[]; } } function nextDataFromBunData() { const { router: { routes, route, params: paramsList }, } = globalThis.__BUN_DATA__; const paramsMap = new Map(); for (let i = 0; i < paramsList.keys.length; i++) { paramsMap.set( decodeURIComponent(paramsList.keys[i]), decodeURIComponent(paramsList.values[i]) ); } const params = {}; var url = new URL(location.href); Object.assign(params, Object.fromEntries(url.searchParams.entries())); Object.assign(params, Object.fromEntries(paramsMap.entries())); const pages = routes.keys.reduce((acc, routeName, i) => { const routePath = routes.values[i]; acc[routeName] = [routePath]; return acc; }, {}); return { page: routes.keys[route], buildId: "1234", assetPrefix: "", isPreview: false, locale: null, locales: [], isFallback: false, err: null, props: {}, query: params, pages, }; } type RenderRouteInfo = PrivateRouteInfo & { App: AppComponent; scroll?: { x: number; y: number } | null; }; const nextDataTag = document.getElementById("__NEXT_DATA__"); // pages is added at runtime and doesn't exist in Next types const data: NEXT_DATA & { pages: Record } = nextDataTag ? JSON.parse(document.getElementById("__NEXT_DATA__")!.textContent!) : nextDataFromBunData(); window.__NEXT_DATA__ = data; const { props: hydrateProps, err: hydrateErr, page, query, buildId, assetPrefix, runtimeConfig, // Todo, revist this constant when supporting dynamic() dynamicIds, isFallback, locale, locales, domainLocales, isPreview, pages, } = data; const prefix: string = assetPrefix || ""; setConfig({ serverRuntimeConfig: {}, publicRuntimeConfig: runtimeConfig || {}, }); let asPath: string = getURL(); // make sure not to attempt stripping basePath for 404s if (hasBasePath(asPath)) { asPath = delBasePath(asPath); } export const pageLoader: PageLoader = new PageLoader(buildId, prefix, pages); const headManager: { mountedInstances: Set; updateHead: (head: JSX.Element[]) => void; } = initHeadManager(); export let router: Router; let CachedApp: AppComponent = null; export default function boot(EntryPointNamespace) { _boot(EntryPointNamespace, false); } class Container extends React.Component<{ fn: (err: Error, info?: any) => void; }> { componentDidCatch(componentErr: Error, info: any) { this.props.fn(componentErr, info); } componentDidMount() { this.scrollToHash(); // We need to replace the router state if: // - the page was (auto) exported and has a query string or search (hash) // - it was auto exported and is a dynamic route (to provide params) // - if it is a client-side skeleton (fallback render) if ( router.isSsr && // We don't update for 404 requests as this can modify // the asPath unexpectedly e.g. adding basePath when // it wasn't originally present page !== "/404" && page !== "/_error" && (isFallback || (data.nextExport && (isDynamicRoute(router.pathname) || location.search || process.env.__NEXT_HAS_REWRITES)) || (hydrateProps && hydrateProps.__N_SSG && (location.search || process.env.__NEXT_HAS_REWRITES))) ) { // update query on mount for exported pages router.replace( router.pathname + "?" + String( assign( urlQueryToSearchParams(router.query), new URLSearchParams(location.search) ) ), asPath, { // @ts-ignore // WARNING: `_h` is an internal option for handing Next.js // client-side hydration. Your app should _never_ use this property. // It may change at any time without notice. _h: 1, // Fallback pages must trigger the data fetch, so the transition is // not shallow. // Other pages (strictly updating query) happens shallowly, as data // requirements would already be present. shallow: !isFallback, } ); } } componentDidUpdate() { this.scrollToHash(); } scrollToHash() { let { hash } = location; hash = hash && hash.substring(1); if (!hash) return; const el: HTMLElement | null = document.getElementById(hash); if (!el) return; // If we call scrollIntoView() in here without a setTimeout // it won't scroll properly. setTimeout(() => el.scrollIntoView(), 0); } render() { return this.props.children; } } let CachedComponent: React.ComponentType; const wrapApp = (App: AppComponent) => (wrappedAppProps: Record): JSX.Element => { const appProps: AppProps = { ...wrappedAppProps, Component: CachedComponent, err: hydrateErr, router, }; return ( ); }; function AppContainer({ children, }: React.PropsWithChildren<{}>): React.ReactElement { return (
{JSON.stringify(error)}
}> {children}
); } let reactRoot: any = null; const USE_REACT_18 = "hydrateRoot" in ReactDOM; export async function _boot(EntryPointNamespace, isError) { NextRouteLoader.getClientBuildManifest = () => Promise.resolve({}); const PageComponent = EntryPointNamespace.default; const appScripts = globalThis.__NEXT_DATA__.pages["/_app"]; // Type 'typeof App' is not assignable to type 'ComponentClass'. // Construct signature return types 'App' and 'Component' are incompatible. // @ts-expect-error CachedApp = NextApp; CachedComponent = PageComponent; if (appScripts && appScripts.length > 0) { let appSrc; for (let asset of appScripts) { if (!asset.endsWith(".css")) { appSrc = asset; break; } } if (appSrc) { const AppModule = await import(appSrc); console.assert( AppModule.default, appSrc + " must have a default export'd React component" ); if ("default" in AppModule) { CachedApp = AppModule.default; } } } router = createRouter(page, query, asPath, { initialProps: hydrateProps, pageLoader, App: CachedApp, Component: CachedComponent, wrapApp, err: null, isFallback: Boolean(isFallback), subscription: async (info, App, scroll) => { return render( Object.assign< {}, Omit, Pick >({}, info, { // If we don't have an info.Component, we may be shallow routing, // fallback to current entry point Component: info.Component || CachedComponent, App, scroll, }) ); }, locale, locales, defaultLocale: "", domainLocales, isPreview, }); globalThis.next.router = router; const domEl = document.querySelector("#__next"); const reactEl = ( ); if (USE_REACT_18) { if (!isError && !reactRoot) { // Unlike with createRoot, you don't need a separate root.render() call here reactRoot = ReactDOM.hydrateRoot(domEl, reactEl); } else { if (!reactRoot) { reactRoot = ReactDOM.createRoot(domEl); } reactRoot.render(reactEl); } } else { if (isError) { ReactDOM.render(reactEl, domEl); } else { ReactDOM.hydrate(reactEl, domEl); } } } function TopLevelRender({ App, Component, props }) { return ( ); } export function render(props) { if (USE_REACT_18) { reactRoot.render(); } else { ReactDOM.render( , document.getElementById("__next") ); } } export function renderError(e) { const reactEl = {null}; if (USE_REACT_18) { if (!reactRoot) { const domEl = document.querySelector("#__next"); // Unlike with createRoot, you don't need a separate root.render() call here reactRoot = ReactDOM.hydrateRoot(domEl, reactEl); } else { reactRoot.render(reactEl); } } else { const domEl = document.querySelector("#__next"); ReactDOM.render(reactEl, domEl); } } globalThis.next = { version: "12.0.4", emitter, render, renderError, };