Skip to content

Commit 0631549

Browse files
authored
Fix react packages are not bundled for metadata routes (#55579)
`isAppLayer` condition was missing `app-metadata-route` layer, made it as a util now like other webpack layer utils, add metadata route layer to the group. Then `React.cache` can be available there. Also update regex to be compatible across platform Fixes #55561 Closes NEXT-1635
1 parent bad5365 commit 0631549

File tree

6 files changed

+68
-20
lines changed

6 files changed

+68
-20
lines changed

packages/next/src/build/utils.ts

+6
Original file line numberDiff line numberDiff line change
@@ -2131,3 +2131,9 @@ export function isWebpackDefaultLayer(
21312131
): boolean {
21322132
return layer === null || layer === undefined
21332133
}
2134+
2135+
export function isWebpackAppLayer(
2136+
layer: WebpackLayerName | null | undefined
2137+
): boolean {
2138+
return Boolean(layer && WEBPACK_LAYERS.GROUP.app.includes(layer as any))
2139+
}

packages/next/src/build/webpack-config.ts

+20-19
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ import {
1919
WEBPACK_RESOURCE_QUERIES,
2020
WebpackLayerName,
2121
} from '../lib/constants'
22-
import { isWebpackDefaultLayer, isWebpackServerLayer } from './utils'
22+
import {
23+
isWebpackAppLayer,
24+
isWebpackDefaultLayer,
25+
isWebpackServerLayer,
26+
} from './utils'
2327
import { CustomRoutes } from '../lib/load-custom-routes.js'
2428
import { isEdgeRuntime } from '../lib/is-edge-runtime'
2529
import {
@@ -412,7 +416,7 @@ function createRSCAliases(
412416
}
413417

414418
if (!opts.isEdgeServer) {
415-
if (opts.layer === 'ssr') {
419+
if (opts.layer === WEBPACK_LAYERS.serverSideRendering) {
416420
alias = Object.assign(alias, {
417421
'react/jsx-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-runtime`,
418422
'react/jsx-dev-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-dev-runtime`,
@@ -421,7 +425,7 @@ function createRSCAliases(
421425
'react-dom/server.edge$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-dom-server-edge`,
422426
'react-server-dom-webpack/client.edge$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-server-dom-webpack-client-edge`,
423427
})
424-
} else if (opts.layer === 'rsc') {
428+
} else if (opts.layer === WEBPACK_LAYERS.reactServerComponents) {
425429
alias = Object.assign(alias, {
426430
'react/jsx-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-runtime`,
427431
'react/jsx-dev-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-dev-runtime`,
@@ -434,7 +438,7 @@ function createRSCAliases(
434438
}
435439

436440
if (opts.isEdgeServer) {
437-
if (opts.layer === 'rsc') {
441+
if (opts.layer === WEBPACK_LAYERS.reactServerComponents) {
438442
alias[
439443
'react$'
440444
] = `next/dist/compiled/react${bundledReactChannel}/react.shared-subset`
@@ -1383,15 +1387,7 @@ export default async function getBaseWebpackConfig(
13831387
return `commonjs next/dist/lib/import-next-warning`
13841388
}
13851389

1386-
const isAppLayer = (
1387-
[
1388-
WEBPACK_LAYERS.reactServerComponents,
1389-
WEBPACK_LAYERS.serverSideRendering,
1390-
WEBPACK_LAYERS.appPagesBrowser,
1391-
WEBPACK_LAYERS.actionBrowser,
1392-
WEBPACK_LAYERS.appRouteHandler,
1393-
] as WebpackLayerName[]
1394-
).includes(layer!)
1390+
const isAppLayer = isWebpackAppLayer(layer)
13951391

13961392
// Relative requires don't need custom resolution, because they
13971393
// are relative to requests we've already resolved here.
@@ -1461,25 +1457,30 @@ export default async function getBaseWebpackConfig(
14611457
// Specific Next.js imports that should remain external
14621458
// TODO-APP: Investigate if we can remove this.
14631459
if (request.startsWith('next/dist/')) {
1460+
// Non external that needs to be transpiled
14641461
// Image loader needs to be transpiled
1465-
if (/^next\/dist\/shared\/lib\/image-loader/.test(request)) {
1462+
if (/^next[\\/]dist[\\/]shared[\\/]lib[\\/]image-loader/.test(request)) {
14661463
return
14671464
}
14681465

1469-
if (/^next\/dist\/compiled\/next-server/.test(request)) {
1466+
if (/^next[\\/]dist[\\/]compiled[\\/]next-server/.test(request)) {
14701467
return `commonjs ${request}`
14711468
}
14721469

14731470
if (
1474-
/^next\/dist\/shared\/(?!lib\/router\/router)/.test(request) ||
1475-
/^next\/dist\/compiled\/.*\.c?js$/.test(request)
1471+
/^next[\\/]dist[\\/]shared[\\/](?!lib[\\/]router[\\/]router)/.test(
1472+
request
1473+
) ||
1474+
/^next[\\/]dist[\\/]compiled[\\/].*\.c?js$/.test(request)
14761475
) {
14771476
return `commonjs ${request}`
14781477
}
14791478

14801479
if (
1481-
/^next\/dist\/esm\/shared\/(?!lib\/router\/router)/.test(request) ||
1482-
/^next\/dist\/compiled\/.*\.mjs$/.test(request)
1480+
/^next[\\/]dist[\\/]esm[\\/]shared[\\/](?!lib[\\/]router[\\/]router)/.test(
1481+
request
1482+
) ||
1483+
/^next[\\/]dist[\\/]compiled[\\/].*\.mjs$/.test(request)
14831484
) {
14841485
return `module ${request}`
14851486
}

packages/next/src/lib/constants.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ const WEBPACK_LAYERS_NAMES = {
107107
*/
108108
reactServerComponents: 'rsc',
109109
/**
110-
* Server Side Rendering layer (ssr).
110+
* Server Side Rendering layer for app (ssr).
111111
*/
112112
serverSideRendering: 'ssr',
113113
/**
@@ -157,6 +157,14 @@ const WEBPACK_LAYERS = {
157157
WEBPACK_LAYERS_NAMES.middleware,
158158
WEBPACK_LAYERS_NAMES.api,
159159
],
160+
app: [
161+
WEBPACK_LAYERS_NAMES.reactServerComponents,
162+
WEBPACK_LAYERS_NAMES.actionBrowser,
163+
WEBPACK_LAYERS_NAMES.appMetadataRoute,
164+
WEBPACK_LAYERS_NAMES.appRouteHandler,
165+
WEBPACK_LAYERS_NAMES.serverSideRendering,
166+
WEBPACK_LAYERS_NAMES.appPagesBrowser,
167+
],
160168
},
161169
}
162170

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use client'
2+
3+
import React from 'react'
4+
5+
function ClientComponent() {
6+
const [state] = React.useState('component')
7+
return <div>{`client-` + state}</div>
8+
}
9+
10+
export const clientRef = <ClientComponent />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react'
2+
import { clientRef } from './client-component'
3+
4+
export const contentType = 'image/png'
5+
const cachedNoop = React.cache(() => null)
6+
7+
function noopCall(value) {
8+
return value
9+
}
10+
11+
export default function sitemap() {
12+
// keep the variable from being tree-shaken
13+
noopCall(clientRef)
14+
cachedNoop()
15+
return []
16+
}

test/e2e/app-dir/metadata-dynamic-routes/index.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ createNextDescribe(
6666
"
6767
`)
6868
})
69+
70+
it('should not throw if client components are imported but not used', async () => {
71+
const { status } = await next.fetch(
72+
'/client-ref-dependency/sitemap.xml'
73+
)
74+
expect(status).toBe(200)
75+
})
6976
})
7077

7178
describe('social image routes', () => {

0 commit comments

Comments
 (0)