Fix: only inject clientTraceMetadata into html page once (#66763)
This commit is contained in:
parent
918af1667a
commit
46441387be
4 changed files with 61 additions and 18 deletions
|
@ -33,7 +33,12 @@ export function makeGetServerInsertedHTML({
|
|||
basePath: string
|
||||
}) {
|
||||
let flushedErrorMetaTagsUntilIndex = 0
|
||||
let hasUnflushedPolyfills = polyfills.length !== 0
|
||||
// flag for static content that only needs to be flushed once
|
||||
let hasFlushedInitially = false
|
||||
|
||||
const polyfillTags = polyfills.map((polyfill) => {
|
||||
return <script key={polyfill.src} {...polyfill} />
|
||||
})
|
||||
|
||||
return async function getServerInsertedHTML() {
|
||||
// Loop through all the errors that have been captured but not yet
|
||||
|
@ -71,11 +76,18 @@ export function makeGetServerInsertedHTML({
|
|||
}
|
||||
}
|
||||
|
||||
const traceMetaTags = (tracingMetadata || []).map(
|
||||
({ key, value }, index) => (
|
||||
<meta key={`next-trace-data-${index}`} name={key} content={value} />
|
||||
)
|
||||
)
|
||||
|
||||
const serverInsertedHTML = renderServerInsertedHTML()
|
||||
|
||||
// Skip React rendering if we know the content is empty.
|
||||
if (
|
||||
!hasUnflushedPolyfills &&
|
||||
polyfillTags.length === 0 &&
|
||||
traceMetaTags.length === 0 &&
|
||||
errorMetaTags.length === 0 &&
|
||||
Array.isArray(serverInsertedHTML) &&
|
||||
serverInsertedHTML.length === 0
|
||||
|
@ -87,23 +99,10 @@ export function makeGetServerInsertedHTML({
|
|||
<>
|
||||
{
|
||||
/* Insert the polyfills if they haven't been flushed yet. */
|
||||
hasUnflushedPolyfills &&
|
||||
polyfills.map((polyfill) => {
|
||||
return <script key={polyfill.src} {...polyfill} />
|
||||
})
|
||||
hasFlushedInitially ? null : polyfillTags
|
||||
}
|
||||
{serverInsertedHTML}
|
||||
{tracingMetadata
|
||||
? tracingMetadata.map(({ key, value }) => {
|
||||
return (
|
||||
<meta
|
||||
key={`next-trace-data-${key}:${value}`}
|
||||
name={key}
|
||||
content={value}
|
||||
/>
|
||||
)
|
||||
})
|
||||
: null}
|
||||
{hasFlushedInitially ? null : traceMetaTags}
|
||||
{errorMetaTags}
|
||||
</>,
|
||||
{
|
||||
|
@ -113,7 +112,7 @@ export function makeGetServerInsertedHTML({
|
|||
}
|
||||
)
|
||||
|
||||
hasUnflushedPolyfills = false
|
||||
hasFlushedInitially = true
|
||||
|
||||
// There's no need to wait for the stream to be ready
|
||||
// e.g. calling `await stream.allReady` because `streamToString` will
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
'use client'
|
||||
|
||||
import { useServerInsertedHTML } from 'next/navigation'
|
||||
|
||||
export function Client() {
|
||||
useServerInsertedHTML(() => (
|
||||
<>
|
||||
<meta name="client-inserted-key" content="client-inserted-value" />
|
||||
</>
|
||||
))
|
||||
return null
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import React, { Suspense } from 'react'
|
||||
import { Client } from './client'
|
||||
|
||||
async function Component() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
return (
|
||||
<div>
|
||||
<h1>Component</h1>
|
||||
<Client />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Suspensey() {
|
||||
return (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Component />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
return <Suspensey />
|
||||
}
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
|
@ -37,6 +37,12 @@ describe('clientTraceMetadata', () => {
|
|||
expect(firstLoadSpanIdContent).not.toBe(secondLoadSpanIdContent)
|
||||
})
|
||||
|
||||
it('should only insert the client trace metadata once', async () => {
|
||||
const html = await next.render('/suspense')
|
||||
const matches = html.match(/meta name="my-test-key-1"/g)
|
||||
expect(matches.length).toBe(1)
|
||||
})
|
||||
|
||||
if (isNextDev) {
|
||||
describe('next dev only', () => {
|
||||
it('should inject propagation data for a statically server-side-rendered page', async () => {
|
||||
|
|
Loading…
Reference in a new issue