Repository: vercel/next.js
Pull request: fix: skip collecting metadata for app-error in webpack

In nextjs 16, we're generating static 500.html from app router, which is an empty page with out any user side custom stuff. However in webpack bundler next-app-loader there's a phase that we're collecting static metadata files for the page and we collected the static files for the static 500.html. So when you have a static og image file, it will be collected and nextjs will try to resolve the absolute url. Even the `metadataBase` is set in root layout, because the 500.html is not sharing any layout with user side, (it's a simple and fixed static page, again) so it will warn that metadataBase is not set.

The solution is to avoid collect static metadata files for that static 500 page, which is only used on deployment, and mostly in app router pages there's no technically server errored page yet, so it won't be used for most of the case.

Reported by @SukkaW 

Closes NXT-112

Changed files:
filename: packages/next/src/build/webpack/loaders/next-app-loader/index.ts
patch: @@ -38,6 +38,7 @@ import { PARALLEL_ROUTE_DEFAULT_PATH } from '../../../../client/components/built
 import type { Compilation } from 'webpack'
 import { createAppRouteCode } from './create-app-route-code'
 import { MissingDefaultParallelRouteError } from '../../../../shared/lib/errors/missing-default-parallel-route-error'
+import { normalizePathSep } from '../../../../shared/lib/page-path/normalize-path-sep'
 
 export type AppLoaderOptions = {
   name: string
@@ -87,7 +88,7 @@ const PARALLEL_VIRTUAL_SEGMENT = 'slot$'
 const defaultGlobalErrorPath =
   'next/dist/client/components/builtin/global-error.js'
 const defaultNotFoundPath = 'next/dist/client/components/builtin/not-found.js'
-const defaultEmptyStubPath = 'next/dist/client/components/builtin/empty-stub'
+const defaultEmptyStubPath = 'next/dist/client/components/builtin/empty-stub.js'
 const defaultLayoutPath = 'next/dist/client/components/builtin/layout.js'
 const defaultGlobalNotFoundPath =
   'next/dist/client/components/builtin/global-not-found.js'
@@ -176,9 +177,7 @@ async function createTreeCodeFromPath(
   async function resolveAdjacentParallelSegments(
     segmentPath: string
   ): Promise<string[]> {
-    const absoluteSegmentPath = await resolveDir(
-      `${appDirPrefix}${segmentPath}`
-    )
+    const absoluteSegmentPath = resolveDir(`${appDirPrefix}${segmentPath}`)
 
     if (!absoluteSegmentPath) {
       return []
@@ -232,7 +231,11 @@ async function createTreeCodeFromPath(
     const routerDirPath = `${appDirPrefix}${segmentPath}`
     const resolvedRouteDir = resolveDir(routerDirPath)
 
-    if (resolvedRouteDir) {
+    if (
+      resolvedRouteDir &&
+      // Do not collect metadata for app-error route as it's for generating pure static 500.html
+      !normalizePathSep(pagePath).endsWith(appErrorPath)
+    ) {
       metadata = await createStaticMetadataFromRoute(resolvedRouteDir, {
         basePath,
         segment: segmentPath,

filename: test/production/app-dir/metadata-base-warning/app/layout.tsx
patch: @@ -0,0 +1,19 @@
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+  title: 'my title',
+  description: 'my description',
+  metadataBase: 'https://my-domain.com/',
+}
+
+export default function RootLayout({
+  children,
+}: Readonly<{
+  children: React.ReactNode
+}>) {
+  return (
+    <html>
+      <body>{children}</body>
+    </html>
+  )
+}

filename: test/production/app-dir/metadata-base-warning/app/page.tsx
patch: @@ -0,0 +1,7 @@
+export default function Home() {
+  return (
+    <div>
+      <h1>Hello World</h1>
+    </div>
+  )
+}

filename: test/production/app-dir/metadata-base-warning/metadata-base-warning.test.ts
patch: @@ -0,0 +1,13 @@
+import { nextTestSetup } from 'e2e-utils'
+
+describe('metadata-base-warning', () => {
+  const { next } = nextTestSetup({
+    files: __dirname,
+  })
+
+  it('should not warn metadataBase for static image when metadataBase is set', async () => {
+    expect(next.cliOutput).not.toContain(
+      'metadataBase property in metadata export is not set for resolving social open graph or twitter images'
+    )
+  })
+})

filename: test/production/app-dir/metadata-base-warning/next.config.js
patch: @@ -0,0 +1,6 @@
+/**
+ * @type {import('next').NextConfig}
+ */
+const nextConfig = {}
+
+module.exports = nextConfig