diff options
Diffstat (limited to 'demos/css-stress-test/nexty/client.development.tsx')
-rw-r--r-- | demos/css-stress-test/nexty/client.development.tsx | 162 |
1 files changed, 149 insertions, 13 deletions
diff --git a/demos/css-stress-test/nexty/client.development.tsx b/demos/css-stress-test/nexty/client.development.tsx index 82bce03a8..b83d78e01 100644 --- a/demos/css-stress-test/nexty/client.development.tsx +++ b/demos/css-stress-test/nexty/client.development.tsx @@ -30,32 +30,168 @@ import { createRouter, makePublicRouterInstance, } from "next/dist/client/router"; +import * as React from "react"; export const emitter: MittEmitter<string> = 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[]; + } +} + +type RenderRouteInfo = PrivateRouteInfo & { + App: AppComponent; + scroll?: { x: number; y: number } | null; +}; +type RenderErrorProps = Omit<RenderRouteInfo, "Component" | "styleSheets">; + +const data: typeof window["__NEXT_DATA__"] = JSON.parse( + document.getElementById("__NEXT_DATA__")!.textContent! +); +window.__NEXT_DATA__ = data; + +const { + props: hydrateProps, + err: hydrateErr, + page, + query, + buildId, + assetPrefix, + runtimeConfig, + dynamicIds, + isFallback, + locale, + locales, + domainLocales, + isPreview, +} = 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); +} + +const pageLoader: PageLoader = new PageLoader(buildId, prefix); + +const headManager: { + mountedInstances: Set<unknown>; + updateHead: (head: JSX.Element[]) => void; +} = initHeadManager(); +const appElement: HTMLElement | null = document.getElementById("__next"); + +let lastRenderReject: (() => void) | null; +let webpackHMR: any; +export let router: Router; +let CachedApp: AppComponent, onPerfEntry: (metric: any) => void; + export default function boot(EntryPointNamespace, loader) { _boot(EntryPointNamespace); } -function _boot(EntryPointNamespace) { - const next_data_node = document.querySelector("#__NEXT_DATA__"); - if (!next_data_node) { - throw new Error( - "__NEXT_DATA__ is missing. That means something went wrong while rendering on the server." - ); +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(); } - try { - globalThis.NEXT_DATA = JSON.parse(next_data_node.innerHTML); - } catch (error) { - error.message = `Error parsing __NEXT_DATA__\n${error.message}`; - throw error; + 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); } - const props = { ...globalThis.NEXT_DATA.props }; + render() { + return this.props.children; + } +} +let CachedComponent: React.ComponentType; + +function _boot(EntryPointNamespace) { const PageComponent = EntryPointNamespace.default; ReactDOM.hydrate( - <App Component={PageComponent} pageProps={props.pageProps}></App>, + <Container fn={(error) => <div>{JSON.stringify(error)}</div>}> + <App Component={PageComponent} pageProps={data.props}></App> + </Container>, + document.querySelector("#__next") ); } |