Compare commits
2 Commits
pr33767
...
sync-nextj
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
178c267a4e | ||
|
|
1db62223e0 |
@@ -58,12 +58,6 @@ export function typedArrayToBinaryChunk(
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
|
||||
export function clonePrecomputedChunk(
|
||||
chunk: PrecomputedChunk,
|
||||
): PrecomputedChunk {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ import {
|
||||
writeChunkAndReturn,
|
||||
stringToChunk,
|
||||
stringToPrecomputedChunk,
|
||||
clonePrecomputedChunk,
|
||||
} from 'react-server/src/ReactServerStreamConfig';
|
||||
import {
|
||||
resolveRequest,
|
||||
@@ -4227,15 +4226,13 @@ export function writeCompletedBoundaryInstruction(
|
||||
) {
|
||||
resumableState.instructions |=
|
||||
SentStyleInsertionFunction | SentCompleteBoundaryFunction;
|
||||
writeChunk(
|
||||
destination,
|
||||
clonePrecomputedChunk(completeBoundaryWithStylesScript1FullBoth),
|
||||
);
|
||||
writeChunk(destination, completeBoundaryWithStylesScript1FullBoth);
|
||||
} else if (
|
||||
(resumableState.instructions & SentStyleInsertionFunction) ===
|
||||
NothingSent
|
||||
) {
|
||||
resumableState.instructions |= SentStyleInsertionFunction;
|
||||
|
||||
writeChunk(destination, completeBoundaryWithStylesScript1FullPartial);
|
||||
} else {
|
||||
writeChunk(destination, completeBoundaryWithStylesScript1Partial);
|
||||
|
||||
@@ -731,6 +731,65 @@ describe('ReactDOMFloat', () => {
|
||||
).toEqual(['<script src="src-of-external-runtime" async=""></script>']);
|
||||
});
|
||||
|
||||
// @gate enableFloat
|
||||
it('can send style insertion implementation independent of boundary commpletion instruction implementation', async () => {
|
||||
await act(() => {
|
||||
renderToPipeableStream(
|
||||
<html>
|
||||
<body>
|
||||
<Suspense fallback="loading foo...">
|
||||
<BlockedOn value="foo">foo</BlockedOn>
|
||||
</Suspense>
|
||||
<Suspense fallback="loading bar...">
|
||||
<BlockedOn value="bar">
|
||||
<link rel="stylesheet" href="bar" precedence="bar" />
|
||||
bar
|
||||
</BlockedOn>
|
||||
</Suspense>
|
||||
</body>
|
||||
</html>,
|
||||
).pipe(writable);
|
||||
});
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
{'loading foo...'}
|
||||
{'loading bar...'}
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
|
||||
await act(() => {
|
||||
resolveText('foo');
|
||||
});
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
foo
|
||||
{'loading bar...'}
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
await act(() => {
|
||||
resolveText('bar');
|
||||
});
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="bar" data-precedence="bar" />
|
||||
</head>
|
||||
<body>
|
||||
foo
|
||||
{'loading bar...'}
|
||||
<link rel="preload" href="bar" as="style" />
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
});
|
||||
|
||||
// @gate enableFloat
|
||||
it('can avoid inserting a late stylesheet if it already rendered on the client', async () => {
|
||||
await act(() => {
|
||||
|
||||
@@ -46,9 +46,6 @@ const ReactNoopFlightServer = ReactFlightServer({
|
||||
stringToPrecomputedChunk(content: string): Uint8Array {
|
||||
return textEncoder.encode(content);
|
||||
},
|
||||
clonePrecomputedChunk(chunk: Uint8Array): Uint8Array {
|
||||
return chunk;
|
||||
},
|
||||
isClientReference(reference: Object): boolean {
|
||||
return reference.$$typeof === Symbol.for('react.client.reference');
|
||||
},
|
||||
|
||||
@@ -45,4 +45,31 @@ describe('ReactFlightDOMReplyEdge', () => {
|
||||
|
||||
expect(decoded).toEqual({some: 'object'});
|
||||
});
|
||||
|
||||
it('should abort when parsing an incomplete payload', async () => {
|
||||
const infinitePromise = new Promise(() => {});
|
||||
const controller = new AbortController();
|
||||
const promiseForResult = ReactServerDOMClient.encodeReply(
|
||||
{promise: infinitePromise},
|
||||
{
|
||||
signal: controller.signal,
|
||||
},
|
||||
);
|
||||
controller.abort();
|
||||
const body = await promiseForResult;
|
||||
|
||||
const decoded = await ReactServerDOMServer.decodeReply(
|
||||
body,
|
||||
webpackServerMap,
|
||||
);
|
||||
|
||||
let error = null;
|
||||
try {
|
||||
await decoded.promise;
|
||||
} catch (x) {
|
||||
error = x;
|
||||
}
|
||||
expect(error).not.toBe(null);
|
||||
expect(error.message).toBe('Connection closed.');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -135,6 +135,8 @@ export type Response = {
|
||||
_formData: FormData,
|
||||
_chunks: Map<number, SomeChunk<any>>,
|
||||
_fromJSON: (key: string, value: JSONValue) => any,
|
||||
_closed: boolean,
|
||||
_closedReason: mixed,
|
||||
};
|
||||
|
||||
export function getRoot<T>(response: Response): Thenable<T> {
|
||||
@@ -198,6 +200,14 @@ function createResolvedModelChunk<T>(
|
||||
return new Chunk(RESOLVED_MODEL, value, null, response);
|
||||
}
|
||||
|
||||
function createErroredChunk<T>(
|
||||
response: Response,
|
||||
reason: mixed,
|
||||
): ErroredChunk<T> {
|
||||
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
|
||||
return new Chunk(ERRORED, null, reason, response);
|
||||
}
|
||||
|
||||
function resolveModelChunk<T>(chunk: SomeChunk<T>, value: string): void {
|
||||
if (chunk.status !== PENDING) {
|
||||
// We already resolved. We didn't expect to see this.
|
||||
@@ -297,6 +307,8 @@ function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {
|
||||
// Report that any missing chunks in the model is now going to throw this
|
||||
// error upon read. Also notify any pending promises.
|
||||
export function reportGlobalError(response: Response, error: Error): void {
|
||||
response._closed = true;
|
||||
response._closedReason = error;
|
||||
response._chunks.forEach(chunk => {
|
||||
// If this chunk was already resolved or errored, it won't
|
||||
// trigger an error but if it wasn't then we need to
|
||||
@@ -318,6 +330,10 @@ function getChunk(response: Response, id: number): SomeChunk<any> {
|
||||
if (backingEntry != null) {
|
||||
// We assume that this is a string entry for now.
|
||||
chunk = createResolvedModelChunk(response, (backingEntry: any));
|
||||
} else if (response._closed) {
|
||||
// We have already errored the response and we're not going to get
|
||||
// anything more streaming in so this will immediately error.
|
||||
chunk = createErroredChunk(response, response._closedReason);
|
||||
} else {
|
||||
// We're still waiting on this entry to stream in.
|
||||
chunk = createPendingChunk(response);
|
||||
@@ -519,6 +535,8 @@ export function createResponse(
|
||||
}
|
||||
return value;
|
||||
},
|
||||
_closed: false,
|
||||
_closedReason: null,
|
||||
};
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export function flushBuffered(destination: Destination) {
|
||||
// transform streams. https://github.com/whatwg/streams/issues/960
|
||||
}
|
||||
|
||||
const VIEW_SIZE = 512;
|
||||
const VIEW_SIZE = 2048;
|
||||
let currentView = null;
|
||||
let writtenBytes = 0;
|
||||
|
||||
@@ -40,15 +40,6 @@ export function writeChunk(
|
||||
}
|
||||
|
||||
if (chunk.byteLength > VIEW_SIZE) {
|
||||
if (__DEV__) {
|
||||
if (precomputedChunkSet.has(chunk)) {
|
||||
console.error(
|
||||
'A large precomputed chunk was passed to writeChunk without being copied.' +
|
||||
' Large chunks get enqueued directly and are not copied. This is incompatible with precomputed chunks because you cannot enqueue the same precomputed chunk twice.' +
|
||||
' Use "cloneChunk" to make a copy of this large precomputed chunk before writing it. This is a bug in React.',
|
||||
);
|
||||
}
|
||||
}
|
||||
// this chunk may overflow a single view which implies it was not
|
||||
// one that is cached by the streaming renderer. We will enqueu
|
||||
// it directly and expect it is not re-used
|
||||
@@ -120,15 +111,15 @@ export function stringToChunk(content: string): Chunk {
|
||||
return textEncoder.encode(content);
|
||||
}
|
||||
|
||||
const precomputedChunkSet: Set<Chunk | BinaryChunk> = __DEV__
|
||||
? new Set()
|
||||
: (null: any);
|
||||
|
||||
export function stringToPrecomputedChunk(content: string): PrecomputedChunk {
|
||||
const precomputedChunk = textEncoder.encode(content);
|
||||
|
||||
if (__DEV__) {
|
||||
precomputedChunkSet.add(precomputedChunk);
|
||||
if (precomputedChunk.byteLength > VIEW_SIZE) {
|
||||
console.error(
|
||||
'precomputed chunks must be smaller than the view size configured for this host. This is a bug in React.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return precomputedChunk;
|
||||
@@ -151,14 +142,6 @@ export function typedArrayToBinaryChunk(
|
||||
return content.byteLength > VIEW_SIZE ? buffer.slice() : buffer;
|
||||
}
|
||||
|
||||
export function clonePrecomputedChunk(
|
||||
precomputedChunk: PrecomputedChunk,
|
||||
): PrecomputedChunk {
|
||||
return precomputedChunk.byteLength > VIEW_SIZE
|
||||
? precomputedChunk.slice()
|
||||
: precomputedChunk;
|
||||
}
|
||||
|
||||
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
|
||||
return chunk.byteLength;
|
||||
}
|
||||
|
||||
@@ -70,12 +70,6 @@ export function typedArrayToBinaryChunk(
|
||||
return content;
|
||||
}
|
||||
|
||||
export function clonePrecomputedChunk(
|
||||
chunk: PrecomputedChunk,
|
||||
): PrecomputedChunk {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
|
||||
return Buffer.byteLength(chunk, 'utf8');
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export function flushBuffered(destination: Destination) {
|
||||
// transform streams. https://github.com/whatwg/streams/issues/960
|
||||
}
|
||||
|
||||
const VIEW_SIZE = 512;
|
||||
const VIEW_SIZE = 2048;
|
||||
let currentView = null;
|
||||
let writtenBytes = 0;
|
||||
|
||||
@@ -40,15 +40,6 @@ export function writeChunk(
|
||||
}
|
||||
|
||||
if (chunk.byteLength > VIEW_SIZE) {
|
||||
if (__DEV__) {
|
||||
if (precomputedChunkSet.has(chunk)) {
|
||||
console.error(
|
||||
'A large precomputed chunk was passed to writeChunk without being copied.' +
|
||||
' Large chunks get enqueued directly and are not copied. This is incompatible with precomputed chunks because you cannot enqueue the same precomputed chunk twice.' +
|
||||
' Use "cloneChunk" to make a copy of this large precomputed chunk before writing it. This is a bug in React.',
|
||||
);
|
||||
}
|
||||
}
|
||||
// this chunk may overflow a single view which implies it was not
|
||||
// one that is cached by the streaming renderer. We will enqueu
|
||||
// it directly and expect it is not re-used
|
||||
@@ -120,15 +111,15 @@ export function stringToChunk(content: string): Chunk {
|
||||
return textEncoder.encode(content);
|
||||
}
|
||||
|
||||
const precomputedChunkSet: Set<Chunk | BinaryChunk> = __DEV__
|
||||
? new Set()
|
||||
: (null: any);
|
||||
|
||||
export function stringToPrecomputedChunk(content: string): PrecomputedChunk {
|
||||
const precomputedChunk = textEncoder.encode(content);
|
||||
|
||||
if (__DEV__) {
|
||||
precomputedChunkSet.add(precomputedChunk);
|
||||
if (precomputedChunk.byteLength > VIEW_SIZE) {
|
||||
console.error(
|
||||
'precomputed chunks must be smaller than the view size configured for this host. This is a bug in React.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return precomputedChunk;
|
||||
@@ -151,14 +142,6 @@ export function typedArrayToBinaryChunk(
|
||||
return content.byteLength > VIEW_SIZE ? buffer.slice() : buffer;
|
||||
}
|
||||
|
||||
export function clonePrecomputedChunk(
|
||||
precomputedChunk: PrecomputedChunk,
|
||||
): PrecomputedChunk {
|
||||
return precomputedChunk.byteLength > VIEW_SIZE
|
||||
? precomputedChunk.slice()
|
||||
: precomputedChunk;
|
||||
}
|
||||
|
||||
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
|
||||
return chunk.byteLength;
|
||||
}
|
||||
|
||||
@@ -60,12 +60,6 @@ export function typedArrayToBinaryChunk(
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
|
||||
export function clonePrecomputedChunk(
|
||||
chunk: PrecomputedChunk,
|
||||
): PrecomputedChunk {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
|
||||
@@ -99,15 +99,6 @@ function writeViewChunk(
|
||||
return;
|
||||
}
|
||||
if (chunk.byteLength > VIEW_SIZE) {
|
||||
if (__DEV__) {
|
||||
if (precomputedChunkSet && precomputedChunkSet.has(chunk)) {
|
||||
console.error(
|
||||
'A large precomputed chunk was passed to writeChunk without being copied.' +
|
||||
' Large chunks get enqueued directly and are not copied. This is incompatible with precomputed chunks because you cannot enqueue the same precomputed chunk twice.' +
|
||||
' Use "cloneChunk" to make a copy of this large precomputed chunk before writing it. This is a bug in React.',
|
||||
);
|
||||
}
|
||||
}
|
||||
// this chunk may overflow a single view which implies it was not
|
||||
// one that is cached by the streaming renderer. We will enqueu
|
||||
// it directly and expect it is not re-used
|
||||
@@ -201,14 +192,14 @@ export function stringToChunk(content: string): Chunk {
|
||||
return content;
|
||||
}
|
||||
|
||||
const precomputedChunkSet = __DEV__ ? new Set<PrecomputedChunk>() : null;
|
||||
|
||||
export function stringToPrecomputedChunk(content: string): PrecomputedChunk {
|
||||
const precomputedChunk = textEncoder.encode(content);
|
||||
|
||||
if (__DEV__) {
|
||||
if (precomputedChunkSet) {
|
||||
precomputedChunkSet.add(precomputedChunk);
|
||||
if (precomputedChunk.byteLength > VIEW_SIZE) {
|
||||
console.error(
|
||||
'precomputed chunks must be smaller than the view size configured for this host. This is a bug in React.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,14 +213,6 @@ export function typedArrayToBinaryChunk(
|
||||
return new Uint8Array(content.buffer, content.byteOffset, content.byteLength);
|
||||
}
|
||||
|
||||
export function clonePrecomputedChunk(
|
||||
precomputedChunk: PrecomputedChunk,
|
||||
): PrecomputedChunk {
|
||||
return precomputedChunk.length > VIEW_SIZE
|
||||
? precomputedChunk.slice()
|
||||
: precomputedChunk;
|
||||
}
|
||||
|
||||
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
|
||||
return typeof chunk === 'string'
|
||||
? Buffer.byteLength(chunk, 'utf8')
|
||||
|
||||
@@ -41,7 +41,6 @@ export const closeWithError = $$$config.closeWithError;
|
||||
export const stringToChunk = $$$config.stringToChunk;
|
||||
export const stringToPrecomputedChunk = $$$config.stringToPrecomputedChunk;
|
||||
export const typedArrayToBinaryChunk = $$$config.typedArrayToBinaryChunk;
|
||||
export const clonePrecomputedChunk = $$$config.clonePrecomputedChunk;
|
||||
export const byteLengthOfChunk = $$$config.byteLengthOfChunk;
|
||||
export const byteLengthOfBinaryChunk = $$$config.byteLengthOfBinaryChunk;
|
||||
export const createFastHash = $$$config.createFastHash;
|
||||
|
||||
Reference in New Issue
Block a user