Skip to content

Commit

Permalink
fix(next): properly pass layout-level maxDuration config to the chi…
Browse files Browse the repository at this point in the history
…ldren page segments on build (vercel#68793)

> [!NOTE]
> This PR is recommended to [hide
whitespace](https://github.blog/news-insights/product-news/ignore-white-space-in-code-review/)
when reviewing.

### What?

Fixed layouts to properly pass route segment config `maxDuration` to
their children page segments.

```tsx
// layout.tsx

export const maxDuration = 5

```

### Why?

- We separately handle the route segment configs on different places.
- `maxDuration` was missing logic to get value from the layouts unlike
[other route segment
configs](https://github.com/vercel/next.js/blob/canary/packages/next/src/build/utils.ts#L1636-L1652).

### How?

- Instead of explicit logic for the `maxDuration`, get the route segment
configs from the layout on the page's static info.
- Ensure to inherit the value from the layout only if is a page segment.

#### See Changes by Commits

- current: 522b953
- expected: 12496d4
- fix: 196e0e8

Fixes NDX-196
  • Loading branch information
devjiwonchoi authored Aug 15, 2024
1 parent f1ca90f commit 9150f1b
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 60 deletions.
54 changes: 31 additions & 23 deletions packages/next/src/build/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,14 @@ import {
isInternalComponent,
isNonRoutePagesPage,
} from '../lib/is-internal-component'
import {
isMetadataRoute,
isStaticMetadataRouteFile,
} from '../lib/metadata/is-metadata-route'
import { isMetadataRoute } from '../lib/metadata/is-metadata-route'
import { RouteKind } from '../server/route-kind'
import { encodeToBase64 } from './webpack/loaders/utils'
import { normalizeCatchAllRoutes } from './normalize-catchall-routes'
import type { PageExtensions } from './page-extensions-type'
import type { MappedPages } from './build-context'
import { PAGE_TYPES } from '../lib/page-types'
import { isAppPageRoute } from '../lib/is-app-page-route'

export function sortByPageExts(pageExtensions: PageExtensions) {
return (a: string, b: string) => {
Expand Down Expand Up @@ -119,17 +117,21 @@ export async function getStaticInfoIncludingLayouts({
pageFilePath,
isDev,
page,
// TODO: sync types for pages: PAGE_TYPES, ROUTER_TYPE, 'app' | 'pages', etc.
pageType: isInsideAppDir ? PAGE_TYPES.APP : PAGE_TYPES.PAGES,
})

const staticInfo: PageStaticInfo = isInsideAppDir
? {
// TODO-APP: Remove the rsc key altogether. It's no longer required.
rsc: 'server',
}
: pageStaticInfo
if (!isInsideAppDir || !appDir) {
return pageStaticInfo
}

if (isInsideAppDir && appDir) {
const staticInfo: PageStaticInfo = {
// TODO-APP: Remove the rsc key altogether. It's no longer required.
rsc: 'server',
}

// inherit from layout files only if it's a page route
if (isAppPageRoute(page)) {
const layoutFiles = []
const potentialLayoutFiles = pageExtensions.map((ext) => 'layout.' + ext)
let dir = dirname(pageFilePath)
Expand Down Expand Up @@ -162,22 +164,28 @@ export async function getStaticInfoIncludingLayouts({
if (layoutStaticInfo.preferredRegion) {
staticInfo.preferredRegion = layoutStaticInfo.preferredRegion
}
if (layoutStaticInfo.extraConfig) {
staticInfo.extraConfig = {
...staticInfo.extraConfig,
...layoutStaticInfo.extraConfig,
}
}
}
}

if (pageStaticInfo.runtime) {
staticInfo.runtime = pageStaticInfo.runtime
}
if (pageStaticInfo.preferredRegion) {
staticInfo.preferredRegion = pageStaticInfo.preferredRegion
}

// if it's static metadata route, don't inherit runtime from layout
const relativePath = pageFilePath.replace(appDir, '')
if (isStaticMetadataRouteFile(relativePath)) {
delete staticInfo.runtime
delete staticInfo.preferredRegion
if (pageStaticInfo.runtime) {
staticInfo.runtime = pageStaticInfo.runtime
}
if (pageStaticInfo.preferredRegion) {
staticInfo.preferredRegion = pageStaticInfo.preferredRegion
}
if (pageStaticInfo.extraConfig) {
staticInfo.extraConfig = {
...staticInfo.extraConfig,
...pageStaticInfo.extraConfig,
}
}

return staticInfo
}

Expand Down
26 changes: 17 additions & 9 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,13 @@ import {
} from '../telemetry/events'
import type { EventBuildFeatureUsage } from '../telemetry/events'
import { Telemetry } from '../telemetry/storage'
import { hadUnsupportedValue } from './analysis/get-page-static-info'
import {
getPageStaticInfo,
hadUnsupportedValue,
} from './analysis/get-page-static-info'
import { createPagesMapping, getPageFromPath, sortByPageExts } from './entries'
createPagesMapping,
getPageFromPath,
getStaticInfoIncludingLayouts,
sortByPageExts,
} from './entries'
import { PAGE_TYPES } from '../lib/page-types'
import { generateBuildId } from './generate-build-id'
import { isWriteable } from './is-writeable'
Expand Down Expand Up @@ -2018,13 +2020,19 @@ export default async function build(
pagePath
)

const isInsideAppDir = pageType === 'app'
const staticInfo = pagePath
? await getPageStaticInfo({
? await getStaticInfoIncludingLayouts({
isInsideAppDir,
pageFilePath,
nextConfig: config,
// TODO: fix type mismatch
pageType:
pageType === 'app' ? PAGE_TYPES.APP : PAGE_TYPES.PAGES,
pageExtensions: config.pageExtensions,
appDir,
config,
isDev: false,
// If this route is an App Router page route, inherit the
// route segment configs (e.g. `runtime`) from the layout by
// passing the `originalAppPath`, which should end with `/page`.
page: isInsideAppDir ? originalAppPath! : page,
})
: undefined

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default function Page() {
return <p>app-layout</p>
}

// overwrite ../layout's maxDuration
export const maxDuration = 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function Layout({ children }: { children: React.ReactNode }) {
return <>{children}</>
}

export const maxDuration = 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <p>app-layout</p>
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,38 @@ describe('with-exported-function-config', () => {
await next.readFile('.next/server/functions-config-manifest.json')
)

expect(functionsConfigManifest).toMatchInlineSnapshot(`
{
"functions": {
"/api/page-route": {
"maxDuration": 1,
},
"/app-route": {
"maxDuration": 1,
},
"/app-route-edge": {
"maxDuration": 2,
},
"/app-ssr": {
"maxDuration": 3,
},
"/app-ssr-edge": {
"maxDuration": 4,
},
"/page": {
"maxDuration": 2,
},
"/page-ssr": {
"maxDuration": 3,
},
},
"version": 1,
}
`)
expect(functionsConfigManifest).toEqual({
functions: {
'/api/page-route': {
maxDuration: 1,
},
'/app-layout': {
maxDuration: 1,
},
'/app-layout/inner': {
maxDuration: 2,
},
'/app-route': {
maxDuration: 1,
},
'/app-route-edge': {
maxDuration: 2,
},
'/app-ssr': {
maxDuration: 3,
},
'/app-ssr-edge': {
maxDuration: 4,
},
'/page': {
maxDuration: 2,
},
'/page-ssr': {
maxDuration: 3,
},
},
version: 1,
})
}
})
})

0 comments on commit 9150f1b

Please sign in to comment.