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

[metadata] do not rethrow postpone when streaming metadata is not enabled #75887

Merged
merged 7 commits into from
Feb 11, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/next/src/lib/metadata/metadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,14 @@ export function createMetadataComponents({
} catch (notFoundMetadataErr) {
// In PPR rendering we still need to throw the postpone error.
// If metadata is postponed, React needs to be aware of the location of error.
if (isPostpone(notFoundMetadataErr)) {
if (serveStreamingMetadata && isPostpone(notFoundMetadataErr)) {
throw notFoundMetadataErr
}
}
}
// In PPR rendering we still need to throw the postpone error.
// If metadata is postponed, React needs to be aware of the location of error.
if (isPostpone(metadataErr)) {
if (serveStreamingMetadata && isPostpone(metadataErr)) {
throw metadataErr
}
// We don't actually want to error in this component. We will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,46 @@ import { nextTestSetup } from 'e2e-utils'

const isPPREnabled = process.env.__NEXT_EXPERIMENTAL_PPR === 'true'

describe('app-dir - metadata-static-generation', () => {
const { next, isNextStart } = nextTestSetup({
files: __dirname,
})
// PPR tests are covered in test/e2e/app-dir/ppr-metadata-blocking
;(isPPREnabled ? describe.skip : describe)(
'app-dir - metadata-static-generation',
() => {
const { next, isNextStart } = nextTestSetup({
files: __dirname,
})

if (isNextStart) {
// Precondition for the following tests in build mode.
// This test is only useful for non-PPR mode as in PPR mode those routes
// are all listed in the prerender manifest.
it('should generate all pages static', async () => {
const prerenderManifest = JSON.parse(
await next.readFile('.next/prerender-manifest.json')
)
const staticRoutes = prerenderManifest.routes
expect(Object.keys(staticRoutes).sort()).toEqual([
'/',
'/suspenseful/static',
])
})
}

if (isNextStart && !isPPREnabled) {
// Precondition for the following tests in build mode.
// This test is only useful for non-PPR mode as in PPR mode those routes
// are all listed in the prerender manifest.
it('should generate all pages static', async () => {
const prerenderManifest = JSON.parse(
await next.readFile('.next/prerender-manifest.json')
it('should contain async generated metadata in head for simple static page', async () => {
const $ = await next.render$('/')
expect($('head title').text()).toBe('index page')
expect($('head meta[name="description"]').attr('content')).toBe(
'index page description'
)
const staticRoutes = prerenderManifest.routes
expect(Object.keys(staticRoutes).sort()).toEqual([
'/',
'/suspenseful/static',
])
})
}

it('should contain async generated metadata in head for simple static page', async () => {
const $ = await next.render$('/')
expect($('head title').text()).toBe('index page')
expect($('head meta[name="description"]').attr('content')).toBe(
'index page description'
)
})

it('should contain async generated metadata in head static page with suspenseful content', async () => {
const $ = await next.render$('/suspenseful/static')
expect($('head title').text()).toBe('suspenseful page - static')
})
it('should contain async generated metadata in head static page with suspenseful content', async () => {
const $ = await next.render$('/suspenseful/static')
expect($('head title').text()).toBe('suspenseful page - static')
})

it('should contain async generated metadata in head for dynamic page', async () => {
const $ = await next.render$('/suspenseful/dynamic')
expect($('head title').text()).toBe('suspenseful page - dynamic')
})
})
it('should contain async generated metadata in head for dynamic page', async () => {
const $ = await next.render$('/suspenseful/dynamic')
expect($('head title').text()).toBe('suspenseful page - dynamic')
})
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { nextTestSetup } from 'e2e-utils'

function countSubstring(str: string, substr: string): number {
return str.split(substr).length - 1
}

describe('ppr-metadata-blocking-ppr-fallback', () => {
const { next, skipped } = nextTestSetup({
files: __dirname,
skipDeployment: true,
env: {
__NEXT_EXPERIMENTAL_STATIC_SHELL_DEBUGGING: '1',
},
})

if (skipped) return

it('should not include metadata in partial shell when page is fully dynamic', async () => {
const $ = await next.render$('/fully-dynamic?__nextppronly=fallback')
expect(countSubstring($.html(), '<title>')).toBe(0)
})

it('should include viewport metadata in partial shell when metadata is dynamic under suspense', async () => {
const $ = await next.render$(
'/dynamic-metadata/partial?__nextppronly=fallback'
)
expect(countSubstring($.html(), '<title>')).toBe(0)
expect(countSubstring($.html(), '<meta name="viewport"')).toBe(1)
})

it('should include viewport metadata in partial shell when page is partially dynamic', async () => {
const $ = await next.render$('/dynamic-page/partial?__nextppronly=fallback')
expect($('head title').text()).toBe('dynamic-page - partial')
expect(countSubstring($.html(), '<title>')).toBe(1)
expect(countSubstring($.html(), '<meta name="viewport"')).toBe(1)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function countSubstring(str: string, substr: string): number {
}

describe('ppr-metadata-blocking', () => {
const { next, isNextStart } = nextTestSetup({
const { next, isNextDev, isNextStart } = nextTestSetup({
files: __dirname,
})

Expand Down Expand Up @@ -55,8 +55,8 @@ describe('ppr-metadata-blocking', () => {

it('should generate metadata in head when page content is static', async () => {
const $ = await next.render$('/dynamic-metadata')
expect($('head title').text()).toBe('dynamic metadata')
expect(countSubstring($.html(), '<title>')).toBe(1)
expect($('head title').text()).toBe('dynamic metadata')

const browser = await next.browser('/dynamic-metadata')
expect(await browser.waitForElementByCss('head title').text()).toBe(
Expand All @@ -69,8 +69,14 @@ describe('ppr-metadata-blocking', () => {
describe('partial shell', () => {
it('should insert metadata into head with dynamic metadata and wrapped under layout Suspense boundary', async () => {
const $ = await next.render$('/dynamic-metadata/partial')
expect($('head title').text()).toBe('dynamic-metadata - partial')
expect(countSubstring($.html(), '<title>')).toBe(1)
// Dev: dynamic rendering
if (isNextDev) {
expect(countSubstring($.html(), '<title>')).toBe(1)
expect($('head title').text()).toBe('dynamic-metadata - partial')
} else {
// Production: PPR
expect(countSubstring($.html(), '<title>')).toBe(0)
}

const browser = await next.browser('/dynamic-metadata/partial')
expect(await browser.waitForElementByCss('head title').text()).toBe(
Expand Down Expand Up @@ -133,6 +139,9 @@ describe('ppr-metadata-blocking', () => {

// Dynamic render should not have postponed header
const headers = res1.headers
// In blocking mode of metadata, it's still postponed if metadata or page is dynamic.
// It won't behave differently when the bot is visiting.

expect(headers.get('x-nextjs-postponed')).toBe(null)

const $1 = cheerio.load(await res1.text())
Expand All @@ -142,7 +151,7 @@ describe('ppr-metadata-blocking', () => {
const attribute2 = parseInt($2('[data-date]').attr('data-date'))

// Two requests are dynamic and should not have the same data-date attribute
expect(attribute2).toBeGreaterThan(attribute1)
expect(attribute2).not.toEqual(attribute1)
expect(attribute1).toBeTruthy()
})
})
Expand Down
Loading