Skip to content

Commit

Permalink
Merge branch 'canary' into feature/swc-reads-file
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Nov 25, 2021
2 parents f611ba4 + b71f9d9 commit 0815d65
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 69 deletions.
2 changes: 1 addition & 1 deletion docs/api-reference/next.config.js/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ module.exports = (phase, { defaultConfig }) => {
}
```

`phase` is the current context in which the configuration is loaded. You can see the [available phases](https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/constants.ts#L1-L4). Phases can be imported from `next/constants`:
`phase` is the current context in which the configuration is loaded. You can see the [available phases](https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/constants.ts#L1-L5). Phases can be imported from `next/constants`:

```js
const { PHASE_DEVELOPMENT_SERVER } = require('next/constants')
Expand Down
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

0 comments on commit 0815d65

Please sign in to comment.