Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix metadata layer webpack rule for server-only #52403

Merged
merged 6 commits into from
Jul 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
100 changes: 46 additions & 54 deletions packages/next/src/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ const NEXT_PROJECT_ROOT_DIST_CLIENT = path.join(
'client'
)

const isWebpackServerLayer = (layer: string | null) =>
Boolean(layer && WEBPACK_LAYERS.GROUP.server.includes(layer))

if (parseInt(React.version) < 18) {
throw new Error('Next.js requires react >= 18.2.0 to be installed.')
}
Expand Down Expand Up @@ -1400,7 +1403,7 @@ export default async function getBaseWebpackConfig(
// so that the DefinePlugin can inject process.env values.

// Treat next internals as non-external for server layer
if (layer === WEBPACK_LAYERS.server || layer === WEBPACK_LAYERS.action) {
if (isWebpackServerLayer(layer)) {
return
}

Expand Down Expand Up @@ -1430,7 +1433,7 @@ export default async function getBaseWebpackConfig(
// Don't bundle @vercel/og nodejs bundle for nodejs runtime.
// TODO-APP: bundle route.js with different layer that externals common node_module deps.
if (
layer === WEBPACK_LAYERS.server &&
isWebpackServerLayer(layer) &&
request === 'next/dist/compiled/@vercel/og/index.node.js'
) {
return `module ${request}`
Expand Down Expand Up @@ -1574,7 +1577,7 @@ export default async function getBaseWebpackConfig(
(isEsm && isAppLayer)

if (/node_modules[/\\].*\.[mc]?js$/.test(res)) {
if (layer === WEBPACK_LAYERS.server || layer === WEBPACK_LAYERS.action) {
if (isWebpackServerLayer(layer)) {
// All packages should be bundled for the server layer if they're not opted out.
// This option takes priority over the transpilePackages option.

Expand Down Expand Up @@ -1944,6 +1947,13 @@ export default async function getBaseWebpackConfig(
layer: WEBPACK_LAYERS.shared,
test: asyncStoragesRegex,
},
// Convert metadata routes to separate layer
{
resourceQuery: new RegExp(
WEBPACK_RESOURCE_QUERIES.metadataRoute
),
layer: WEBPACK_LAYERS.metadataRoute,
},
{
// All app dir layers need to use this configured resolution logic
issuerLayer: {
Expand Down Expand Up @@ -1979,7 +1989,7 @@ export default async function getBaseWebpackConfig(
? [
{
issuerLayer: {
or: [WEBPACK_LAYERS.server, WEBPACK_LAYERS.action],
or: [isWebpackServerLayer],
},
test: {
// Resolve it if it is a source code file, and it has NOT been
Expand All @@ -1993,18 +2003,16 @@ export default async function getBaseWebpackConfig(
},
resolve: {
conditionNames: reactServerCondition,
alias: {
// If missing the alias override here, the default alias will be used which aliases
// react to the direct file path, not the package name. In that case the condition
// will be ignored completely.
...createRSCAliases(bundledReactChannel, {
reactSharedSubset: true,
reactDomServerRenderingStub: true,
reactServerCondition: true,
// No server components profiling
reactProductionProfiling,
}),
},
// If missing the alias override here, the default alias will be used which aliases
// react to the direct file path, not the package name. In that case the condition
// will be ignored completely.
alias: createRSCAliases(bundledReactChannel, {
reactSharedSubset: true,
reactDomServerRenderingStub: true,
reactServerCondition: true,
// No server components profiling
reactProductionProfiling,
}),
},
use: {
loader: 'next-flight-loader',
Expand All @@ -2024,16 +2032,6 @@ export default async function getBaseWebpackConfig(
} as any,
]
: []),
...(hasAppDir
? [
{
resourceQuery: new RegExp(
WEBPACK_RESOURCE_QUERIES.metadataRoute
),
layer: WEBPACK_LAYERS.metadataImage,
},
]
: []),
...(hasAppDir && isEdgeServer
? [
// The Edge bundle includes the server in its entrypoint, so it has to
Expand All @@ -2056,7 +2054,7 @@ export default async function getBaseWebpackConfig(
{
exclude: [asyncStoragesRegex],
issuerLayer: {
or: [WEBPACK_LAYERS.server, WEBPACK_LAYERS.action],
or: [isWebpackServerLayer],
},
test: {
// Resolve it if it is a source code file, and it has NOT been
Expand All @@ -2071,28 +2069,24 @@ export default async function getBaseWebpackConfig(
resolve: {
// It needs `conditionNames` here to require the proper asset,
// when react is acting as dependency of compiled/react-dom.
alias: {
...createRSCAliases(bundledReactChannel, {
reactSharedSubset: true,
reactDomServerRenderingStub: true,
reactServerCondition: true,
reactProductionProfiling,
}),
},
alias: createRSCAliases(bundledReactChannel, {
reactSharedSubset: true,
reactDomServerRenderingStub: true,
reactServerCondition: true,
reactProductionProfiling,
}),
},
},
{
test: codeCondition.test,
issuerLayer: WEBPACK_LAYERS.client,
resolve: {
alias: {
...createRSCAliases(bundledReactChannel, {
reactSharedSubset: false,
reactDomServerRenderingStub: true,
reactServerCondition: false,
reactProductionProfiling,
}),
},
alias: createRSCAliases(bundledReactChannel, {
reactSharedSubset: false,
reactDomServerRenderingStub: true,
reactServerCondition: false,
reactProductionProfiling,
}),
},
},
],
Expand All @@ -2101,15 +2095,13 @@ export default async function getBaseWebpackConfig(
test: codeCondition.test,
issuerLayer: WEBPACK_LAYERS.appClient,
resolve: {
alias: {
...createRSCAliases(bundledReactChannel, {
// Only alias server rendering stub in client SSR layer.
reactSharedSubset: false,
reactDomServerRenderingStub: false,
reactServerCondition: false,
reactProductionProfiling,
}),
},
alias: createRSCAliases(bundledReactChannel, {
// Only alias server rendering stub in client SSR layer.
reactSharedSubset: false,
reactDomServerRenderingStub: false,
reactServerCondition: false,
reactProductionProfiling,
}),
},
},
]
Expand All @@ -2135,7 +2127,7 @@ export default async function getBaseWebpackConfig(
{
test: codeCondition.test,
issuerLayer: {
or: [WEBPACK_LAYERS.server, WEBPACK_LAYERS.action],
or: [isWebpackServerLayer],
},
exclude: [asyncStoragesRegex],
use: swcLoaderForServerLayer,
Expand Down Expand Up @@ -2315,7 +2307,7 @@ export default async function getBaseWebpackConfig(
test: /(node_modules|next[/\\]dist[/\\]compiled)[/\\]client-only[/\\]error.js/,
loader: 'next-invalid-import-error-loader',
issuerLayer: {
or: [WEBPACK_LAYERS.server, WEBPACK_LAYERS.action],
or: [isWebpackServerLayer],
},
options: {
message:
Expand Down
15 changes: 13 additions & 2 deletions packages/next/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const SERVER_RUNTIME: Record<string, ServerRuntime> = {
nodejs: 'nodejs',
}

export const WEBPACK_LAYERS = {
const WEBPACK_LAYERS_NAMES = {
shared: 'sc_shared',
server: 'sc_server',
client: 'sc_client',
Expand All @@ -95,7 +95,18 @@ export const WEBPACK_LAYERS = {
middleware: 'middleware',
edgeAsset: 'edge-asset',
appClient: 'app-client',
metadataImage: 'app-metadata-image',
metadataRoute: 'app-metadata-route',
}

export const WEBPACK_LAYERS = {
...WEBPACK_LAYERS_NAMES,
GROUP: {
server: [
WEBPACK_LAYERS_NAMES.server,
WEBPACK_LAYERS_NAMES.action,
WEBPACK_LAYERS_NAMES.metadataRoute,
],
},
}

export const WEBPACK_RESOURCE_QUERIES = {
Expand Down
1 change: 1 addition & 0 deletions test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'server-only'
import { MetadataRoute } from 'next'

export default function sitemap(): MetadataRoute.Sitemap {
Expand Down