From 8062632e44136fe9375b17c9442727e30f07b859 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 26 Sep 2024 10:56:43 +0200 Subject: [PATCH 1/3] Respect reexports from metadata API routes --- .../loaders/next-metadata-route-loader.ts | 51 ++++++++++++------- .../metadata-revalidate/app/manifest.ts | 22 ++++++++ .../app/revalidate/og/opengraph-image.tsx | 24 +++++++++ .../app-dir/metadata-revalidate/app/robots.ts | 14 +++++ .../metadata-revalidate/app/sitemap.ts | 12 +++++ .../metadata-revalidate.test.ts | 31 +++++++++++ 6 files changed, 137 insertions(+), 17 deletions(-) create mode 100644 test/e2e/app-dir/metadata-revalidate/app/manifest.ts create mode 100644 test/e2e/app-dir/metadata-revalidate/app/revalidate/og/opengraph-image.tsx create mode 100644 test/e2e/app-dir/metadata-revalidate/app/robots.ts create mode 100644 test/e2e/app-dir/metadata-revalidate/app/sitemap.ts create mode 100644 test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts diff --git a/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts b/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts index e49475b52fb4c..14159ef2d3f5e 100644 --- a/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts @@ -14,6 +14,27 @@ function errorOnBadHandler(resourcePath: string) { ` } +/* re-export the userland route configs */ +async function createReExportsCode( + resourcePath: string, + loaderContext: webpack.LoaderContext +) { + const exportNames = await getLoaderModuleNamedExports( + resourcePath, + loaderContext + ) + // Re-export configs but avoid conflicted exports + const reExportNames = exportNames.filter( + (name) => name !== 'default' && name !== 'generateSitemaps' + ) + + return reExportNames.length > 0 + ? `export { ${reExportNames.join(', ')} } from ${JSON.stringify( + resourcePath + )}\n` + : '' +} + const cacheHeader = { none: 'no-cache, no-store', longCache: 'public, immutable, no-transform, max-age=31536000', @@ -85,7 +106,10 @@ export const dynamic = 'force-static' return code } -function getDynamicTextRouteCode(resourcePath: string) { +async function getDynamicTextRouteCode( + resourcePath: string, + loaderContext: webpack.LoaderContext +) { return `\ /* dynamic asset route */ import { NextResponse } from 'next/server' @@ -96,6 +120,7 @@ const contentType = ${JSON.stringify(getContentType(resourcePath))} const fileType = ${JSON.stringify(getFilenameAndExtension(resourcePath).name)} ${errorOnBadHandler(resourcePath)} +${await createReExportsCode(resourcePath, loaderContext)} export async function GET() { const data = await handler() @@ -112,7 +137,10 @@ export async function GET() { } // /[id]/route.js -function getDynamicImageRouteCode(resourcePath: string) { +async function getDynamicImageRouteCode( + resourcePath: string, + loaderContext: webpack.LoaderContext +) { return `\ /* dynamic image route */ import { NextResponse } from 'next/server' @@ -124,6 +152,7 @@ const handler = imageModule.default const generateImageMetadata = imageModule.generateImageMetadata ${errorOnBadHandler(resourcePath)} +${await createReExportsCode(resourcePath, loaderContext)} export async function GET(_, ctx) { const { __metadata_id__, ...params } = ctx.params || {} @@ -162,10 +191,6 @@ async function getDynamicSitemapRouteCode( resourcePath, loaderContext ) - // Re-export configs but avoid conflicted exports - const reExportNames = exportNames.filter( - (name) => name !== 'default' && name !== 'generateSitemaps' - ) const hasGenerateSitemaps = exportNames.includes('generateSitemaps') @@ -195,15 +220,7 @@ const contentType = ${JSON.stringify(getContentType(resourcePath))} const fileType = ${JSON.stringify(getFilenameAndExtension(resourcePath).name)} ${errorOnBadHandler(resourcePath)} - -${'' /* re-export the userland route configs */} -${ - reExportNames.length > 0 - ? `export { ${reExportNames.join(', ')} } from ${JSON.stringify( - resourcePath - )}\n` - : '' -} +${await createReExportsCode(resourcePath, loaderContext)} export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = ctx.params || {} @@ -253,11 +270,11 @@ const nextMetadataRouterLoader: webpack.LoaderDefinitionFunction + Open Graph + + ) + ) +} + +export const revalidate = 5 diff --git a/test/e2e/app-dir/metadata-revalidate/app/robots.ts b/test/e2e/app-dir/metadata-revalidate/app/robots.ts new file mode 100644 index 0000000000000..83daa5af5f719 --- /dev/null +++ b/test/e2e/app-dir/metadata-revalidate/app/robots.ts @@ -0,0 +1,14 @@ +import type { MetadataRoute } from 'next' + +export default function robots(): MetadataRoute.Robots { + return { + rules: { + userAgent: '*', + allow: '/', + disallow: '/private/', + }, + sitemap: 'https://acme.com/sitemap.xml', + } +} + +export const revalidate = 5 diff --git a/test/e2e/app-dir/metadata-revalidate/app/sitemap.ts b/test/e2e/app-dir/metadata-revalidate/app/sitemap.ts new file mode 100644 index 0000000000000..8f301a61ef068 --- /dev/null +++ b/test/e2e/app-dir/metadata-revalidate/app/sitemap.ts @@ -0,0 +1,12 @@ +export default function sitemap() { + return [ + { + url: 'https://acme.com', + lastModified: new Date(), + changeFrequency: 'yearly', + priority: 1, + }, + ] +} + +export const revalidate = 5 diff --git a/test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts b/test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts new file mode 100644 index 0000000000000..b046c05077d5d --- /dev/null +++ b/test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts @@ -0,0 +1,31 @@ +import { nextTestSetup } from 'e2e-utils' + +describe('app-dir - metadata-revalidate', () => { + const { next, isNextStart } = nextTestSetup({ + files: __dirname, + }) + + it('should contain the routes in prerender manifest', async () => { + if (isNextStart) { + const manifestContent = await next.readFile( + '.next/prerender-manifest.json' + ) + const prerenderManifest = JSON.parse(manifestContent) + + expect( + prerenderManifest.routes['/revalidate/og/opengraph-image'] + .initialRevalidateSeconds + ).toBe(5) + expect( + prerenderManifest.routes['/manifest.webmanifest'] + .initialRevalidateSeconds + ).toBe(5) + expect( + prerenderManifest.routes['/robots.txt'].initialRevalidateSeconds + ).toBe(5) + expect( + prerenderManifest.routes['/sitemap.xml'].initialRevalidateSeconds + ).toBe(5) + } + }) +}) From ef61ba84581a3cec3e066aa472b6108243ccbe5c Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 26 Sep 2024 11:24:39 +0200 Subject: [PATCH 2/3] update turbopack manifest --- test/turbopack-build-tests-manifest.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/turbopack-build-tests-manifest.json b/test/turbopack-build-tests-manifest.json index 0e4ba5ab383e2..f11f6f2e96b94 100644 --- a/test/turbopack-build-tests-manifest.json +++ b/test/turbopack-build-tests-manifest.json @@ -2191,6 +2191,15 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts": { + "passed": [], + "failed": [ + "app-dir - metadata-revalidate should contain the routes in prerender manifest" + ], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/metadata-warnings/index.test.ts": { "passed": [ "app dir - metadata missing metadataBase should not warn for viewport properties during manually merging metadata", From e3103288b6d105880e664bf86e20f839be738373 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 26 Sep 2024 11:26:45 +0200 Subject: [PATCH 3/3] move to prod test --- .../metadata-revalidate.test.ts | 31 ------------------- .../metadata-revalidate/app/manifest.ts | 0 .../app/revalidate/og/opengraph-image.tsx | 0 .../app-dir/metadata-revalidate/app/robots.ts | 0 .../metadata-revalidate/app/sitemap.ts | 0 .../metadata-revalidate.test.ts | 26 ++++++++++++++++ test/turbopack-build-tests-manifest.json | 18 +++++------ 7 files changed, 35 insertions(+), 40 deletions(-) delete mode 100644 test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts rename test/{e2e => production}/app-dir/metadata-revalidate/app/manifest.ts (100%) rename test/{e2e => production}/app-dir/metadata-revalidate/app/revalidate/og/opengraph-image.tsx (100%) rename test/{e2e => production}/app-dir/metadata-revalidate/app/robots.ts (100%) rename test/{e2e => production}/app-dir/metadata-revalidate/app/sitemap.ts (100%) create mode 100644 test/production/app-dir/metadata-revalidate/metadata-revalidate.test.ts diff --git a/test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts b/test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts deleted file mode 100644 index b046c05077d5d..0000000000000 --- a/test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { nextTestSetup } from 'e2e-utils' - -describe('app-dir - metadata-revalidate', () => { - const { next, isNextStart } = nextTestSetup({ - files: __dirname, - }) - - it('should contain the routes in prerender manifest', async () => { - if (isNextStart) { - const manifestContent = await next.readFile( - '.next/prerender-manifest.json' - ) - const prerenderManifest = JSON.parse(manifestContent) - - expect( - prerenderManifest.routes['/revalidate/og/opengraph-image'] - .initialRevalidateSeconds - ).toBe(5) - expect( - prerenderManifest.routes['/manifest.webmanifest'] - .initialRevalidateSeconds - ).toBe(5) - expect( - prerenderManifest.routes['/robots.txt'].initialRevalidateSeconds - ).toBe(5) - expect( - prerenderManifest.routes['/sitemap.xml'].initialRevalidateSeconds - ).toBe(5) - } - }) -}) diff --git a/test/e2e/app-dir/metadata-revalidate/app/manifest.ts b/test/production/app-dir/metadata-revalidate/app/manifest.ts similarity index 100% rename from test/e2e/app-dir/metadata-revalidate/app/manifest.ts rename to test/production/app-dir/metadata-revalidate/app/manifest.ts diff --git a/test/e2e/app-dir/metadata-revalidate/app/revalidate/og/opengraph-image.tsx b/test/production/app-dir/metadata-revalidate/app/revalidate/og/opengraph-image.tsx similarity index 100% rename from test/e2e/app-dir/metadata-revalidate/app/revalidate/og/opengraph-image.tsx rename to test/production/app-dir/metadata-revalidate/app/revalidate/og/opengraph-image.tsx diff --git a/test/e2e/app-dir/metadata-revalidate/app/robots.ts b/test/production/app-dir/metadata-revalidate/app/robots.ts similarity index 100% rename from test/e2e/app-dir/metadata-revalidate/app/robots.ts rename to test/production/app-dir/metadata-revalidate/app/robots.ts diff --git a/test/e2e/app-dir/metadata-revalidate/app/sitemap.ts b/test/production/app-dir/metadata-revalidate/app/sitemap.ts similarity index 100% rename from test/e2e/app-dir/metadata-revalidate/app/sitemap.ts rename to test/production/app-dir/metadata-revalidate/app/sitemap.ts diff --git a/test/production/app-dir/metadata-revalidate/metadata-revalidate.test.ts b/test/production/app-dir/metadata-revalidate/metadata-revalidate.test.ts new file mode 100644 index 0000000000000..e4a0517d274d1 --- /dev/null +++ b/test/production/app-dir/metadata-revalidate/metadata-revalidate.test.ts @@ -0,0 +1,26 @@ +import { nextTestSetup } from 'e2e-utils' + +describe('app-dir - metadata-revalidate', () => { + const { next } = nextTestSetup({ + files: __dirname, + }) + + it('should contain the routes in prerender manifest', async () => { + const manifestContent = await next.readFile('.next/prerender-manifest.json') + const prerenderManifest = JSON.parse(manifestContent) + + expect( + prerenderManifest.routes['/revalidate/og/opengraph-image'] + .initialRevalidateSeconds + ).toBe(5) + expect( + prerenderManifest.routes['/manifest.webmanifest'].initialRevalidateSeconds + ).toBe(5) + expect( + prerenderManifest.routes['/robots.txt'].initialRevalidateSeconds + ).toBe(5) + expect( + prerenderManifest.routes['/sitemap.xml'].initialRevalidateSeconds + ).toBe(5) + }) +}) diff --git a/test/turbopack-build-tests-manifest.json b/test/turbopack-build-tests-manifest.json index f11f6f2e96b94..40e51638f7ce7 100644 --- a/test/turbopack-build-tests-manifest.json +++ b/test/turbopack-build-tests-manifest.json @@ -2191,15 +2191,6 @@ "flakey": [], "runtimeError": false }, - "test/e2e/app-dir/metadata-revalidate/metadata-revalidate.test.ts": { - "passed": [], - "failed": [ - "app-dir - metadata-revalidate should contain the routes in prerender manifest" - ], - "pending": [], - "flakey": [], - "runtimeError": false - }, "test/e2e/app-dir/metadata-warnings/index.test.ts": { "passed": [ "app dir - metadata missing metadataBase should not warn for viewport properties during manually merging metadata", @@ -16309,6 +16300,15 @@ "flakey": [], "runtimeError": false }, + "test/production/app-dir/metadata-revalidate/metadata-revalidate.test.ts": { + "passed": [], + "failed": [ + "app-dir - metadata-revalidate should contain the routes in prerender manifest" + ], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/production/middleware-typescript/test/index.test.ts": { "passed": ["middleware-typescript should have built and started"], "failed": [],