Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {Children} from 'react';
import {
enableFizzExternalRuntime,
enableSrcObject,
enableFizzBlockingRender,
} from 'shared/ReactFeatureFlags';

import type {
Expand Down Expand Up @@ -4146,16 +4147,21 @@ export function writeCompletedRoot(
// we need to track the paint time of the shell so we know how much to throttle the reveal.
writeShellTimeInstruction(destination, resumableState, renderState);
}
const preamble = renderState.preamble;
if (preamble.htmlChunks || preamble.headChunks) {
// If we rendered the whole document, then we emitted a rel="expect" that needs a
// matching target. Normally we use one of the bootstrap scripts for this but if
// there are none, then we need to emit a tag to complete the shell.
if ((resumableState.instructions & SentCompletedShellId) === NothingSent) {
writeChunk(destination, startChunkForTag('template'));
writeCompletedShellIdAttribute(destination, resumableState);
writeChunk(destination, endOfStartTag);
writeChunk(destination, endChunkForTag('template'));
if (enableFizzBlockingRender) {
const preamble = renderState.preamble;
if (preamble.htmlChunks || preamble.headChunks) {
// If we rendered the whole document, then we emitted a rel="expect" that needs a
// matching target. Normally we use one of the bootstrap scripts for this but if
// there are none, then we need to emit a tag to complete the shell.
if (
(resumableState.instructions & SentCompletedShellId) ===
NothingSent
) {
writeChunk(destination, startChunkForTag('template'));
writeCompletedShellIdAttribute(destination, resumableState);
writeChunk(destination, endOfStartTag);
writeChunk(destination, endChunkForTag('template'));
}
}
}
return writeBootstrap(destination, renderState);
Expand Down Expand Up @@ -5040,11 +5046,13 @@ function writeBlockingRenderInstruction(
resumableState: ResumableState,
renderState: RenderState,
): void {
const idPrefix = resumableState.idPrefix;
const shellId = '\u00AB' + idPrefix + 'R\u00BB';
writeChunk(destination, blockingRenderChunkStart);
writeChunk(destination, stringToChunk(escapeTextForBrowser(shellId)));
writeChunk(destination, blockingRenderChunkEnd);
if (enableFizzBlockingRender) {
const idPrefix = resumableState.idPrefix;
const shellId = '\u00AB' + idPrefix + 'R\u00BB';
writeChunk(destination, blockingRenderChunkStart);
writeChunk(destination, stringToChunk(escapeTextForBrowser(shellId)));
writeChunk(destination, blockingRenderChunkEnd);
}
}

const completedShellIdAttributeStart = stringToPrecomputedChunk(' id="');
Expand Down
23 changes: 20 additions & 3 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3590,7 +3590,9 @@ describe('ReactDOMFizzServer', () => {
(gate(flags => flags.shouldUseFizzExternalRuntime)
? '<script src="react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js" async=""></script>'
: '') +
'<link rel="expect" href="#«R»" blocking="render">',
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render">'
: ''),
);
});

Expand Down Expand Up @@ -4523,7 +4525,15 @@ describe('ReactDOMFizzServer', () => {

// the html should be as-is
expect(document.documentElement.innerHTML).toEqual(
'<head><script src="react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js" async=""></script><link rel="expect" href="#«R»" blocking="render"></head><body><p>hello world!</p><template id="«R»"></template></body>',
'<head><script src="react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js" async=""></script>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render">'
: '') +
'</head><body><p>hello world!</p>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') +
'</body>',
);
});

Expand Down Expand Up @@ -6512,7 +6522,14 @@ describe('ReactDOMFizzServer', () => {
(gate(flags => flags.shouldUseFizzExternalRuntime)
? '<script src="react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js" async=""></script>'
: '') +
'<link rel="expect" href="#«R»" blocking="render"></head><body><script>try { foo() } catch (e) {} ;</script><template id="«R»"></template></body></html>',
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render">'
: '') +
'</head><body><script>try { foo() } catch (e) {} ;</script>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') +
'</body></html>',
);
});

