Skip to content

Commit

Permalink
[Fizz] Support onHeadersReady option for renderTo... functions
Browse files Browse the repository at this point in the history
During a render it can be useful to emit headers to start the process of preloading without waiting for the shell to complete. If provided an `onHeadersReady` callback option Fizz will call this callback with some headers. Currently this is implemented as a set of preload link headers that are generated during the first performWork pass. After this pass preloads are handled as they were preious to this change and emitted as tags.

Since headers are not streamed typically we are choosing an API that provides headers once. Because of this we need to choose a point at which to provide headers once even if we could in theory wait longer to accumulate more. It is possible that a better API is to allow the caller to tell Fizz when it wants whatever headers have accumulated however in practice this would require having some secondary header outside of react that is blocking sending headers and that is considered not a likely ocurrence

In this commit we add the option to pass `onHeadersReady` to static and dynamic render entrypoints. This is not yet wired up to anything so it will never be called. This will be added in a subsequent commit.
  • Loading branch information
gnoff committed Nov 7, 2023
1 parent de95625 commit 57ca924
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 6 deletions.
16 changes: 15 additions & 1 deletion packages/react-dom/src/server/ReactDOMFizzServerBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
* @flow
*/

import type {PostponedState} from 'react-server/src/ReactFizzServer';
import type {
PostponedState,
HeadersDescriptor,
} from 'react-server/src/ReactFizzServer';
import type {ReactNodeList, ReactFormState} from 'shared/ReactTypes';
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
import type {ImportMap} from '../shared/ReactDOMTypes';
Expand Down Expand Up @@ -44,6 +47,7 @@ type Options = {
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
importMap?: ImportMap,
formState?: ReactFormState<any, any> | null,
onHeaders?: (headers: Headers) => void,
};

