Skip to content

Commit

Permalink
fix flight handling during client navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
shuding committed Jul 12, 2022
1 parent d4c623f commit e0b6b84
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 14 deletions.
18 changes: 11 additions & 7 deletions packages/next/client/app-index.tsx
Expand Up @@ -172,25 +172,29 @@ function useInitialServerResponse(cacheKey: string) {
}

const loadCssFromStreamData = (data: string) => {
const seg = data.split(':')
if (seg[0] === 'CSS') {
loadCss(seg.slice(1).join(':'))
if (data.startsWith('CSS:')) {
loadCss(data.slice(4))
}
}

// TODO-APP: Refine the buffering code here to make it more correct.
let buffer = ''
const loadCssFromFlight = new TransformStream({
transform(chunk, controller) {
const data = new TextDecoder().decode(chunk)
buffer += data
let index
while ((index = buffer.indexOf('\n')) !== -1) {
const line = buffer.slice(0, index)
const line = buffer.slice(0, index + 1)
buffer = buffer.slice(index + 1)
loadCssFromStreamData(line)
if (line.startsWith('CSS:')) {
loadCssFromStreamData(line)
} else {
controller.enqueue(new TextEncoder().encode(line))
}
}
if (!data.startsWith('CSS:')) {
controller.enqueue(chunk)
if (buffer && !buffer.startsWith('CSS:')) {
controller.enqueue(new TextEncoder().encode(buffer))
}
},
flush() {
Expand Down
64 changes: 57 additions & 7 deletions packages/next/client/components/app-router.client.tsx
@@ -1,5 +1,5 @@
import React, { useEffect } from 'react'
import { createFromFetch } from 'next/dist/compiled/react-server-dom-webpack'
import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack'
import {
AppRouterContext,
AppTreeContext,
Expand All @@ -16,24 +16,74 @@ import {
// LayoutSegmentsContext,
} from './hooks-client-context'

function fetchFlight(
url: URL,
flightRouterStateData: string
): Promise<Response> {
async function loadCss(cssChunkInfoJson: string) {
const data = JSON.parse(cssChunkInfoJson)
await Promise.all(
data.chunks.map((chunkId: string) => {
// load css related chunks
return (self as any).__next_chunk_load__(chunkId)
})
)
// In development mode, import css in dev when it's wrapped by style loader.
// In production mode, css are standalone chunk that doesn't need to be imported.
if (data.id) {
;(self as any).__next_require__(data.id)
}
}

const loadCssFromStreamData = (data: string) => {
if (data.startsWith('CSS:')) {
loadCss(data.slice(4))
}
}

function fetchFlight(url: URL, flightRouterStateData: string): ReadableStream {
const flightUrl = new URL(url)
const searchParams = flightUrl.searchParams
searchParams.append('__flight__', '1')
searchParams.append('__flight_router_state_tree__', flightRouterStateData)

return fetch(flightUrl.toString())
const { readable, writable } = new TransformStream()

// TODO-APP: Refine the buffering code here to make it more correct.
let buffer = ''
const loadCssFromFlight = new TransformStream({
transform(chunk, controller) {
const data = new TextDecoder().decode(chunk)
buffer += data
let index
while ((index = buffer.indexOf('\n')) !== -1) {
const line = buffer.slice(0, index + 1)
buffer = buffer.slice(index + 1)

if (line.startsWith('CSS:')) {
loadCssFromStreamData(line)
} else {
controller.enqueue(new TextEncoder().encode(line))
}
}
if (buffer && !buffer.startsWith('CSS:')) {
controller.enqueue(new TextEncoder().encode(buffer))
}
},
flush() {
loadCssFromStreamData(buffer)
},
})

fetch(flightUrl.toString()).then((res) => {
res.body?.pipeThrough(loadCssFromFlight).pipeTo(writable)
})

return readable
}

export function fetchServerResponse(
url: URL,
flightRouterState: FlightRouterState
): { readRoot: () => FlightData } {
const flightRouterStateData = JSON.stringify(flightRouterState)
return createFromFetch(fetchFlight(url, flightRouterStateData))
return createFromReadableStream(fetchFlight(url, flightRouterStateData))
}

function ErrorOverlay({
Expand Down

0 comments on commit e0b6b84

Please sign in to comment.