| | |
| | import React, { type JSX } from 'react' |
| | import { isHTTPAccessFallbackError } from '../../client/components/http-access-fallback/http-access-fallback' |
| | import { |
| | getURLFromRedirectError, |
| | getRedirectStatusCodeFromError, |
| | } from '../../client/components/redirect' |
| | import { isRedirectError } from '../../client/components/redirect-error' |
| | import { renderToReadableStream } from 'react-dom/server' |
| | import { streamToString } from '../stream-utils/node-web-streams-helper' |
| | import { RedirectStatusCode } from '../../client/components/redirect-status-code' |
| | import { addPathPrefix } from '../../shared/lib/router/utils/add-path-prefix' |
| | import type { ClientTraceDataEntry } from '../lib/trace/tracer' |
| |
|
| | export function makeGetServerInsertedHTML({ |
| | polyfills, |
| | renderServerInsertedHTML, |
| | serverCapturedErrors, |
| | tracingMetadata, |
| | basePath, |
| | }: { |
| | polyfills: JSX.IntrinsicElements['script'][] |
| | renderServerInsertedHTML: () => React.ReactNode |
| | tracingMetadata: ClientTraceDataEntry[] | undefined |
| | serverCapturedErrors: Array<unknown> |
| | basePath: string |
| | }) { |
| | let flushedErrorMetaTagsUntilIndex = 0 |
| |
|
| | |
| | let polyfillTags = polyfills.map((polyfill) => { |
| | return <script key={polyfill.src} {...polyfill} /> |
| | }) |
| | let traceMetaTags = (tracingMetadata || []).map(({ key, value }, index) => ( |
| | <meta key={`next-trace-data-${index}`} name={key} content={value} /> |
| | )) |
| |
|
| | return async function getServerInsertedHTML() { |
| | |
| | |
| | const errorMetaTags = [] |
| | while (flushedErrorMetaTagsUntilIndex < serverCapturedErrors.length) { |
| | const error = serverCapturedErrors[flushedErrorMetaTagsUntilIndex] |
| | flushedErrorMetaTagsUntilIndex++ |
| |
|
| | if (isHTTPAccessFallbackError(error)) { |
| | errorMetaTags.push( |
| | <meta name="robots" content="noindex" key={error.digest} />, |
| | process.env.NODE_ENV === 'development' ? ( |
| | <meta name="next-error" content="not-found" key="next-error" /> |
| | ) : null |
| | ) |
| | } else if (isRedirectError(error)) { |
| | const redirectUrl = addPathPrefix( |
| | getURLFromRedirectError(error), |
| | basePath |
| | ) |
| | const statusCode = getRedirectStatusCodeFromError(error) |
| | const isPermanent = |
| | statusCode === RedirectStatusCode.PermanentRedirect ? true : false |
| | if (redirectUrl) { |
| | errorMetaTags.push( |
| | <meta |
| | id="__next-page-redirect" |
| | httpEquiv="refresh" |
| | content={`${isPermanent ? 0 : 1};url=${redirectUrl}`} |
| | key={error.digest} |
| | /> |
| | ) |
| | } |
| | } |
| | } |
| |
|
| | const serverInsertedHTML = renderServerInsertedHTML() |
| |
|
| | |
| | if ( |
| | polyfillTags.length === 0 && |
| | traceMetaTags.length === 0 && |
| | errorMetaTags.length === 0 && |
| | Array.isArray(serverInsertedHTML) && |
| | serverInsertedHTML.length === 0 |
| | ) { |
| | return '' |
| | } |
| |
|
| | const stream = await renderToReadableStream( |
| | <> |
| | {polyfillTags} |
| | {serverInsertedHTML} |
| | {traceMetaTags} |
| | {errorMetaTags} |
| | </>, |
| | { |
| | |
| | |
| | progressiveChunkSize: 1024 * 1024, |
| | } |
| | ) |
| |
|
| | |
| | polyfillTags = [] |
| | traceMetaTags = [] |
| |
|
| | |
| | |
| | |
| | return streamToString(stream) |
| | } |
| | } |
| |
|