Skip to content

Commit

Permalink
Respect reexports from metadata API routes (#70508) (#70647)
Browse files Browse the repository at this point in the history
backport #70508

Co-authored-by: JJ Kasper <[email protected]>
  • Loading branch information
huozhi and ijjk authored Oct 1, 2024
1 parent e1da07e commit 73f6b7d
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ function errorOnBadHandler(resourcePath: string) {
`
}

/* re-export the userland route configs */
async function createReExportsCode(
resourcePath: string,
loaderContext: webpack.LoaderContext<any>
) {
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',
Expand Down Expand Up @@ -83,7 +104,10 @@ export const dynamic = 'force-static'
return code
}

function getDynamicTextRouteCode(resourcePath: string) {
async function getDynamicTextRouteCode(
resourcePath: string,
loaderContext: webpack.LoaderContext<any>
) {
return `\
/* dynamic asset route */
import { NextResponse } from 'next/server'
Expand All @@ -94,6 +118,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()
Expand All @@ -110,7 +135,10 @@ export async function GET() {
}

// <metadata-image>/[id]/route.js
function getDynamicImageRouteCode(resourcePath: string) {
async function getDynamicImageRouteCode(
resourcePath: string,
loaderContext: webpack.LoaderContext<any>
) {
return `\
/* dynamic image route */
import { NextResponse } from 'next/server'
Expand All @@ -122,6 +150,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 || {}
Expand Down Expand Up @@ -160,10 +189,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')
if (
Expand Down Expand Up @@ -197,15 +222,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__, ...params } = ctx.params || {}
Expand Down Expand Up @@ -266,11 +283,11 @@ const nextMetadataRouterLoader: webpack.LoaderDefinitionFunction<MetadataRouteLo
let code = ''
if (isDynamic === '1') {
if (fileBaseName === 'robots' || fileBaseName === 'manifest') {
code = getDynamicTextRouteCode(filePath)
code = await getDynamicTextRouteCode(filePath, this)
} else if (fileBaseName === 'sitemap') {
code = await getDynamicSiteMapRouteCode(filePath, page, this)
} else {
code = getDynamicImageRouteCode(filePath)
code = await getDynamicImageRouteCode(filePath, this)
}
} else {
code = await getStaticAssetRouteCode(filePath, fileBaseName)
Expand Down
22 changes: 22 additions & 0 deletions test/production/app-dir/metadata-revalidate/app/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { MetadataRoute } from 'next'

export default function manifest(): MetadataRoute.Manifest {
return {
name: 'Next.js App',
short_name: 'Next.js App',
description: 'Next.js App',
start_url: '/',
display: 'standalone',
background_color: '#fff',
theme_color: '#fff',
icons: [
{
src: '/favicon.ico',
sizes: 'any',
type: 'image/x-icon',
},
],
}
}

export const revalidate = 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ImageResponse } from 'next/og'

/* without generateImageMetadata */
export default function og() {
return new ImageResponse(
(
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 128,
background: 'lavender',
}}
>
Open Graph
</div>
)
)
}

export const revalidate = 5
14 changes: 14 additions & 0 deletions test/production/app-dir/metadata-revalidate/app/robots.ts
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions test/production/app-dir/metadata-revalidate/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default function sitemap() {
return [
{
url: 'https://acme.com',
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
},
]
}

export const revalidate = 5
Original file line number Diff line number Diff line change
@@ -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)
})
})
9 changes: 9 additions & 0 deletions test/turbopack-build-tests-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -15075,6 +15075,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": [],
"failed": ["middleware-typescript should have built and started"],
Expand Down

0 comments on commit 73f6b7d

Please sign in to comment.