Skip to content

Commit

Permalink
Fix failed to hydrate error with global CSS (#38626)
Browse files Browse the repository at this point in the history
Temporarily we need to ensure that `<link>` tags are injected to `<head>` in the stream.

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
  • Loading branch information
shuding committed Jul 14, 2022
1 parent 2473280 commit 8a2bb49
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 15 deletions.
6 changes: 3 additions & 3 deletions packages/next/client/components/layout-router.client.tsx
Expand Up @@ -235,7 +235,7 @@ export default function OuterLayoutRouter({
childProp: ChildProp
loading: React.ReactNode | undefined
}) {
const { childNodes, tree, url, stylesheets } = useContext(AppTreeContext)
const { childNodes, tree, url } = useContext(AppTreeContext)

let childNodesForParallelRouter = childNodes.get(parallelRouterKey)
if (!childNodesForParallelRouter) {
Expand All @@ -256,11 +256,11 @@ export default function OuterLayoutRouter({

return (
<>
{stylesheets
{/* {stylesheets
? stylesheets.map((href) => (
<link rel="stylesheet" href={`/_next/${href}`} key={href} />
))
: null}
: null} */}
{preservedSegments.map((preservedSegment) => {
return (
<LoadingBoundary loading={loading} key={preservedSegment}>
Expand Down
1 change: 1 addition & 0 deletions packages/next/server/app-render.tsx
Expand Up @@ -946,6 +946,7 @@ export async function renderToHTML(
dataStream: serverComponentsInlinedTransformStream?.readable,
generateStaticHTML: generateStaticHTML || !hasConcurrentFeatures,
flushEffectHandler,
initialStylesheets,
})
}

Expand Down
30 changes: 18 additions & 12 deletions packages/next/server/node-web-streams-helper.ts
Expand Up @@ -136,25 +136,18 @@ export function createFlushEffectStream(
})
}

export function createDevScriptTransformStream(): TransformStream<
Uint8Array,
Uint8Array
> {
export function createHeadInjectionTransformStream(
inject: string
): TransformStream<Uint8Array, Uint8Array> {
let injected = false
const foucTags = `<style data-next-hide-fouc>body{display:none}</style>
<noscript data-next-hide-fouc>
<style>body{display:block}</style>
</noscript>`
return new TransformStream({
transform(chunk, controller) {
const content = decodeText(chunk)
let index
if (!injected && (index = content.indexOf('</head')) !== -1) {
injected = true
// head content + fouc tags + </head
const injectedContent =
content.slice(0, index) + foucTags + content.slice(index)

content.slice(0, index) + inject + content.slice(index)
controller.enqueue(encodeText(injectedContent))
} else {
controller.enqueue(chunk)
Expand Down Expand Up @@ -183,12 +176,14 @@ export async function continueFromInitialStream(
dataStream,
generateStaticHTML,
flushEffectHandler,
initialStylesheets,
}: {
dev?: boolean
suffix?: string
dataStream?: ReadableStream<Uint8Array>
generateStaticHTML: boolean
flushEffectHandler?: () => string
initialStylesheets?: string[]
}
): Promise<ReadableStream<Uint8Array>> {
const closeTag = '</body></html>'
Expand All @@ -204,7 +199,18 @@ export async function continueFromInitialStream(
suffixUnclosed != null ? createDeferredSuffixStream(suffixUnclosed) : null,
dataStream ? createInlineDataStream(dataStream) : null,
suffixUnclosed != null ? createSuffixStream(closeTag) : null,
dev ? createDevScriptTransformStream() : null,
createHeadInjectionTransformStream(
dev
? `<style data-next-hide-fouc>body{display:none}</style>
<noscript data-next-hide-fouc>
<style>body{display:block}</style>
</noscript>`
: initialStylesheets
? initialStylesheets
.map((href) => `<link rel="stylesheet" href="/_next/${href}">`)
.join('')
: ''
),
].filter(nonNullable)

return transforms.reduce(
Expand Down

0 comments on commit 8a2bb49

Please sign in to comment.