Skip to content

Commit 81919ac

Browse files
committed
use jsx to insert script
1 parent dba5679 commit 81919ac

File tree

6 files changed

+49
-29
lines changed

6 files changed

+49
-29
lines changed

packages/next/src/client/components/metadata/async-metadata.tsx

+31-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { Suspense, use } from 'react'
44
import type { StreamingMetadataResolvedState } from './types'
55

6-
export const AsyncMetadata =
6+
const IsomorphicAsyncMetadata =
77
typeof window === 'undefined'
88
? (
99
require('./server-inserted-metadata') as typeof import('./server-inserted-metadata')
@@ -12,6 +12,36 @@ export const AsyncMetadata =
1212
require('./browser-resolved-metadata') as typeof import('./browser-resolved-metadata')
1313
).BrowserResolvedMetadata
1414

15+
export function AsyncMetadata({
16+
promise,
17+
nonce,
18+
}: {
19+
promise: Promise<StreamingMetadataResolvedState>
20+
nonce?: string
21+
}) {
22+
return (
23+
<>
24+
<IsomorphicAsyncMetadata promise={promise} />
25+
{/**
26+
* For chromium based browsers (Chrome, Edge, etc.) and Safari, icons need to stay under <head>
27+
* to be picked up by the browser. Firefox doesn't have this requirement.
28+
*
29+
* Firefox won't work if we insert those icons into head, it will still pick up default favicon.ico.
30+
* Because of this limitation, we just don't insert for firefox and leave the default behavior for it.
31+
*
32+
*/}
33+
<script
34+
defer
35+
nonce={nonce}
36+
dangerouslySetInnerHTML={{
37+
__html: `!/firefox/i.test(navigator.userAgent) && \
38+
document.querySelectorAll('body link[rel="icon"], body link[rel="apple-touch-icon"]').forEach(el => document.head.appendChild(el.cloneNode()))`,
39+
}}
40+
/>
41+
</>
42+
)
43+
}
44+
1545
function MetadataOutlet({
1646
promise,
1747
}: {

packages/next/src/lib/metadata/metadata.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export function createMetadataComponents({
7474
ViewportBoundary: (props: { children: React.ReactNode }) => React.ReactNode
7575
serveStreamingMetadata: boolean
7676
}): {
77-
MetadataTree: React.ComponentType
77+
MetadataTree: React.ComponentType<{ nonce?: string }>
7878
ViewportTree: React.ComponentType
7979
getMetadataReady: () => Promise<void>
8080
getViewportReady: () => Promise<void>
@@ -94,10 +94,10 @@ export function createMetadataComponents({
9494
)
9595
}
9696

97-
function MetadataTree() {
97+
function MetadataTree(props: { nonce?: string }) {
9898
return (
9999
<MetadataBoundary>
100-
<Metadata />
100+
<Metadata {...props} />
101101
</MetadataBoundary>
102102
)
103103
}
@@ -201,12 +201,12 @@ export function createMetadataComponents({
201201
}
202202
}
203203
}
204-
async function Metadata() {
204+
async function Metadata({ nonce }: { nonce?: string }) {
205205
const promise = resolveFinalMetadata()
206206
if (serveStreamingMetadata) {
207207
return (
208208
<Suspense fallback={null}>
209-
<AsyncMetadata promise={promise} />
209+
<AsyncMetadata promise={promise} nonce={nonce} />
210210
</Suspense>
211211
)
212212
}

packages/next/src/server/app-render/app-render.tsx

+7-6
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ function createNotFoundLoaderTree(loaderTree: LoaderTree): LoaderTree {
317317
}
318318

319319
function createDivergedMetadataComponents(
320-
Metadata: React.ComponentType<{}>,
320+
Metadata: React.ComponentType,
321321
serveStreamingMetadata: boolean
322322
): {
323323
StaticMetadata: React.ComponentType<{}>
@@ -326,8 +326,9 @@ function createDivergedMetadataComponents(
326326
function EmptyMetadata() {
327327
return null
328328
}
329-
const StreamingMetadata: React.ComponentType<{}> | null =
330-
serveStreamingMetadata ? Metadata : null
329+
const StreamingMetadata: React.ComponentType | null = serveStreamingMetadata
330+
? Metadata
331+
: null
331332

332333
const StaticMetadata: React.ComponentType<{}> = serveStreamingMetadata
333334
? EmptyMetadata
@@ -506,7 +507,7 @@ async function generateDynamicRSCPayload(
506507
createDivergedMetadataComponents(() => {
507508
return (
508509
// Adding requestId as react key to make metadata remount for each render
509-
<MetadataTree key={requestId} />
510+
<MetadataTree key={requestId} nonce={ctx.nonce} />
510511
)
511512
}, serveStreamingMetadata)
512513

@@ -826,7 +827,7 @@ async function getRSCPayload(
826827
createDivergedMetadataComponents(() => {
827828
return (
828829
// Not add requestId as react key to ensure segment prefetch could result consistently if nothing changed
829-
<MetadataTree />
830+
<MetadataTree nonce={ctx.nonce} />
830831
)
831832
}, serveStreamingMetadata)
832833

@@ -954,7 +955,7 @@ async function getErrorRSCPayload(
954955
() => (
955956
<React.Fragment key={flightDataPathHeadKey}>
956957
{/* Adding requestId as react key to make metadata remount for each render */}
957-
<MetadataTree key={requestId} />
958+
<MetadataTree key={requestId} nonce={ctx.nonce} />
958959
</React.Fragment>
959960
),
960961
serveStreamingMetadata

packages/next/src/server/app-render/create-component-tree.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function createComponentTree(props: {
4040
missingSlots?: Set<string>
4141
preloadCallbacks: PreloadCallbacks
4242
authInterrupts: boolean
43-
StreamingMetadata: React.ComponentType<{}> | null
43+
StreamingMetadata: React.ComponentType<{ nonce?: string }> | null
4444
StreamingMetadataOutlet: React.ComponentType
4545
}): Promise<CacheNodeSeedData> {
4646
return getTracer().trace(
@@ -92,7 +92,7 @@ async function createComponentTreeInternal({
9292
missingSlots?: Set<string>
9393
preloadCallbacks: PreloadCallbacks
9494
authInterrupts: boolean
95-
StreamingMetadata: React.ComponentType<{}> | null
95+
StreamingMetadata: React.ComponentType<{ nonce?: string }> | null
9696
StreamingMetadataOutlet: React.ComponentType | null
9797
}): Promise<CacheNodeSeedData> {
9898
const {
@@ -400,7 +400,9 @@ async function createComponentTreeInternal({
400400
const isNotDefaultSegment = actualSegment !== DEFAULT_SEGMENT_KEY
401401

402402
const metadata =
403-
isNotDefaultSegment && StreamingMetadata ? <StreamingMetadata /> : undefined
403+
isNotDefaultSegment && StreamingMetadata ? (
404+
<StreamingMetadata nonce={ctx.nonce} />
405+
) : undefined
404406

405407
// Use the same condition to render metadataOutlet as metadata
406408
const metadataOutlet =

packages/next/src/server/stream-utils/node-web-streams-helper.ts

+1-14
Original file line numberDiff line numberDiff line change
@@ -378,19 +378,6 @@ function createMergedTransformStream(
378378

379379
const CLOSE_TAG = '</body></html>'
380380

381-
/**
382-
* For chromium based browsers (Chrome, Edge, etc.) and Safari, icons need to stay under <head>
383-
* to be picked up by the browser. Firefox doesn't have this requirement.
384-
*
385-
* Firefox won't work if we insert those icons into head, it will still pick up default favicon.ico.
386-
* Because of this limitation, we just don't insert for firefox and leave the default behavior for it.
387-
*
388-
*/
389-
const INSERT_ICON_SCRIPT = `<script data-icon-insert defer="">\
390-
!/firefox/i.test(navigator.userAgent) && \
391-
document.querySelectorAll('body link[rel="icon"], body link[rel="apple-touch-icon"]').forEach(el => document.head.appendChild(el.cloneNode()))\
392-
</script>`
393-
394381
/**
395382
* This transform stream moves the suffix to the end of the stream, so results
396383
* like `</body></html><script>...</script>` will be transformed to
@@ -428,7 +415,6 @@ function createMoveSuffixStream(): TransformStream<Uint8Array, Uint8Array> {
428415
)
429416
controller.enqueue(after)
430417
}
431-
controller.enqueue(encoder.encode(INSERT_ICON_SCRIPT))
432418
} else {
433419
controller.enqueue(chunk)
434420
}
@@ -539,6 +525,7 @@ export type ContinueStreamOptions = {
539525
getServerInsertedHTML: () => Promise<string>
540526
getServerInsertedMetadata: () => Promise<string>
541527
validateRootLayout?: boolean
528+
nonce?: string
542529
/**
543530
* Suffix to inject after the buffered data, but before the close tags.
544531
*/

0 commit comments

Comments
 (0)