Expand Down
22 changes: 18 additions & 4 deletions packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,15 @@ describe('ReactDOMFizzServerBrowser', () => {
),
);
const result = await readResult(stream);
expect(result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
if (gate(flags => flags.enableFizzBlockingRender)) {
expect(result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
} else {
expect(result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head></head><body>hello world</body></html>"`,
);
}
});

it('should emit bootstrap script src at the end', async () => {
Expand Down Expand Up @@ -529,7 +535,15 @@ describe('ReactDOMFizzServerBrowser', () => {

const result = await readResult(stream);
expect(result).toEqual(
'<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/><title>foo</title></head><body>bar<template id="«R»"></template></body></html>',
'<!DOCTYPE html><html><head>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render"/>'
: '') +
'<title>foo</title></head><body>bar' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') +
'</body></html>',
);
});

Expand Down
12 changes: 9 additions & 3 deletions packages/react-dom/src/__tests__/ReactDOMFizzServerEdge-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,14 @@ describe('ReactDOMFizzServerEdge', () => {
setTimeout(resolve, 1);
});

expect(result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body><main>hello</main><template id="«R»"></template></body></html>"`,
);
if (gate(flags => flags.enableFizzBlockingRender)) {
expect(result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body><main>hello</main><template id="«R»"></template></body></html>"`,
);
} else {
expect(result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head></head><body><main>hello</main></body></html>"`,
);
}
});
});
12 changes: 9 additions & 3 deletions packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,15 @@ describe('ReactDOMFizzServerNode', () => {
pipe(writable);
});
// with Float, we emit empty heads if they are elided when rendering <html>
expect(output.result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
if (gate(flags => flags.enableFizzBlockingRender)) {
expect(output.result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
} else {
expect(output.result).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head></head><body>hello world</body></html>"`,
);
}
});

it('should emit bootstrap script src at the end', async () => {
Expand Down
23 changes: 18 additions & 5 deletions packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,15 @@ describe('ReactDOMFizzStaticBrowser', () => {
),
);
const prelude = await readContent(result.prelude);
expect(prelude).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
if (gate(flags => flags.enableFizzBlockingRender)) {
expect(prelude).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
} else {
expect(prelude).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head></head><body>hello world</body></html>"`,
);
}
});

it('should emit bootstrap script src at the end', async () => {
Expand Down Expand Up @@ -1438,8 +1444,15 @@ describe('ReactDOMFizzStaticBrowser', () => {
expect(await readContent(content)).toBe(
'<!DOCTYPE html><html lang="en"><head>' +
'<link rel="stylesheet" href="my-style" data-precedence="high"/>' +
'<link rel="expect" href="#«R»" blocking="render"/></head>' +
'<body>Hello<template id="«R»"></template></body></html>',
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render"/>'
: '') +
'</head>' +
'<body>Hello' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') +
'</body></html>',
);
});

Expand Down
12 changes: 9 additions & 3 deletions packages/react-dom/src/__tests__/ReactDOMFizzStaticNode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,15 @@ describe('ReactDOMFizzStaticNode', () => {
</html>,
);
const prelude = await readContent(result.prelude);
expect(prelude).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
if (gate(flags => flags.enableFizzBlockingRender)) {
expect(prelude).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
);
} else {
expect(prelude).toMatchInlineSnapshot(
`"<!DOCTYPE html><html><head></head><body>hello world</body></html>"`,
);
}
});

// @gate experimental
Expand Down
10 changes: 8 additions & 2 deletions packages/react-dom/src/__tests__/ReactDOMFloat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,14 @@ describe('ReactDOMFloat', () => {
(gate(flags => flags.shouldUseFizzExternalRuntime)
? '<script src="react-dom/unstable_server-external-runtime" async=""></script>'
: '') +
'<link rel="expect" href="#«R»" blocking="render"/><title>foo</title></head>' +
'<body>bar<template id="«R»"></template>',
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render"/>'
: '') +
'<title>foo</title></head>' +
'<body>bar' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: ''),
'</body></html>',
]);
});
Expand Down
11 changes: 9 additions & 2 deletions packages/react-dom/src/__tests__/ReactDOMLegacyFloat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,15 @@ describe('ReactDOMFloat', () => {
);

expect(result).toEqual(
'<html><head><meta charSet="utf-8"/><link rel="expect" href="#«R»" blocking="render"/>' +
'<title>title</title><script src="foo"></script></head><template id="«R»"></template></html>',
'<html><head><meta charSet="utf-8"/>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render"/>'
: '') +
'<title>title</title><script src="foo"></script></head>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') +
'</html>',
);
});
});
44 changes: 35 additions & 9 deletions packages/react-dom/src/__tests__/ReactRenderDocument-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,20 @@ describe('rendering React components at document', () => {
root = ReactDOMClient.hydrateRoot(testDocument, <Root hello="world" />);
});
expect(testDocument.body.innerHTML).toBe(
'Hello world' + '<template id="«R»"></template>',
'Hello world' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: ''),
);

