Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve and refactor some types #31704

Merged
merged 7 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2057,8 +2057,6 @@ export default async function build(
return buildResult
}

export type ClientSsgManifest = Set<string>

function generateClientSsgManifest(
prerenderManifest: PrerenderManifest,
{
Expand All @@ -2067,7 +2065,7 @@ function generateClientSsgManifest(
locales,
}: { buildId: string; distDir: string; locales: string[] }
) {
const ssgPages: ClientSsgManifest = new Set<string>([
const ssgPages = new Set<string>([
...Object.entries(prerenderManifest.routes)
// Filter out dynamic routes
.filter(([, { srcRoute }]) => srcRoute == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/webpack/plugins/middleware-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const ssrEntries = new Map<string, { requireFlightManifest: boolean }>()
export interface MiddlewareManifest {
version: 1
sortedMiddleware: string[]
clientInfo: [string, boolean][]
clientInfo: [location: string, isSSR: boolean][]
middleware: {
[page: string]: {
env: string[]
Expand Down
3 changes: 2 additions & 1 deletion packages/next/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
65 changes: 39 additions & 26 deletions packages/next/client/page-loader.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -13,7 +13,6 @@ import {
createRouteLoader,
getClientBuildManifest,
getMiddlewareManifest,
RouteLoader,
} from './route-loader'

function normalizeRoute(route: string): string {
Expand All @@ -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<string>
}
}

export type StyleSheetTuple = { href: string; text: string }
export type GoodPageCache = {
page: ComponentType
Expand All @@ -35,10 +43,12 @@ export type GoodPageCache = {
export default class PageLoader {
private buildId: string
private assetPrefix: string
private promisedSsgManifest: Promise<Set<string>>
private promisedDevPagesManifest?: Promise<string[]>
private promisedMiddlewareManifest?: Promise<
[location: string, isSSR: boolean][]
>

private promisedSsgManifest?: Promise<ClientSsgManifest>
private promisedDevPagesManifest?: Promise<any>
private promisedMiddlewareManifest?: Promise<[string, boolean][]>
public routeLoader: RouteLoader

constructor(buildId: string, assetPrefix: string) {
Expand All @@ -47,13 +57,12 @@ export default class PageLoader {
this.buildId = buildId
this.assetPrefix = assetPrefix

/** @type {Promise<Set<string>>} */
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!)
}
}
})
Expand All @@ -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!
}
}
}
Expand All @@ -123,7 +138,7 @@ export default class PageLoader {
}: {
href: string
asPath: string
ssg: boolean
ssg?: boolean
rsc?: boolean
locale?: string | false
}): string {
Expand Down Expand Up @@ -157,9 +172,7 @@ export default class PageLoader {
* @param {string} route - the route (file-system path)
*/
_isSsg(route: string): Promise<boolean> {
return this.promisedSsgManifest!.then((s: ClientSsgManifest) =>
s.has(route)
)
return this.promisedSsgManifest.then((manifest) => manifest.has(route))
}

loadPage(route: string): Promise<GoodPageCache> {
Expand Down
50 changes: 25 additions & 25 deletions packages/next/client/route-loader.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -11,36 +10,36 @@ const MS_MAX_IDLE_DELAY = 3800

declare global {
interface Window {
__BUILD_MANIFEST?: ClientBuildManifest
__BUILD_MANIFEST?: Record<string, string[]>
__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<V> = {
interface Future<V> {
resolve: (entrypoint: V) => void
future: Promise<V>
}
Expand Down Expand Up @@ -211,34 +210,35 @@ function resolvePromiseWithTimeout<T>(
// 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<ClientBuildManifest> {
export function getClientBuildManifest() {
if (self.__BUILD_MANIFEST) {
return Promise.resolve(self.__BUILD_MANIFEST)
}

const onBuildManifest: Promise<ClientBuildManifest> =
new Promise<ClientBuildManifest>((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<Record<string, string[]>>((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<ClientBuildManifest>(
return resolvePromiseWithTimeout(
onBuildManifest,
MS_MAX_IDLE_DELAY,
markAssetError(new Error('Failed to load client build manifest'))
)
}

export function getMiddlewareManifest(): Promise<any> {
export function getMiddlewareManifest() {
if (self.__MIDDLEWARE_MANIFEST) {
return Promise.resolve(self.__MIDDLEWARE_MANIFEST)
}

const onMiddlewareManifest: Promise<any> = new Promise<any>((resolve) => {
const onMiddlewareManifest = new Promise<
[location: string, isSSR: boolean][]
>((resolve) => {
const cb = self.__MIDDLEWARE_MANIFEST_CB
self.__MIDDLEWARE_MANIFEST_CB = () => {
resolve(self.__MIDDLEWARE_MANIFEST!)
Expand Down
2 changes: 1 addition & 1 deletion packages/next/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
AppPropsType,
NextWebVitalsMetric,
} from '../shared/lib/utils'
import { Router } from '../client/router'
import type { Router } from '../client/router'

export { AppInitialProps }

Expand Down
22 changes: 12 additions & 10 deletions packages/next/shared/lib/router/router.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -612,7 +614,7 @@ export default class Router implements BaseRouter {

sub: Subscription
clc: ComponentLoadCancel
pageLoader: any
pageLoader: PageLoader
_bps: BeforePopStateCallback | undefined
events: MittEmitter<RouterEvent>
_wrapApp: (App: AppComponent) => any
Expand Down Expand Up @@ -1738,7 +1740,7 @@ export default class Router implements BaseRouter {
])
}

async fetchComponent(route: string): Promise<GoodPageCache> {
async fetchComponent(route: string) {
let cancelled = false
const cancel = (this.clc = () => {
cancelled = true
Expand Down Expand Up @@ -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)
})
Expand Down