Skip to content

Commit 441a235

Browse files
authored
Skip client reference manifests for static metadata route handlers (#74876)
Fixes a regression caused by #74835. [x-ref](https://github.com/vercel/next.js/actions/runs/12773698779/job/35607288377)
1 parent 213c710 commit 441a235

File tree

5 files changed

+69
-19
lines changed

5 files changed

+69
-19
lines changed

Diff for: packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const cacheHeader = {
4141
revalidate: 'public, max-age=0, must-revalidate',
4242
}
4343

44-
type MetadataRouteLoaderOptions = {
44+
export type MetadataRouteLoaderOptions = {
4545
// Using separate argument to avoid json being parsed and hit error
4646
// x-ref: https://github.com/vercel/next.js/pull/62615
4747
filePath: string

Diff for: packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import { getModuleBuildInfo } from '../loaders/get-module-build-info'
4545
import { getAssumedSourceType } from '../loaders/next-flight-loader'
4646
import { isAppRouteRoute } from '../../../lib/is-app-route-route'
4747
import { isMetadataRoute } from '../../../lib/metadata/is-metadata-route'
48+
import type { MetadataRouteLoaderOptions } from '../loaders/next-metadata-route-loader'
4849

4950
interface Options {
5051
dev: boolean
@@ -305,7 +306,12 @@ export class FlightClientEntryPlugin {
305306
).request
306307

307308
if (entryRequest.endsWith(WEBPACK_RESOURCE_QUERIES.metadataRoute)) {
308-
entryRequest = getMetadataRouteResource(entryRequest)
309+
const { filePath, isDynamicRouteExtension } =
310+
getMetadataRouteResource(entryRequest)
311+
312+
if (isDynamicRouteExtension === '1') {
313+
entryRequest = filePath
314+
}
309315
}
310316

311317
const { clientComponentImports, actionImports, cssImports } =
@@ -1110,14 +1116,15 @@ function getModuleResource(mod: webpack.NormalModule): string {
11101116
}
11111117

11121118
if (mod.resource === `?${WEBPACK_RESOURCE_QUERIES.metadataRoute}`) {
1113-
return getMetadataRouteResource(mod.rawRequest)
1119+
return getMetadataRouteResource(mod.rawRequest).filePath
11141120
}
11151121

11161122
return modResource
11171123
}
11181124

1119-
function getMetadataRouteResource(request: string): string {
1120-
const query = request.split('next-metadata-route-loader?')[1]
1125+
function getMetadataRouteResource(request: string): MetadataRouteLoaderOptions {
1126+
// e.g. next-metadata-route-loader?filePath=<some-url-encoded-path>&isDynamicRouteExtension=1!?__next_metadata_route__
1127+
const query = request.split('!')[0].split('next-metadata-route-loader?')[1]
11211128

1122-
return parse(query).filePath as string
1129+
return parse(query) as MetadataRouteLoaderOptions
11231130
}

Diff for: packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts

+28-12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import picomatch from 'next/dist/compiled/picomatch'
1919
import { getModuleBuildInfo } from '../loaders/get-module-build-info'
2020
import { getPageFilePath } from '../../entries'
2121
import { resolveExternal } from '../../handle-externals'
22+
import { isStaticMetadataRoute } from '../../../lib/metadata/is-metadata-route'
2223

2324
const PLUGIN_NAME = 'TraceEntryPointsPlugin'
2425
export const TRACE_IGNORES = [
@@ -115,6 +116,7 @@ export interface BuildTraceContext {
115116
outputPath: string
116117
depModArray: string[]
117118
entryNameMap: Record<string, string>
119+
absolutePathByEntryName: Record<string, string>
118120
}
119121
chunksTrace?: {
120122
action: TurbotraceAction
@@ -241,19 +243,28 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
241243
nodePath.join(outputPath, `${outputPrefix}${entrypoint.name}.js`)
242244
)
243245

244-
if (entrypoint.name.startsWith('app/')) {
245-
// include the client reference manifest
246-
const clientManifestsForEntrypoint = nodePath.join(
247-
outputPath,
248-
outputPrefix,
249-
entrypoint.name.replace(/%5F/g, '_') +
250-
'_' +
251-
CLIENT_REFERENCE_MANIFEST +
252-
'.js'
253-
)
246+
if (entrypoint.name.startsWith('app/') && this.appDir) {
247+
const appDirRelativeEntryPath =
248+
this.buildTraceContext.entriesTrace?.absolutePathByEntryName[
249+
entrypoint.name
250+
]?.replace(this.appDir, '')
254251

255-
if (clientManifestsForEntrypoint !== null) {
256-
entryFiles.add(clientManifestsForEntrypoint)
252+
// Include the client reference manifest in the trace, but not for
253+
// static metadata routes, for which we don't generate those.
254+
if (
255+
appDirRelativeEntryPath &&
256+
!isStaticMetadataRoute(appDirRelativeEntryPath)
257+
) {
258+
entryFiles.add(
259+
nodePath.join(
260+
outputPath,
261+
outputPrefix,
262+
entrypoint.name.replace(/%5F/g, '_') +
263+
'_' +
264+
CLIENT_REFERENCE_MANIFEST +
265+
'.js'
266+
)
267+
)
257268
}
258269
}
259270

@@ -315,6 +326,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
315326
const entryNameMap = new Map<string, string>()
316327
const entryModMap = new Map<string, any>()
317328
const additionalEntries = new Map<string, Map<string, any>>()
329+
const absolutePathByEntryName = new Map<string, string>()
318330

319331
const depModMap = new Map<string, any>()
320332

@@ -356,6 +368,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
356368
) {
357369
entryModMap.set(absolutePath, entryMod)
358370
entryNameMap.set(absolutePath, name)
371+
absolutePathByEntryName.set(name, absolutePath)
359372
}
360373
}
361374

@@ -441,6 +454,9 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
441454
appDir: this.rootDir,
442455
depModArray: Array.from(depModMap.keys()),
443456
entryNameMap: Object.fromEntries(entryNameMap),
457+
absolutePathByEntryName: Object.fromEntries(
458+
absolutePathByEntryName
459+
),
444460
outputPath: compilation.outputOptions.path!,
445461
}
446462

Binary file not shown.

Diff for: test/e2e/app-dir/use-cache-metadata-route-handler/use-cache-metadata-route-handler.test.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { nextTestSetup } from 'e2e-utils'
22

33
describe('use-cache-metadata-route-handler', () => {
4-
const { next, isNextDev, isNextStart } = nextTestSetup({
4+
const { next, isNextDev, isNextStart, isTurbopack } = nextTestSetup({
55
files: __dirname,
66
})
77

@@ -131,4 +131,31 @@ describe('use-cache-metadata-route-handler', () => {
131131
expect(body).toEqual({ name: 'buildtime' })
132132
}
133133
})
134+
135+
if (isNextStart && !isTurbopack) {
136+
it('should include the client reference manifest in the route.js.nft.json files of dynamic metadata routes', async () => {
137+
for (const filename of [
138+
'icon',
139+
'manifest.webmanifest',
140+
'opengraph-image',
141+
'products/sitemap/[__metadata_id__]',
142+
'robots.txt',
143+
'sitemap.xml',
144+
]) {
145+
const { files } = await next.readJSON(
146+
`/.next/server/app/${filename}/route.js.nft.json`
147+
)
148+
149+
expect(files).toInclude('route_client-reference-manifest.js')
150+
}
151+
})
152+
153+
it('should not include the client reference manifest in the route.js.nft.json files of static metadata routes', async () => {
154+
const { files } = await next.readJSON(
155+
'/.next/server/app/favicon.ico/route.js.nft.json'
156+
)
157+
158+
expect(files).not.toInclude('route_client-reference-manifest.js')
159+
})
160+
}
134161
})

0 commit comments

Comments
 (0)