Skip to content

Commit 2989c8a

Browse files
authoredJul 7, 2022
Add app-path-routes manifest (#38420)
This outputs a separate manifest for leveraging during deploy to handle the new app outputs. Also ensures dynamic routes from `app` our output in the `routes-manifest` correctly along with fixing the `react-dom` import. x-ref: #37551
1 parent aa0ba3c commit 2989c8a

File tree

5 files changed

+72
-29
lines changed

5 files changed

+72
-29
lines changed
 

‎packages/next/build/index.ts

+55-18
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ import {
5454
SERVER_FILES_MANIFEST,
5555
STATIC_STATUS_PAGES,
5656
MIDDLEWARE_MANIFEST,
57+
APP_PATHS_MANIFEST,
58+
APP_PATH_ROUTES_MANIFEST,
5759
} from '../shared/lib/constants'
5860
import { getSortedRoutes, isDynamicRoute } from '../shared/lib/router/utils'
5961
import { __ApiPreviewProps } from '../server/api-utils'
@@ -114,6 +116,7 @@ import { getNamedRouteRegex } from '../shared/lib/router/utils/route-regex'
114116
import { flatReaddir } from '../lib/flat-readdir'
115117
import { RemotePattern } from '../shared/lib/image-config'
116118
import { eventSwcPlugins } from '../telemetry/events/swc-plugins'
119+
import { normalizeAppPath } from '../shared/lib/router/utils/app-paths'
117120

118121
export type SsgRoute = {
119122
initialRevalidateSeconds: number | false
@@ -385,10 +388,10 @@ export default async function build(
385388
})
386389
)
387390

388-
let mappedappPaths: { [page: string]: string } | undefined
391+
let mappedAppPaths: { [page: string]: string } | undefined
389392

390393
if (appPaths && appDir) {
391-
mappedappPaths = nextBuildSpan
394+
mappedAppPaths = nextBuildSpan
392395
.traceChild('create-app-mapping')
393396
.traceFn(() =>
394397
createPagesMapping({
@@ -427,7 +430,7 @@ export default async function build(
427430
rootDir: dir,
428431
rootPaths: mappedRootPaths,
429432
appDir,
430-
appPaths: mappedappPaths,
433+
appPaths: mappedAppPaths,
431434
pageExtensions: config.pageExtensions,
432435
})
433436
)
@@ -574,21 +577,36 @@ export default async function build(
574577
defaultLocale: string
575578
localeDetection?: false
576579
}
577-
} = nextBuildSpan.traceChild('generate-routes-manifest').traceFn(() => ({
578-
version: 3,
579-
pages404: true,
580-
basePath: config.basePath,
581-
redirects: redirects.map((r: any) => buildCustomRoute(r, 'redirect')),
582-
headers: headers.map((r: any) => buildCustomRoute(r, 'header')),
583-
dynamicRoutes: getSortedRoutes(pageKeys)
584-
.filter(isDynamicRoute)
585-
.map(pageToRoute),
586-
staticRoutes: getSortedRoutes(pageKeys)
587-
.filter((page) => !isDynamicRoute(page) && !isReservedPage(page))
588-
.map(pageToRoute),
589-
dataRoutes: [],
590-
i18n: config.i18n || undefined,
591-
}))
580+
} = nextBuildSpan.traceChild('generate-routes-manifest').traceFn(() => {
581+
const sortedRoutes = getSortedRoutes([
582+
...pageKeys,
583+
...Object.keys(mappedAppPaths || {}).map((key) =>
584+
normalizeAppPath(key)
585+
),
586+
])
587+
const dynamicRoutes: Array<ReturnType<typeof pageToRoute>> = []
588+
const staticRoutes: typeof dynamicRoutes = []
589+
590+
for (const route of sortedRoutes) {
591+
if (isDynamicRoute(route)) {
592+
dynamicRoutes.push(pageToRoute(route))
593+
} else if (!isReservedPage(route)) {
594+
staticRoutes.push(pageToRoute(route))
595+
}
596+
}
597+
598+
return {
599+
version: 3,
600+
pages404: true,
601+
basePath: config.basePath,
602+
redirects: redirects.map((r: any) => buildCustomRoute(r, 'redirect')),
603+
headers: headers.map((r: any) => buildCustomRoute(r, 'header')),
604+
dynamicRoutes,
605+
staticRoutes,
606+
dataRoutes: [],
607+
i18n: config.i18n || undefined,
608+
}
609+
})
592610

