From 68e72c0ecfd9ab7e8fd8528612f021c87047e67d Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Mon, 22 Nov 2021 21:00:10 +0100 Subject: [PATCH 1/7] Remove unused exports and simplify types --- packages/next/client/route-loader.ts | 50 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/next/client/route-loader.ts b/packages/next/client/route-loader.ts index 7147eee9194c0..d1198fc2a0244 100644 --- a/packages/next/client/route-loader.ts +++ b/packages/next/client/route-loader.ts @@ -1,5 +1,4 @@ -import { ComponentType } from 'react' -import { ClientBuildManifest } from '../build/webpack/plugins/build-manifest-plugin' +import type { ComponentType } from 'react' import getAssetPathFromRoute from '../shared/lib/router/utils/get-asset-path-from-route' import { requestIdleCallback } from './request-idle-callback' @@ -11,36 +10,36 @@ const MS_MAX_IDLE_DELAY = 3800 declare global { interface Window { - __BUILD_MANIFEST?: ClientBuildManifest + __BUILD_MANIFEST?: Record __BUILD_MANIFEST_CB?: Function - __MIDDLEWARE_MANIFEST?: any + __MIDDLEWARE_MANIFEST?: [location: string, isSSR: boolean][] __MIDDLEWARE_MANIFEST_CB?: Function } } -export interface LoadedEntrypointSuccess { +interface LoadedEntrypointSuccess { component: ComponentType exports: any } -export interface LoadedEntrypointFailure { +interface LoadedEntrypointFailure { error: unknown } -export type RouteEntrypoint = LoadedEntrypointSuccess | LoadedEntrypointFailure +type RouteEntrypoint = LoadedEntrypointSuccess | LoadedEntrypointFailure -export interface RouteStyleSheet { +interface RouteStyleSheet { href: string content: string } -export interface LoadedRouteSuccess extends LoadedEntrypointSuccess { +interface LoadedRouteSuccess extends LoadedEntrypointSuccess { styles: RouteStyleSheet[] } -export interface LoadedRouteFailure { +interface LoadedRouteFailure { error: unknown } -export type RouteLoaderEntry = LoadedRouteSuccess | LoadedRouteFailure +type RouteLoaderEntry = LoadedRouteSuccess | LoadedRouteFailure -export type Future = { +interface Future { resolve: (entrypoint: V) => void future: Promise } @@ -211,34 +210,35 @@ function resolvePromiseWithTimeout( // Only cache this response as a last resort if we cannot eliminate all other // code branches that use the Build Manifest Callback and push them through // the Route Loader interface. -export function getClientBuildManifest(): Promise { +export function getClientBuildManifest() { if (self.__BUILD_MANIFEST) { return Promise.resolve(self.__BUILD_MANIFEST) } - const onBuildManifest: Promise = - new Promise((resolve) => { - // Mandatory because this is not concurrent safe: - const cb = self.__BUILD_MANIFEST_CB - self.__BUILD_MANIFEST_CB = () => { - resolve(self.__BUILD_MANIFEST!) - cb && cb() - } - }) + const onBuildManifest = new Promise>((resolve) => { + // Mandatory because this is not concurrent safe: + const cb = self.__BUILD_MANIFEST_CB + self.__BUILD_MANIFEST_CB = () => { + resolve(self.__BUILD_MANIFEST!) + cb && cb() + } + }) - return resolvePromiseWithTimeout( + return resolvePromiseWithTimeout( onBuildManifest, MS_MAX_IDLE_DELAY, markAssetError(new Error('Failed to load client build manifest')) ) } -export function getMiddlewareManifest(): Promise { +export function getMiddlewareManifest() { if (self.__MIDDLEWARE_MANIFEST) { return Promise.resolve(self.__MIDDLEWARE_MANIFEST) } - const onMiddlewareManifest: Promise = new Promise((resolve) => { + const onMiddlewareManifest = new Promise< + [location: string, isSSR: boolean][] + >((resolve) => { const cb = self.__MIDDLEWARE_MANIFEST_CB self.__MIDDLEWARE_MANIFEST_CB = () => { resolve(self.__MIDDLEWARE_MANIFEST!) From 8c6825cdb308adf71283676cb54153129fa8570a Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Mon, 22 Nov 2021 21:00:28 +0100 Subject: [PATCH 2/7] Fix middleware empty manifest --- packages/next/build/webpack/plugins/build-manifest-plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/build/webpack/plugins/build-manifest-plugin.ts b/packages/next/build/webpack/plugins/build-manifest-plugin.ts index 53627db2c44c7..99ab86f421e19 100644 --- a/packages/next/build/webpack/plugins/build-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/build-manifest-plugin.ts @@ -209,7 +209,7 @@ export default class BuildManifestPlugin { assetMap.lowPriorityFiles.push(ssgManifestPath) assets[ssgManifestPath] = new sources.RawSource(srcEmptySsgManifest) - const srcEmptyMiddlewareManifest = `self.__MIDDLEWARE_MANIFEST=new Set;self.__MIDDLEWARE_MANIFEST_CB&&self.__MIDDLEWARE_MANIFEST_CB()` + const srcEmptyMiddlewareManifest = `self.__MIDDLEWARE_MANIFEST=[];self.__MIDDLEWARE_MANIFEST_CB&&self.__MIDDLEWARE_MANIFEST_CB()` const middlewareManifestPath = `${CLIENT_STATIC_FILES_PATH}/${this.buildId}/_middlewareManifest.js` assetMap.lowPriorityFiles.push(middlewareManifestPath) assets[middlewareManifestPath] = new sources.RawSource( From fe49a56e4c422562b427dca5de71f79e6adb57ae Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Mon, 22 Nov 2021 21:00:49 +0100 Subject: [PATCH 3/7] Better type for clientInfo --- packages/next/build/webpack/plugins/middleware-plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/build/webpack/plugins/middleware-plugin.ts b/packages/next/build/webpack/plugins/middleware-plugin.ts index 2fd4ba4cf0c53..8c1ac1354544f 100644 --- a/packages/next/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/build/webpack/plugins/middleware-plugin.ts @@ -18,7 +18,7 @@ export const ssrEntries = new Map() export interface MiddlewareManifest { version: 1 sortedMiddleware: string[] - clientInfo: [string, boolean][] + clientInfo: [location: string, isSSR: boolean][] middleware: { [page: string]: { env: string[] From 21317eafeef720f85eebf42730a3e07840dd77af Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Mon, 22 Nov 2021 21:01:19 +0100 Subject: [PATCH 4/7] Import only the Router type in some places --- packages/next/client/index.tsx | 3 ++- packages/next/pages/_app.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 695e1dc117419..47dee09ea965c 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -6,7 +6,8 @@ import { StyleRegistry } from 'styled-jsx' import { HeadManagerContext } from '../shared/lib/head-manager-context' import mitt, { MittEmitter } from '../shared/lib/mitt' import { RouterContext } from '../shared/lib/router-context' -import Router, { +import type Router from '../shared/lib/router/router' +import { AppComponent, AppProps, delBasePath, diff --git a/packages/next/pages/_app.tsx b/packages/next/pages/_app.tsx index 334a34b4a306e..691555628145f 100644 --- a/packages/next/pages/_app.tsx +++ b/packages/next/pages/_app.tsx @@ -6,7 +6,7 @@ import { AppPropsType, NextWebVitalsMetric, } from '../shared/lib/utils' -import { Router } from '../client/router' +import type { Router } from '../client/router' export { AppInitialProps } From 05577292409d4c34499e4d04445a72d5891361e2 Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Mon, 22 Nov 2021 21:01:29 +0100 Subject: [PATCH 5/7] Remove unused type --- packages/next/build/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index e00f7b52d4a65..aa1de3f08cb4e 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -2057,8 +2057,6 @@ export default async function build( return buildResult } -export type ClientSsgManifest = Set - function generateClientSsgManifest( prerenderManifest: PrerenderManifest, { @@ -2067,7 +2065,7 @@ function generateClientSsgManifest( locales, }: { buildId: string; distDir: string; locales: string[] } ) { - const ssgPages: ClientSsgManifest = new Set([ + const ssgPages = new Set([ ...Object.entries(prerenderManifest.routes) // Filter out dynamic routes .filter(([, { srcRoute }]) => srcRoute == null) From 258c54e64118f3c45823da32226846257b756ad0 Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Mon, 22 Nov 2021 21:01:57 +0100 Subject: [PATCH 6/7] Refactor PageLoader types --- packages/next/client/page-loader.ts | 65 +++++++++++++++++------------ 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/packages/next/client/page-loader.ts b/packages/next/client/page-loader.ts index 81cf102bf73b8..b9a768a2f1c8e 100644 --- a/packages/next/client/page-loader.ts +++ b/packages/next/client/page-loader.ts @@ -1,5 +1,5 @@ -import { ComponentType } from 'react' -import { ClientSsgManifest } from '../build' +import type { ComponentType } from 'react' +import type { RouteLoader } from './route-loader' import { addBasePath, addLocale, @@ -13,7 +13,6 @@ import { createRouteLoader, getClientBuildManifest, getMiddlewareManifest, - RouteLoader, } from './route-loader' function normalizeRoute(route: string): string { @@ -25,6 +24,15 @@ function normalizeRoute(route: string): string { return route.replace(/\/$/, '') } +declare global { + interface Window { + __DEV_MIDDLEWARE_MANIFEST?: [location: string, isSSR: boolean][] + __DEV_PAGES_MANIFEST?: { pages: string[] } + __SSG_MANIFEST_CB?: () => void + __SSG_MANIFEST?: Set + } +} + export type StyleSheetTuple = { href: string; text: string } export type GoodPageCache = { page: ComponentType @@ -35,10 +43,12 @@ export type GoodPageCache = { export default class PageLoader { private buildId: string private assetPrefix: string + private promisedSsgManifest: Promise> + private promisedDevPagesManifest?: Promise + private promisedMiddlewareManifest?: Promise< + [location: string, isSSR: boolean][] + > - private promisedSsgManifest?: Promise - private promisedDevPagesManifest?: Promise - private promisedMiddlewareManifest?: Promise<[string, boolean][]> public routeLoader: RouteLoader constructor(buildId: string, assetPrefix: string) { @@ -47,13 +57,12 @@ export default class PageLoader { this.buildId = buildId this.assetPrefix = assetPrefix - /** @type {Promise>} */ this.promisedSsgManifest = new Promise((resolve) => { - if ((window as any).__SSG_MANIFEST) { - resolve((window as any).__SSG_MANIFEST) + if (window.__SSG_MANIFEST) { + resolve(window.__SSG_MANIFEST) } else { - ;(window as any).__SSG_MANIFEST_CB = () => { - resolve((window as any).__SSG_MANIFEST) + window.__SSG_MANIFEST_CB = () => { + resolve(window.__SSG_MANIFEST!) } } }) @@ -63,48 +72,54 @@ export default class PageLoader { if (process.env.NODE_ENV === 'production') { return getClientBuildManifest().then((manifest) => manifest.sortedPages) } else { - if ((window as any).__DEV_PAGES_MANIFEST) { - return (window as any).__DEV_PAGES_MANIFEST.pages + if (window.__DEV_PAGES_MANIFEST) { + return window.__DEV_PAGES_MANIFEST.pages } else { if (!this.promisedDevPagesManifest) { + // TODO: Decide what should happen when fetching fails instead of asserting + // @ts-ignore this.promisedDevPagesManifest = fetch( `${this.assetPrefix}/_next/static/development/_devPagesManifest.json` ) .then((res) => res.json()) - .then((manifest) => { - ;(window as any).__DEV_PAGES_MANIFEST = manifest + .then((manifest: { pages: string[] }) => { + window.__DEV_PAGES_MANIFEST = manifest return manifest.pages }) .catch((err) => { console.log(`Failed to fetch devPagesManifest`, err) }) } - return this.promisedDevPagesManifest + // TODO Remove this assertion as this could be undefined + return this.promisedDevPagesManifest! } } } - getMiddlewareList(): Promise<[string, boolean][]> { + getMiddlewareList() { if (process.env.NODE_ENV === 'production') { return getMiddlewareManifest() } else { - if ((window as any).__DEV_MIDDLEWARE_MANIFEST) { - return (window as any).__DEV_MIDDLEWARE_MANIFEST + if (window.__DEV_MIDDLEWARE_MANIFEST) { + return window.__DEV_MIDDLEWARE_MANIFEST } else { if (!this.promisedMiddlewareManifest) { + // TODO: Decide what should happen when fetching fails instead of asserting + // @ts-ignore this.promisedMiddlewareManifest = fetch( `${this.assetPrefix}/_next/static/${this.buildId}/_devMiddlewareManifest.json` ) .then((res) => res.json()) - .then((manifest) => { - ;(window as any).__DEV_MIDDLEWARE_MANIFEST = manifest + .then((manifest: [location: string, isSSR: boolean][]) => { + window.__DEV_MIDDLEWARE_MANIFEST = manifest return manifest }) .catch((err) => { console.log(`Failed to fetch _devMiddlewareManifest`, err) }) } - return this.promisedMiddlewareManifest + // TODO Remove this assertion as this could be undefined + return this.promisedMiddlewareManifest! } } } @@ -123,7 +138,7 @@ export default class PageLoader { }: { href: string asPath: string - ssg: boolean + ssg?: boolean rsc?: boolean locale?: string | false }): string { @@ -157,9 +172,7 @@ export default class PageLoader { * @param {string} route - the route (file-system path) */ _isSsg(route: string): Promise { - return this.promisedSsgManifest!.then((s: ClientSsgManifest) => - s.has(route) - ) + return this.promisedSsgManifest.then((manifest) => manifest.has(route)) } loadPage(route: string): Promise { From 6d3c00a713233a9ad16018daaf310eef0f26900f Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Mon, 22 Nov 2021 21:02:11 +0100 Subject: [PATCH 7/7] Refactor Router type imports --- packages/next/shared/lib/router/router.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/next/shared/lib/router/router.ts b/packages/next/shared/lib/router/router.ts index c758703249fe8..f855aa2fbbccc 100644 --- a/packages/next/shared/lib/router/router.ts +++ b/packages/next/shared/lib/router/router.ts @@ -1,23 +1,25 @@ // tslint:disable:no-console -import { ParsedUrlQuery } from 'querystring' -import { ComponentType } from 'react' -import { UrlObject } from 'url' +import type { ComponentType } from 'react' +import type { DomainLocale } from '../../../server/config' +import type { MittEmitter } from '../mitt' +import type { ParsedUrlQuery } from 'querystring' +import type { RouterEvent } from '../../../client/router' +import type { StyleSheetTuple } from '../../../client/page-loader' +import type { UrlObject } from 'url' +import type PageLoader from '../../../client/page-loader' import { normalizePathTrailingSlash, removePathTrailingSlash, } from '../../../client/normalize-trailing-slash' -import { GoodPageCache, StyleSheetTuple } from '../../../client/page-loader' import { getClientBuildManifest, isAssetError, markAssetError, } from '../../../client/route-loader' -import { RouterEvent } from '../../../client/router' import isError from '../../../lib/is-error' -import type { DomainLocale } from '../../../server/config' import { denormalizePagePath } from '../../../server/denormalize-page-path' import { normalizeLocalePath } from '../i18n/normalize-locale-path' -import mitt, { MittEmitter } from '../mitt' +import mitt from '../mitt' import { AppContextType, formatWithValidation, @@ -612,7 +614,7 @@ export default class Router implements BaseRouter { sub: Subscription clc: ComponentLoadCancel - pageLoader: any + pageLoader: PageLoader _bps: BeforePopStateCallback | undefined events: MittEmitter _wrapApp: (App: AppComponent) => any @@ -1738,7 +1740,7 @@ export default class Router implements BaseRouter { ]) } - async fetchComponent(route: string): Promise { + async fetchComponent(route: string) { let cancelled = false const cancel = (this.clc = () => { cancelled = true @@ -1819,7 +1821,7 @@ export default class Router implements BaseRouter { this.locale ) - const fns: [string, boolean][] = await this.pageLoader.getMiddlewareList() + const fns = await this.pageLoader.getMiddlewareList() const requiresPreflight = fns.some(([middleware, isSSR]) => { return getRouteMatcher(getMiddlewareRegex(middleware, !isSSR))(cleanedAs) })