type ResumeOptions = {
Expand Down Expand Up @@ -97,6 +101,15 @@ function renderToReadableStream(
allReady.catch(() => {});
reject(error);
}

const onHeaders = options ? options.onHeaders : undefined;
let onHeadersImpl;
if (onHeaders) {
onHeadersImpl = (headersDescriptor: HeadersDescriptor) => {
onHeaders(new Headers(headersDescriptor));
};
}

const resumableState = createResumableState(
options ? options.identifierPrefix : undefined,
options ? options.unstable_externalRuntimeSrc : undefined,
Expand All @@ -122,6 +135,7 @@ function renderToReadableStream(
onFatalError,
options ? options.onPostpone : undefined,
options ? options.formState : undefined,
onHeadersImpl,
);
if (options && options.signal) {
const signal = options.signal;
Expand Down
12 changes: 12 additions & 0 deletions packages/react-dom/src/server/ReactDOMFizzServerBun.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* @flow
*/

import type {HeadersDescriptor} from 'react-server/src/ReactFizzServer';
import type {ReactNodeList, ReactFormState} from 'shared/ReactTypes';
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
import type {ImportMap} from '../shared/ReactDOMTypes';
Expand Down Expand Up @@ -41,6 +42,7 @@ type Options = {
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
importMap?: ImportMap,
formState?: ReactFormState<any, any> | null,
onHeaders?: (headers: Headers) => void,
};

// TODO: Move to sub-classing ReadableStream.
Expand Down Expand Up @@ -87,6 +89,15 @@ function renderToReadableStream(
allReady.catch(() => {});
reject(error);
}

const onHeaders = options ? options.onHeaders : undefined;
let onHeadersImpl;
if (onHeaders) {
onHeadersImpl = (headersDescriptor: HeadersDescriptor) => {
onHeaders(new Headers(headersDescriptor));
};
}

const resumableState = createResumableState(
options ? options.identifierPrefix : undefined,
options ? options.unstable_externalRuntimeSrc : undefined,
Expand All @@ -112,6 +123,7 @@ function renderToReadableStream(
onFatalError,
options ? options.onPostpone : undefined,
options ? options.formState : undefined,
onHeadersImpl,
);
if (options && options.signal) {
const signal = options.signal;
Expand Down
17 changes: 16 additions & 1 deletion packages/react-dom/src/server/ReactDOMFizzServerEdge.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
* @flow
*/

import type {PostponedState} from 'react-server/src/ReactFizzServer';
import type {
PostponedState,
HeadersDescriptor,
} from 'react-server/src/ReactFizzServer';
import type {ReactNodeList, ReactFormState} from 'shared/ReactTypes';
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
import type {ImportMap} from '../shared/ReactDOMTypes';
Expand Down Expand Up @@ -44,6 +47,7 @@ type Options = {
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
importMap?: ImportMap,
formState?: ReactFormState<any, any> | null,
onHeaders?: (headers: Headers) => void,
};

type ResumeOptions = {
Expand Down Expand Up @@ -97,6 +101,15 @@ function renderToReadableStream(
allReady.catch(() => {});
reject(error);
}

const onHeaders = options ? options.onHeaders : undefined;
let onHeadersImpl;
if (onHeaders) {
onHeadersImpl = (headersDescriptor: HeadersDescriptor) => {
onHeaders(new Headers(headersDescriptor));
};
}

const resumableState = createResumableState(
options ? options.identifierPrefix : undefined,
options ? options.unstable_externalRuntimeSrc : undefined,
Expand All @@ -122,6 +135,7 @@ function renderToReadableStream(
onFatalError,
options ? options.onPostpone : undefined,
options ? options.formState : undefined,
onHeadersImpl,
);
if (options && options.signal) {
const signal = options.signal;
Expand Down Expand Up @@ -190,6 +204,7 @@ function resume(
onShellReady,
onShellError,
onFatalError,
undefined,
options ? options.onPostpone : undefined,
);
if (options && options.signal) {
Expand Down
8 changes: 7 additions & 1 deletion packages/react-dom/src/server/ReactDOMFizzServerNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
* @flow
*/

import type {Request, PostponedState} from 'react-server/src/ReactFizzServer';
import type {
Request,
PostponedState,
HeadersDescriptor,
} from 'react-server/src/ReactFizzServer';
import type {ReactNodeList, ReactFormState} from 'shared/ReactTypes';
import type {Writable} from 'stream';
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
Expand Down Expand Up @@ -60,6 +64,7 @@ type Options = {
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
importMap?: ImportMap,
formState?: ReactFormState<any, any> | null,
onHeaders?: (headers: HeadersDescriptor) => void,
};

type ResumeOptions = {
Expand Down Expand Up @@ -104,6 +109,7 @@ function createRequestImpl(children: ReactNodeList, options: void | Options) {
undefined,
options ? options.onPostpone : undefined,
options ? options.formState : undefined,
options ? options.onHeaders : undefined,
);
}

Expand Down
16 changes: 15 additions & 1 deletion packages/react-dom/src/server/ReactDOMFizzStaticBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

import type {ReactNodeList} from 'shared/ReactTypes';
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
import type {PostponedState} from 'react-server/src/ReactFizzServer';
import type {
PostponedState,
HeadersDescriptor,
} from 'react-server/src/ReactFizzServer';
import type {ImportMap} from '../shared/ReactDOMTypes';

import ReactVersion from 'shared/ReactVersion';
Expand Down Expand Up @@ -41,6 +44,7 @@ type Options = {
onPostpone?: (reason: string) => void,
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
importMap?: ImportMap,
onHeaders?: (headers: Headers) => void,
};

type StaticResult = {
Expand Down Expand Up @@ -77,6 +81,15 @@ function prerender(
};
resolve(result);
}

const onHeaders = options ? options.onHeaders : undefined;
let onHeadersImpl;
if (onHeaders) {
onHeadersImpl = (headersDescriptor: HeadersDescriptor) => {
onHeaders(new Headers(headersDescriptor));
};
}

const resources = createResumableState(
options ? options.identifierPrefix : undefined,
options ? options.unstable_externalRuntimeSrc : undefined,
Expand All @@ -101,6 +114,7 @@ function prerender(
undefined,
onFatalError,
options ? options.onPostpone : undefined,
onHeadersImpl,
);
if (options && options.signal) {
const signal = options.signal;
Expand Down
15 changes: 14 additions & 1 deletion packages/react-dom/src/server/ReactDOMFizzStaticEdge.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

import type {ReactNodeList} from 'shared/ReactTypes';
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
import type {PostponedState} from 'react-server/src/ReactFizzServer';
import type {
PostponedState,
HeadersDescriptor,
} from 'react-server/src/ReactFizzServer';
import type {ImportMap} from '../shared/ReactDOMTypes';

import ReactVersion from 'shared/ReactVersion';
Expand Down Expand Up @@ -41,6 +44,7 @@ type Options = {
onPostpone?: (reason: string) => void,
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
importMap?: ImportMap,
onHeaders?: (headers: Headers) => void,
};

type StaticResult = {
Expand Down Expand Up @@ -77,6 +81,14 @@ function prerender(
};
resolve(result);
}

const onHeaders = options ? options.onHeaders : undefined;
let onHeadersImpl;
if (onHeaders) {
onHeadersImpl = (headersDescriptor: HeadersDescriptor) => {
onHeaders(new Headers(headersDescriptor));
};
}
const resources = createResumableState(
options ? options.identifierPrefix : undefined,
options ? options.unstable_externalRuntimeSrc : undefined,
Expand All @@ -101,6 +113,7 @@ function prerender(
undefined,
onFatalError,
options ? options.onPostpone : undefined,
onHeadersImpl,
);
if (options && options.signal) {
const signal = options.signal;
Expand Down
7 changes: 6 additions & 1 deletion packages/react-dom/src/server/ReactDOMFizzStaticNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

import type {ReactNodeList} from 'shared/ReactTypes';
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
import type {PostponedState} from 'react-server/src/ReactFizzServer';
import type {
PostponedState,
HeadersDescriptor,
} from 'react-server/src/ReactFizzServer';
import type {ImportMap} from '../shared/ReactDOMTypes';

import {Writable, Readable} from 'stream';
Expand Down Expand Up @@ -42,6 +45,7 @@ type Options = {
onPostpone?: (reason: string) => void,
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
importMap?: ImportMap,
onHeaders?: (headers: HeadersDescriptor) => void,
};

type StaticResult = {
Expand Down Expand Up @@ -110,6 +114,7 @@ function prerenderToNodeStream(
undefined,
onFatalError,
options ? options.onPostpone : undefined,
options ? options.onHeaders : undefined,
);
if (options && options.signal) {
const signal = options.signal;
Expand Down
8 changes: 8 additions & 0 deletions packages/react-server/src/ReactFizzServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ function defaultErrorHandler(error: mixed) {

function noop(): void {}

export type HeadersDescriptor = {
Link: string,
};

export function createRequest(
children: ReactNodeList,
resumableState: ResumableState,
Expand All @@ -366,6 +370,7 @@ export function createRequest(
onFatalError: void | ((error: mixed) => void),
onPostpone: void | ((reason: string) => void),
formState: void | null | ReactFormState<any, any>,
onHeaders: void | ((headers: HeadersDescriptor) => void),
): Request {
prepareHostDispatcher();
const pingedTasks: Array<Task> = [];
Expand Down Expand Up @@ -442,6 +447,7 @@ export function createPrerenderRequest(
onShellError: void | ((error: mixed) => void),
onFatalError: void | ((error: mixed) => void),
onPostpone: void | ((reason: string) => void),
onHeaders: void | ((headers: HeadersDescriptor) => void),
): Request {
const request = createRequest(
children,
Expand All @@ -455,6 +461,8 @@ export function createPrerenderRequest(
onShellError,
onFatalError,
onPostpone,
undefined,
onHeaders,
);
// Start tracking postponed holes during this render.
request.trackedPostpones = {
Expand Down

0 comments on commit 57ca924

Please sign in to comment.