Skip to content

Commit ce558a6

Browse files
committed
[Fizz/Float] Float for stylesheet resources
This change implements Float for a minimal use case of hoisting stylesheet resources to the head and ensuring the flush in the appropriate spot in the stream. Subsequent commits will add support for client stylesheet hoisting and Flight resources. While there is some additional buildout of Float capabilities in general the public APIs have all been removed. The intent with this first implementation is to opt in <link rel="stylesheet"> use the more useful semantics of resources
1 parent 56389e8 commit ce558a6

31 files changed

+2374
-260
lines changed

packages/react-art/src/ReactARTHostConfig.js

+3
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,6 @@ export function preparePortalMount(portalInstance: any): void {
451451
export function detachDeletedInstance(node: Instance): void {
452452
// noop
453453
}
454+
455+
export function prepareToRender() {}
456+
export function cleanupAfterRender() {}

packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js

+69
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,30 @@ describe('ReactDOMFizzServer', () => {
144144
}
145145
}
146146

147+
async function actIntoEmptyDocument(callback) {
148+
await callback();
149+
// Await one turn around the event loop.
150+
// This assumes that we'll flush everything we have so far.
151+
await new Promise(resolve => {
152+
setImmediate(resolve);
153+
});
154+
if (hasErrored) {
155+
throw fatalError;
156+
}
157+
// JSDOM doesn't support stream HTML parser so we need to give it a proper fragment.
158+
// We also want to execute any scripts that are embedded.
159+
// We assume that we have now received a proper fragment of HTML.
160+
const bufferedContent = buffer;
161+
// Test Environment
162+
const jsdom = new JSDOM(bufferedContent, {
163+
runScripts: 'dangerously',
164+
});
165+
window = jsdom.window;
166+
document = jsdom.window.document;
167+
container = document;
168+
buffer = '';
169+
}
170+
147171
function getVisibleChildren(element) {
148172
const children = [];
149173
let node = element.firstChild;
@@ -301,6 +325,7 @@ describe('ReactDOMFizzServer', () => {
301325
);
302326
pipe(writable);
303327
});
328+
304329
expect(getVisibleChildren(container)).toEqual(
305330
<div>
306331
<div>Loading...</div>
@@ -3202,6 +3227,50 @@ describe('ReactDOMFizzServer', () => {
32023227
);
32033228
});
32043229

3230+
it('converts stylesheet links into preinit-as-style resources', async () => {
3231+
function App() {
3232+
return (
3233+
<>
3234+
<link rel="stylesheet" href="foo" />
3235+
<html data-foo="foo">
3236+
<head data-bar="bar">
3237+
<title>a title</title>
3238+
</head>
3239+
<body>a body</body>
3240+
</html>
3241+
</>
3242+
);
3243+
}
3244+
3245+
const chunks = [];
3246+
function listener(chunk) {
3247+
chunks.push(chunk);
3248+
}
3249+
3250+
await actIntoEmptyDocument(async () => {
3251+
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(<App />);
3252+
writable.on('data', listener);
3253+
pipe(writable);
3254+
});
3255+
writable.removeListener('data', listener);
3256+
3257+
expect(
3258+
chunks[0].startsWith(
3259+
'<!DOCTYPE html><html data-foo="foo"><head data-bar="bar">',
3260+
),
3261+
).toBe(true);
3262+
3263+
expect(getVisibleChildren(container)).toEqual(
3264+
<html data-foo="foo">
3265+
<head data-bar="bar">
3266+
<link rel="stylesheet" href="foo" />
3267+
<title>a title</title>
3268+
</head>
3269+
<body>a body</body>
3270+
</html>,
3271+
);
3272+
});
3273+
32053274
describe('error escaping', () => {
32063275
it('escapes error hash, message, and component stack values in directly flushed errors (html escaping)', async () => {
32073276
window.__outlet = {};

0 commit comments

Comments
 (0)