593611
if (rewrites.beforeFiles.length === 0 && rewrites.fallback.length === 0) {
594612
routesManifest.rewrites = rewrites.afterFiles.map((r: any) =>
@@ -689,6 +707,7 @@ export default async function build(
689707
REACT_LOADABLE_MANIFEST,
690708
config.optimizeFonts ? path.join(serverDir, FONT_MANIFEST) : null,
691709
BUILD_ID_FILE,
710+
appDir ? path.join(serverDir, APP_PATHS_MANIFEST) : null,
692711
]
693712
.filter(nonNullable)
694713
.map((file) => path.join(config.distDir, file)),
@@ -1618,6 +1637,24 @@ export default async function build(
16181637
'utf8'
16191638
)
16201639

1640+
if (appDir) {
1641+
const appPathsManifest = JSON.parse(
1642+
await promises.readFile(
1643+
path.join(distDir, serverDir, APP_PATHS_MANIFEST),
1644+
'utf8'
1645+
)
1646+
)
1647+
const appPathRoutes: Record<string, string> = {}
1648+
1649+
Object.keys(appPathsManifest).forEach((entry) => {
1650+
appPathRoutes[entry] = normalizeAppPath(entry) || '/'
1651+
})
1652+
await promises.writeFile(
1653+
path.join(distDir, APP_PATH_ROUTES_MANIFEST),
1654+
JSON.stringify(appPathRoutes, null, 2)
1655+
)
1656+
}
1657+
16211658
const middlewareManifest: MiddlewareManifest = JSON.parse(
16221659
await promises.readFile(
16231660
path.join(distDir, serverDir, MIDDLEWARE_MANIFEST),

‎packages/next/server/app-render.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ import {
2020
import { isDynamicRoute } from '../shared/lib/router/utils'
2121
import { tryGetPreviewData } from './api-utils/node'
2222
import { htmlEscapeJsonString } from './htmlescape'
23-
import { stripInternalQueries } from './utils'
23+
import { shouldUseReactRoot, stripInternalQueries } from './utils'
2424
import { NextApiRequestCookies } from './api-utils'
2525
import { matchSegment } from '../client/components/match-segments'
2626

27-
const ReactDOMServer = process.env.__NEXT_REACT_ROOT
27+
// this needs to be required lazily so that `next-server` can set
28+
// the env before we require
29+
const ReactDOMServer = shouldUseReactRoot
2830
? require('react-dom/server.browser')
2931
: require('react-dom/server')
3032

‎packages/next/server/base-server.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
913913
const { useFileSystemPublicRoutes } = this.nextConfig
914914

915915
if (useFileSystemPublicRoutes) {
916-
this.appPathRoutes = this.getappPathRoutes()
916+
this.appPathRoutes = this.getAppPathRoutes()
917917
this.dynamicRoutes = this.getDynamicRoutes()
918918
}
919919

@@ -1022,7 +1022,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
10221022
.filter((item): item is RoutingItem => Boolean(item))
10231023
}
10241024

1025-
protected getappPathRoutes(): Record<string, string> {
1025+
protected getAppPathRoutes(): Record<string, string> {
10261026
const appPathRoutes: Record<string, string> = {}
10271027

10281028
Object.keys(this.appPathsManifest || {}).forEach((entry) => {
@@ -1031,7 +1031,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
10311031
return appPathRoutes
10321032
}
10331033

1034-
protected getappPathLayouts(pathname: string): string[] {
1034+
protected getAppPathLayouts(pathname: string): string[] {
10351035
const layoutPaths: string[] = []
10361036

10371037
if (this.appPathRoutes) {

‎packages/next/shared/lib/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const PHASE_DEVELOPMENT_SERVER = 'phase-development-server'
55
export const PHASE_TEST = 'phase-test'
66
export const PAGES_MANIFEST = 'pages-manifest.json'
77
export const APP_PATHS_MANIFEST = 'app-paths-manifest.json'
8+
export const APP_PATH_ROUTES_MANIFEST = 'app-path-routes-manifest.json'
89
export const BUILD_MANIFEST = 'build-manifest.json'
910
export const EXPORT_MARKER = 'export-marker.json'
1011
export const EXPORT_DETAIL = 'export-detail.json'

‎test/e2e/switchable-runtime/index.test.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ describe('Switchable runtime', () => {
8080
.click()
8181
.waitForElementByCss('.node-rsc-ssr')
8282

83-
expect(await browser.elementByCss('body').text()).toContain(
84-
'This is a SSR RSC page.'
83+
await check(
84+
() => browser.eval('document.documentElement.innerHTML'),
85+
/This is a SSR RSC page/
8586
)
8687
expect(flightRequest).toContain('/node-rsc-ssr?__flight__=1')
8788
})
@@ -94,8 +95,9 @@ describe('Switchable runtime', () => {
9495
.click()
9596
.waitForElementByCss('.node-rsc-ssg')
9697

97-
expect(await browser.elementByCss('body').text()).toContain(
98-
'This is a SSG RSC page.'
98+
await check(
99+
() => browser.eval('document.documentElement.innerHTML'),
100+
/This is a SSG RSC page/
99101
)
100102
})
101103

@@ -107,8 +109,9 @@ describe('Switchable runtime', () => {
107109
.click()
108110
.waitForElementByCss('.node-rsc')
109111

110-
expect(await browser.elementByCss('body').text()).toContain(
111-
'This is a static RSC page.'
112+
await check(
113+
() => browser.eval('document.documentElement.innerHTML'),
114+
/This is a static RSC page/
112115
)
113116
})
114117

0 commit comments

Comments
 (0)
Please sign in to comment.