await act(() => {
root.render(<Root hello="moon" />);
});
expect(testDocument.body.innerHTML).toBe(
'Hello moon' + '<template id="«R»"></template>',
'Hello moon' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: ''),
);

expect(body === testDocument.body).toBe(true);
Expand All @@ -112,7 +118,10 @@ describe('rendering React components at document', () => {
root = ReactDOMClient.hydrateRoot(testDocument, <Root />);
});
expect(testDocument.body.innerHTML).toBe(
'Hello world' + '<template id="«R»"></template>',
'Hello world' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: ''),
);

const originalDocEl = testDocument.documentElement;
Expand All @@ -124,9 +133,15 @@ describe('rendering React components at document', () => {
expect(testDocument.firstChild).toBe(originalDocEl);
expect(testDocument.head).toBe(originalHead);
expect(testDocument.body).toBe(originalBody);
expect(originalBody.innerHTML).toBe('<template id="«R»"></template>');
expect(originalBody.innerHTML).toBe(
gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '',
);
expect(originalHead.innerHTML).toBe(
'<link rel="expect" href="#«R»" blocking="render">',
gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render">'
: '',
);
});

Expand Down Expand Up @@ -166,15 +181,20 @@ describe('rendering React components at document', () => {
});

expect(testDocument.body.innerHTML).toBe(
'Hello world' + '<template id="«R»"></template>',
'Hello world' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: ''),
);

await act(() => {
root.render(<Component2 />);
});

expect(testDocument.body.innerHTML).toBe(
'<template id="«R»"></template>' + 'Goodbye world',
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') + 'Goodbye world',
);
});

Expand Down Expand Up @@ -205,7 +225,10 @@ describe('rendering React components at document', () => {
});

expect(testDocument.body.innerHTML).toBe(
'Hello world' + '<template id="«R»"></template>',
'Hello world' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: ''),
);
});

Expand Down Expand Up @@ -341,7 +364,10 @@ describe('rendering React components at document', () => {
expect(testDocument.body.innerHTML).toBe(
favorSafetyOverHydrationPerf
? 'Hello world'
: 'Goodbye world<template id="«R»"></template>',
: 'Goodbye world' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: ''),
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1921,14 +1921,28 @@ describe('ReactFlightDOM', () => {
expect(content1).toEqual(
'<!DOCTYPE html><html><head><link rel="preload" href="before1" as="style"/>' +
'<link rel="preload" href="after1" as="style"/>' +
'<link rel="expect" href="#«R»" blocking="render"/></head>' +
'<body><p>hello world</p><template id="«R»"></template></body></html>',
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render"/>'
: '') +
'</head>' +
'<body><p>hello world</p>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') +
'</body></html>',
);
expect(content2).toEqual(
'<!DOCTYPE html><html><head><link rel="preload" href="before2" as="style"/>' +
'<link rel="preload" href="after2" as="style"/>' +
'<link rel="expect" href="#«R»" blocking="render"/></head>' +
'<body><p>hello world</p><template id="«R»"></template></body></html>',
(gate(flags => flags.enableFizzBlockingRender)
? '<link rel="expect" href="#«R»" blocking="render"/>'
: '') +
'</head>' +
'<body><p>hello world</p>' +
(gate(flags => flags.enableFizzBlockingRender)
? '<template id="«R»"></template>'
: '') +
'</body></html>',
);
});

Expand Down
Loading
Loading