Skip to content

Commit

Permalink
Ensure metadata routes dont skip static optimization (#66097)
Browse files Browse the repository at this point in the history
Follow-up to #65825 this ensures
we don't skip the static optimization specifically for metadata routes
as this most often should be static as they aren't dynamic content and
are requested very frequently.
  • Loading branch information
ijjk committed May 22, 2024
1 parent fa42f0d commit 0329a8f
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 2 deletions.
15 changes: 13 additions & 2 deletions packages/next/src/export/routes/app-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import { SERVER_DIRECTORY } from '../../shared/lib/constants'
import { hasNextSupport } from '../../telemetry/ci-info'
import { isStaticGenEnabled } from '../../server/future/route-modules/app-route/helpers/is-static-gen-enabled'
import type { ExperimentalConfig } from '../../server/config-shared'
import {
isMetadataRouteFile,
isStaticMetadataRoute,
} from '../../lib/metadata/is-metadata-route'
import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths'

export const enum ExportedAppRouteFiles {
BODY = 'BODY',
Expand Down Expand Up @@ -89,8 +94,14 @@ export async function exportAppRoute(
// Route module loading and handling.
const module = await RouteModuleLoader.load<AppRouteRouteModule>(filename)
const userland = module.userland

if (!isStaticGenEnabled(userland)) {
// we don't bail from the static optimization for
// metadata routes
const normalizedPage = normalizeAppPath(page)
const isMetadataRoute =
isStaticMetadataRoute(normalizedPage) ||
isMetadataRouteFile(`${normalizedPage}.ts`, ['ts'], true)

if (!isStaticGenEnabled(userland) && !isMetadataRoute) {
return { revalidate: 0 }
}

Expand Down
37 changes: 37 additions & 0 deletions test/production/app-dir/metadata-static/app/favicon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ImageResponse } from 'next/og'

// Image metadata
export const size = {
width: 32,
height: 32,
}
export const contentType = 'image/png'

// Image generation
export default function Icon() {
return new ImageResponse(
(
// ImageResponse JSX element
<div
style={{
fontSize: 24,
background: 'black',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
}}
>
A
</div>
),
// ImageResponse options
{
// For convenience, we can re-use the exported icons size metadata
// config to also set the ImageResponse's width and height.
...size,
}
)
}
20 changes: 20 additions & 0 deletions test/production/app-dir/metadata-static/app/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { MetadataRoute } from 'next'

export default function manifest(): MetadataRoute.Manifest {
return {
name: 'Next.js App',
short_name: 'Next.js App',
description: 'Next.js App',
start_url: '/',
display: 'standalone',
background_color: '#fff',
theme_color: '#fff',
icons: [
{
src: '/favicon.ico',
sizes: 'any',
type: 'image/x-icon',
},
],
}
}
38 changes: 38 additions & 0 deletions test/production/app-dir/metadata-static/app/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ImageResponse } from 'next/og'

// Image metadata
export const alt = 'About Acme'
export const size = {
width: 1200,
height: 630,
}

export const contentType = 'image/png'

// Image generation
export default async function Image() {
return new ImageResponse(
(
// ImageResponse JSX element
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
About Acme
</div>
),
// ImageResponse options
{
// For convenience, we can re-use the exported opengraph-image
// size config to also set the ImageResponse's width and height.
...size,
}
)
}
12 changes: 12 additions & 0 deletions test/production/app-dir/metadata-static/app/robots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { MetadataRoute } from 'next'

export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: '/private/',
},
sitemap: 'https://acme.com/sitemap.xml',
}
}
24 changes: 24 additions & 0 deletions test/production/app-dir/metadata-static/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { MetadataRoute } from 'next'

export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: 'https://acme.com',
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
},
{
url: 'https://acme.com/about',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: 'https://acme.com/blog',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.5,
},
]
}
27 changes: 27 additions & 0 deletions test/production/app-dir/metadata-static/metadata-static.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { nextTestSetup } from 'e2e-utils'

describe('app dir - metadata', () => {
const { next } = nextTestSetup({
files: __dirname,
})

it('should have statically optimized metadata routes by default', async () => {
const prerenderManifest = JSON.parse(
await next.readFile('.next/prerender-manifest.json')
)

for (const key of [
'/robots.txt',
'/sitemap',
'/opengraph-image',
'/manifest.webmanifest',
]) {
expect(prerenderManifest.routes[key]).toBeTruthy()
expect(prerenderManifest.routes[key].initialRevalidateSeconds).toBe(false)

const res = await next.fetch(key)
expect(res.status).toBe(200)
expect(res.headers.get('x-nextjs-cache')).toBe('HIT')
}
})
})
7 changes: 7 additions & 0 deletions test/turbopack-build-tests-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14684,6 +14684,13 @@
"flakey": [],
"runtimeError": false
},
"test/production/app-dir/metadata-static/metadata-static.test.ts": {
"passed": [],
"pending": [],
"failed": [
"app dir - metadata should have statically optimized metadata routes by default"
]
},
"test/production/allow-development-build/allow-development-build.test.ts": {
"passed": [
"allow-development-build with NODE_ENV not set to development should fail the build with a message about not setting NODE_ENV",
Expand Down

0 comments on commit 0329a8f

Please sign in to comment.