mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
[Fizz] Split ResponseState/Resources into RenderState/ResumableState (#27268)
This exposes a `resume()` API to go with the `prerender()` (only in experimental). It doesn't work yet since we don't yet emit the postponed state so not yet tested. The main thing this does is rename ResponseState->RenderState and Resources->ResumableState. We separated out resources into a separate concept preemptively since it seemed like separate enough but probably doesn't warrant being a separate concept. The result is that we have a per RenderState in the Config which is really just temporary state and things that must be flushed completely in the prerender. Most things should be ResumableState. Most options are specified in the `prerender()` and transferred into the `resume()` but certain options that are unique per request can't be. Notably `nonce` is special. This means that bootstrap scripts and external runtime can't use `nonce` in this mode. They need to have a CSP configured to deal with external scripts, but not inline. We need to be able to restore state of things that we've already emitted in the prerender. We could have separate snapshot/restore methods that does this work when it happens but that means we have to explicitly do that work. This design is trying to keep to the principle that we just work with resumable data structures instead so that we're designing for it with every feature. It also makes restoring faster since it's just straight into the data structure. This is not yet a serializable format. That can be done in a follow up. We also need to vet that each step makes sense. Notably stylesToHoist is a bit unclear how it'll work.
This commit is contained in:
parent
86198b9231
commit
31034b6de7
|
|
@ -492,7 +492,6 @@ module.exports = {
|
|||
ReadableStreamController: 'readonly',
|
||||
RequestInfo: 'readonly',
|
||||
RequestOptions: 'readonly',
|
||||
ResponseState: 'readonly',
|
||||
StoreAsGlobal: 'readonly',
|
||||
symbol: 'readonly',
|
||||
SyntheticEvent: 'readonly',
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -7,16 +7,10 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {
|
||||
Resources,
|
||||
BootstrapScriptDescriptor,
|
||||
ExternalRuntimeScript,
|
||||
StreamingFormat,
|
||||
InstructionState,
|
||||
} from './ReactFizzConfigDOM';
|
||||
import type {ResumableState, BoundaryResources} from './ReactFizzConfigDOM';
|
||||
|
||||
import {
|
||||
createResponseState as createResponseStateImpl,
|
||||
createRenderState as createRenderStateImpl,
|
||||
pushTextInstance as pushTextInstanceImpl,
|
||||
pushSegmentFinale as pushSegmentFinaleImpl,
|
||||
writeStartCompletedSuspenseBoundary as writeStartCompletedSuspenseBoundaryImpl,
|
||||
|
|
@ -37,65 +31,44 @@ import {NotPending} from '../shared/ReactDOMFormActions';
|
|||
|
||||
export const isPrimaryRenderer = false;
|
||||
|
||||
export type ResponseState = {
|
||||
export type RenderState = {
|
||||
// Keep this in sync with ReactFizzConfigDOM
|
||||
bootstrapChunks: Array<Chunk | PrecomputedChunk>,
|
||||
placeholderPrefix: PrecomputedChunk,
|
||||
segmentPrefix: PrecomputedChunk,
|
||||
boundaryPrefix: string,
|
||||
idPrefix: string,
|
||||
nextSuspenseID: number,
|
||||
streamingFormat: StreamingFormat,
|
||||
startInlineScript: PrecomputedChunk,
|
||||
instructions: InstructionState,
|
||||
externalRuntimeScript: null | ExternalRuntimeScript,
|
||||
htmlChunks: null | Array<Chunk | PrecomputedChunk>,
|
||||
headChunks: null | Array<Chunk | PrecomputedChunk>,
|
||||
hasBody: boolean,
|
||||
charsetChunks: Array<Chunk | PrecomputedChunk>,
|
||||
preconnectChunks: Array<Chunk | PrecomputedChunk>,
|
||||
preloadChunks: Array<Chunk | PrecomputedChunk>,
|
||||
hoistableChunks: Array<Chunk | PrecomputedChunk>,
|
||||
boundaryResources: ?BoundaryResources,
|
||||
stylesToHoist: boolean,
|
||||
// This is an extra field for the legacy renderer
|
||||
generateStaticMarkup: boolean,
|
||||
};
|
||||
|
||||
export function createResponseState(
|
||||
resources: Resources,
|
||||
export function createRenderState(
|
||||
resumableState: ResumableState,
|
||||
nonce: string | void,
|
||||
generateStaticMarkup: boolean,
|
||||
identifierPrefix: string | void,
|
||||
externalRuntimeConfig: string | BootstrapScriptDescriptor | void,
|
||||
): ResponseState {
|
||||
const responseState = createResponseStateImpl(
|
||||
resources,
|
||||
identifierPrefix,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
externalRuntimeConfig,
|
||||
);
|
||||
): RenderState {
|
||||
const renderState = createRenderStateImpl(resumableState, nonce);
|
||||
return {
|
||||
// Keep this in sync with ReactFizzConfigDOM
|
||||
bootstrapChunks: responseState.bootstrapChunks,
|
||||
placeholderPrefix: responseState.placeholderPrefix,
|
||||
segmentPrefix: responseState.segmentPrefix,
|
||||
boundaryPrefix: responseState.boundaryPrefix,
|
||||
idPrefix: responseState.idPrefix,
|
||||
nextSuspenseID: responseState.nextSuspenseID,
|
||||
streamingFormat: responseState.streamingFormat,
|
||||
startInlineScript: responseState.startInlineScript,
|
||||
instructions: responseState.instructions,
|
||||
externalRuntimeScript: responseState.externalRuntimeScript,
|
||||
htmlChunks: responseState.htmlChunks,
|
||||
headChunks: responseState.headChunks,
|
||||
hasBody: responseState.hasBody,
|
||||
charsetChunks: responseState.charsetChunks,
|
||||
preconnectChunks: responseState.preconnectChunks,
|
||||
preloadChunks: responseState.preloadChunks,
|
||||
hoistableChunks: responseState.hoistableChunks,
|
||||
stylesToHoist: responseState.stylesToHoist,
|
||||
placeholderPrefix: renderState.placeholderPrefix,
|
||||
segmentPrefix: renderState.segmentPrefix,
|
||||
boundaryPrefix: renderState.boundaryPrefix,
|
||||
startInlineScript: renderState.startInlineScript,
|
||||
htmlChunks: renderState.htmlChunks,
|
||||
headChunks: renderState.headChunks,
|
||||
charsetChunks: renderState.charsetChunks,
|
||||
preconnectChunks: renderState.preconnectChunks,
|
||||
preloadChunks: renderState.preloadChunks,
|
||||
hoistableChunks: renderState.hoistableChunks,
|
||||
boundaryResources: renderState.boundaryResources,
|
||||
stylesToHoist: renderState.stylesToHoist,
|
||||
|
||||
// This is an extra field for the legacy renderer
|
||||
generateStaticMarkup,
|
||||
|
|
@ -111,7 +84,7 @@ import {
|
|||
export const doctypeChunk: PrecomputedChunk = stringToPrecomputedChunk('');
|
||||
|
||||
export type {
|
||||
Resources,
|
||||
ResumableState,
|
||||
BoundaryResources,
|
||||
FormatContext,
|
||||
SuspenseBoundaryID,
|
||||
|
|
@ -137,7 +110,7 @@ export {
|
|||
writePlaceholder,
|
||||
writeCompletedRoot,
|
||||
createRootFormatContext,
|
||||
createResources,
|
||||
createResumableState,
|
||||
createBoundaryResources,
|
||||
writePreamble,
|
||||
writeHoistables,
|
||||
|
|
@ -152,29 +125,29 @@ import escapeTextForBrowser from './escapeTextForBrowser';
|
|||
export function pushTextInstance(
|
||||
target: Array<Chunk | PrecomputedChunk>,
|
||||
text: string,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
textEmbedded: boolean,
|
||||
): boolean {
|
||||
if (responseState.generateStaticMarkup) {
|
||||
if (renderState.generateStaticMarkup) {
|
||||
target.push(stringToChunk(escapeTextForBrowser(text)));
|
||||
return false;
|
||||
} else {
|
||||
return pushTextInstanceImpl(target, text, responseState, textEmbedded);
|
||||
return pushTextInstanceImpl(target, text, renderState, textEmbedded);
|
||||
}
|
||||
}
|
||||
|
||||
export function pushSegmentFinale(
|
||||
target: Array<Chunk | PrecomputedChunk>,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
lastPushedText: boolean,
|
||||
textEmbedded: boolean,
|
||||
): void {
|
||||
if (responseState.generateStaticMarkup) {
|
||||
if (renderState.generateStaticMarkup) {
|
||||
return;
|
||||
} else {
|
||||
return pushSegmentFinaleImpl(
|
||||
target,
|
||||
responseState,
|
||||
renderState,
|
||||
lastPushedText,
|
||||
textEmbedded,
|
||||
);
|
||||
|
|
@ -183,31 +156,31 @@ export function pushSegmentFinale(
|
|||
|
||||
export function writeStartCompletedSuspenseBoundary(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
): boolean {
|
||||
if (responseState.generateStaticMarkup) {
|
||||
if (renderState.generateStaticMarkup) {
|
||||
// A completed boundary is done and doesn't need a representation in the HTML
|
||||
// if we're not going to be hydrating it.
|
||||
return true;
|
||||
}
|
||||
return writeStartCompletedSuspenseBoundaryImpl(destination, responseState);
|
||||
return writeStartCompletedSuspenseBoundaryImpl(destination, renderState);
|
||||
}
|
||||
export function writeStartClientRenderedSuspenseBoundary(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
// flushing these error arguments are not currently supported in this legacy streaming format.
|
||||
errorDigest: ?string,
|
||||
errorMessage: ?string,
|
||||
errorComponentStack: ?string,
|
||||
): boolean {
|
||||
if (responseState.generateStaticMarkup) {
|
||||
if (renderState.generateStaticMarkup) {
|
||||
// A client rendered boundary is done and doesn't need a representation in the HTML
|
||||
// since we'll never hydrate it. This is arguably an error in static generation.
|
||||
return true;
|
||||
}
|
||||
return writeStartClientRenderedSuspenseBoundaryImpl(
|
||||
destination,
|
||||
responseState,
|
||||
renderState,
|
||||
errorDigest,
|
||||
errorMessage,
|
||||
errorComponentStack,
|
||||
|
|
@ -215,21 +188,21 @@ export function writeStartClientRenderedSuspenseBoundary(
|
|||
}
|
||||
export function writeEndCompletedSuspenseBoundary(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
): boolean {
|
||||
if (responseState.generateStaticMarkup) {
|
||||
if (renderState.generateStaticMarkup) {
|
||||
return true;
|
||||
}
|
||||
return writeEndCompletedSuspenseBoundaryImpl(destination, responseState);
|
||||
return writeEndCompletedSuspenseBoundaryImpl(destination, renderState);
|
||||
}
|
||||
export function writeEndClientRenderedSuspenseBoundary(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
): boolean {
|
||||
if (responseState.generateStaticMarkup) {
|
||||
if (renderState.generateStaticMarkup) {
|
||||
return true;
|
||||
}
|
||||
return writeEndClientRenderedSuspenseBoundaryImpl(destination, responseState);
|
||||
return writeEndClientRenderedSuspenseBoundaryImpl(destination, renderState);
|
||||
}
|
||||
|
||||
export type TransitionStatus = FormStatus;
|
||||
|
|
|
|||
|
|
@ -15,3 +15,6 @@ exports.renderToStaticMarkup = l.renderToStaticMarkup;
|
|||
exports.renderToNodeStream = l.renderToNodeStream;
|
||||
exports.renderToStaticNodeStream = l.renderToStaticNodeStream;
|
||||
exports.renderToReadableStream = s.renderToReadableStream;
|
||||
if (s.resume) {
|
||||
exports.resume = s.resume;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ if (process.env.NODE_ENV === 'production') {
|
|||
|
||||
exports.version = b.version;
|
||||
exports.renderToReadableStream = b.renderToReadableStream;
|
||||
if (b.resume) {
|
||||
exports.resume = b.resume;
|
||||
}
|
||||
exports.renderToNodeStream = b.renderToNodeStream;
|
||||
exports.renderToStaticNodeStream = b.renderToStaticNodeStream;
|
||||
exports.renderToString = l.renderToString;
|
||||
|
|
|
|||
|
|
@ -16,3 +16,6 @@ exports.renderToNodeStream = b.renderToNodeStream;
|
|||
exports.renderToStaticNodeStream = b.renderToStaticNodeStream;
|
||||
exports.renderToString = l.renderToString;
|
||||
exports.renderToStaticMarkup = l.renderToStaticMarkup;
|
||||
if (b.resume) {
|
||||
exports.resume = b.resume;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,3 +15,6 @@ exports.renderToStaticMarkup = l.renderToStaticMarkup;
|
|||
exports.renderToNodeStream = l.renderToNodeStream;
|
||||
exports.renderToStaticNodeStream = l.renderToStaticNodeStream;
|
||||
exports.renderToPipeableStream = s.renderToPipeableStream;
|
||||
if (s.resume) {
|
||||
exports.resume = s.resume;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,14 @@ export function renderToStaticNodeStream() {
|
|||
}
|
||||
|
||||
export function renderToReadableStream() {
|
||||
return require('./src/server/ReactDOMFizzServerBrowser').renderToReadableStream.apply(
|
||||
return require('./src/server/react-dom-server.browser').renderToReadableStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function resume() {
|
||||
return require('./src/server/react-dom-server.browser').resume.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,21 +12,21 @@ import ReactVersion from 'shared/ReactVersion';
|
|||
export {ReactVersion as version};
|
||||
|
||||
export function renderToReadableStream() {
|
||||
return require('./src/server/ReactDOMFizzServerBun').renderToReadableStream.apply(
|
||||
return require('./src/server/react-dom-server.bun').renderToReadableStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function renderToNodeStream() {
|
||||
return require('./src/server/ReactDOMFizzServerBun').renderToNodeStream.apply(
|
||||
return require('./src/server/react-dom-server.bun').renderToNodeStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function renderToStaticNodeStream() {
|
||||
return require('./src/server/ReactDOMFizzServerBun').renderToStaticNodeStream.apply(
|
||||
return require('./src/server/react-dom-server.bun').renderToStaticNodeStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
|
|
@ -45,3 +45,10 @@ export function renderToStaticMarkup() {
|
|||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function resume() {
|
||||
return require('./src/server/react-dom-server.bun').resume.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,21 +12,21 @@ import ReactVersion from 'shared/ReactVersion';
|
|||
export {ReactVersion as version};
|
||||
|
||||
export function renderToReadableStream() {
|
||||
return require('./src/server/ReactDOMFizzServerEdge').renderToReadableStream.apply(
|
||||
return require('./src/server/react-dom-server.edge').renderToReadableStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function renderToNodeStream() {
|
||||
return require('./src/server/ReactDOMFizzServerEdge').renderToNodeStream.apply(
|
||||
return require('./src/server/react-dom-server.edge').renderToNodeStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function renderToStaticNodeStream() {
|
||||
return require('./src/server/ReactDOMFizzServerEdge').renderToStaticNodeStream.apply(
|
||||
return require('./src/server/react-dom-server.edge').renderToStaticNodeStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
|
|
@ -45,3 +45,10 @@ export function renderToStaticMarkup() {
|
|||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function resume() {
|
||||
return require('./src/server/react-dom-server.edge').resume.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,14 @@ export function renderToStaticNodeStream() {
|
|||
}
|
||||
|
||||
export function renderToPipeableStream() {
|
||||
return require('./src/server/ReactDOMFizzServerNode').renderToPipeableStream.apply(
|
||||
return require('./src/server/react-dom-server.node').renderToPipeableStream.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
}
|
||||
|
||||
export function resume() {
|
||||
return require('./src/server/react-dom-server.node').resume.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -218,12 +218,14 @@ describe('ReactDOMFizzStatic', () => {
|
|||
);
|
||||
}
|
||||
|
||||
const promise = ReactDOMFizzStatic.prerenderToNodeStreams(<App />);
|
||||
const promise = ReactDOMFizzStatic.prerenderToNodeStream(<App />);
|
||||
|
||||
resolveText('Hello');
|
||||
|
||||
const result = await promise;
|
||||
|
||||
expect(result.postponed).toBe(null);
|
||||
|
||||
await act(async () => {
|
||||
result.prelude.pipe(writable);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
}
|
||||
|
||||
// @gate experimental
|
||||
it('should call prerenderToNodeStreams', async () => {
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
it('should call prerenderToNodeStream', async () => {
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>hello world</div>,
|
||||
);
|
||||
const prelude = await readContent(result.prelude);
|
||||
|
|
@ -57,7 +57,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
|
||||
// @gate experimental
|
||||
it('should emit DOCTYPE at the root of the document', async () => {
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<html>
|
||||
<body>hello world</body>
|
||||
</html>,
|
||||
|
|
@ -76,7 +76,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
|
||||
// @gate experimental
|
||||
it('should emit bootstrap script src at the end', async () => {
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>hello world</div>,
|
||||
{
|
||||
bootstrapScriptContent: 'INIT();',
|
||||
|
|
@ -101,7 +101,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
}
|
||||
return 'Done';
|
||||
}
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<Suspense fallback="Loading">
|
||||
<Wait />
|
||||
|
|
@ -127,7 +127,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
const reportedErrors = [];
|
||||
let caughtError = null;
|
||||
try {
|
||||
await ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
await ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<Throw />
|
||||
</div>,
|
||||
|
|
@ -149,7 +149,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
const reportedErrors = [];
|
||||
let caughtError = null;
|
||||
try {
|
||||
await ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
await ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<Suspense fallback={<Throw />}>
|
||||
<InfiniteSuspend />
|
||||
|
|
@ -171,7 +171,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
// @gate experimental
|
||||
it('should not error the stream when an error is thrown inside suspense boundary', async () => {
|
||||
const reportedErrors = [];
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const result = await ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<Suspense fallback={<div>Loading</div>}>
|
||||
<Throw />
|
||||
|
|
@ -193,7 +193,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
it('should be able to complete by aborting even if the promise never resolves', async () => {
|
||||
const errors = [];
|
||||
const controller = new AbortController();
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<Suspense fallback={<div>Loading</div>}>
|
||||
<InfiniteSuspend />
|
||||
|
|
@ -223,7 +223,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
it('should reject if aborting before the shell is complete', async () => {
|
||||
const errors = [];
|
||||
const controller = new AbortController();
|
||||
const promise = ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const promise = ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<InfiniteSuspend />
|
||||
</div>,
|
||||
|
|
@ -262,7 +262,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
</Suspense>
|
||||
);
|
||||
}
|
||||
const streamPromise = ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const streamPromise = ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<App />
|
||||
</div>,
|
||||
|
|
@ -291,7 +291,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
const theReason = new Error('aborted for reasons');
|
||||
controller.abort(theReason);
|
||||
|
||||
const promise = ReactDOMFizzStatic.prerenderToNodeStreams(
|
||||
const promise = ReactDOMFizzStatic.prerenderToNodeStream(
|
||||
<div>
|
||||
<Suspense fallback={<div>Loading</div>}>
|
||||
<InfiniteSuspend />
|
||||
|
|
@ -342,7 +342,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
|
||||
const errors = [];
|
||||
const controller = new AbortController();
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStreams(<App />, {
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStream(<App />, {
|
||||
signal: controller.signal,
|
||||
onError(x) {
|
||||
errors.push(x);
|
||||
|
|
@ -384,7 +384,7 @@ describe('ReactDOMFizzStaticNode', () => {
|
|||
|
||||
const errors = [];
|
||||
const controller = new AbortController();
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStreams(<App />, {
|
||||
const resultPromise = ReactDOMFizzStatic.prerenderToNodeStream(<App />, {
|
||||
signal: controller.signal,
|
||||
onError(x) {
|
||||
errors.push(x.message);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {PostponedState} from 'react-server/src/ReactFizzServer';
|
||||
import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -20,8 +21,8 @@ import {
|
|||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -39,6 +40,14 @@ type Options = {
|
|||
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
|
||||
};
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
signal?: AbortSignal,
|
||||
onError?: (error: mixed) => ?string,
|
||||
onPostpone?: (reason: string) => void,
|
||||
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
|
||||
};
|
||||
|
||||
// TODO: Move to sub-classing ReadableStream.
|
||||
type ReactDOMServerReadableStream = ReadableStream & {
|
||||
allReady: Promise<void>,
|
||||
|
|
@ -81,19 +90,18 @@ function renderToReadableStream(
|
|||
allReady.catch(() => {});
|
||||
reject(error);
|
||||
}
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, options ? options.nonce : undefined),
|
||||
createRootFormatContext(options ? options.namespaceURI : undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options ? options.onError : undefined,
|
||||
|
|
@ -119,4 +127,74 @@ function renderToReadableStream(
|
|||
});
|
||||
}
|
||||
|
||||
export {renderToReadableStream, ReactVersion as version};
|
||||
function resume(
|
||||
children: ReactNodeList,
|
||||
postponedState: PostponedState,
|
||||
options?: ResumeOptions,
|
||||
): Promise<ReactDOMServerReadableStream> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let onFatalError;
|
||||
let onAllReady;
|
||||
const allReady = new Promise<void>((res, rej) => {
|
||||
onAllReady = res;
|
||||
onFatalError = rej;
|
||||
});
|
||||
|
||||
function onShellReady() {
|
||||
const stream: ReactDOMServerReadableStream = (new ReadableStream(
|
||||
{
|
||||
type: 'bytes',
|
||||
pull: (controller): ?Promise<void> => {
|
||||
startFlowing(request, controller);
|
||||
},
|
||||
cancel: (reason): ?Promise<void> => {
|
||||
abort(request);
|
||||
},
|
||||
},
|
||||
// $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
|
||||
{highWaterMark: 0},
|
||||
): any);
|
||||
// TODO: Move to sub-classing ReadableStream.
|
||||
stream.allReady = allReady;
|
||||
resolve(stream);
|
||||
}
|
||||
function onShellError(error: mixed) {
|
||||
// If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
|
||||
// However, `allReady` will be rejected by `onFatalError` as well.
|
||||
// So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
|
||||
allReady.catch(() => {});
|
||||
reject(error);
|
||||
}
|
||||
const request = createRequest(
|
||||
children,
|
||||
postponedState.resumableState,
|
||||
createRenderState(
|
||||
postponedState.resumableState,
|
||||
options ? options.nonce : undefined,
|
||||
),
|
||||
postponedState.rootFormatContext,
|
||||
postponedState.progressiveChunkSize,
|
||||
options ? options.onError : undefined,
|
||||
onAllReady,
|
||||
onShellReady,
|
||||
onShellError,
|
||||
onFatalError,
|
||||
options ? options.onPostpone : undefined,
|
||||
);
|
||||
if (options && options.signal) {
|
||||
const signal = options.signal;
|
||||
if (signal.aborted) {
|
||||
abort(request, (signal: any).reason);
|
||||
} else {
|
||||
const listener = () => {
|
||||
abort(request, (signal: any).reason);
|
||||
signal.removeEventListener('abort', listener);
|
||||
};
|
||||
signal.addEventListener('abort', listener);
|
||||
}
|
||||
}
|
||||
startWork(request);
|
||||
});
|
||||
}
|
||||
|
||||
export {renderToReadableStream, resume, ReactVersion as version};
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import {
|
|||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -82,19 +82,18 @@ function renderToReadableStream(
|
|||
allReady.catch(() => {});
|
||||
reject(error);
|
||||
}
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, options ? options.nonce : undefined),
|
||||
createRootFormatContext(options ? options.namespaceURI : undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options ? options.onError : undefined,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {PostponedState} from 'react-server/src/ReactFizzServer';
|
||||
import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -20,8 +21,8 @@ import {
|
|||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -39,6 +40,14 @@ type Options = {
|
|||
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
|
||||
};
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
signal?: AbortSignal,
|
||||
onError?: (error: mixed) => ?string,
|
||||
onPostpone?: (reason: string) => void,
|
||||
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
|
||||
};
|
||||
|
||||
// TODO: Move to sub-classing ReadableStream.
|
||||
type ReactDOMServerReadableStream = ReadableStream & {
|
||||
allReady: Promise<void>,
|
||||
|
|
@ -81,19 +90,18 @@ function renderToReadableStream(
|
|||
allReady.catch(() => {});
|
||||
reject(error);
|
||||
}
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, options ? options.nonce : undefined),
|
||||
createRootFormatContext(options ? options.namespaceURI : undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options ? options.onError : undefined,
|
||||
|
|
@ -119,4 +127,74 @@ function renderToReadableStream(
|
|||
});
|
||||
}
|
||||
|
||||
export {renderToReadableStream, ReactVersion as version};
|
||||
function resume(
|
||||
children: ReactNodeList,
|
||||
postponedState: PostponedState,
|
||||
options?: ResumeOptions,
|
||||
): Promise<ReactDOMServerReadableStream> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let onFatalError;
|
||||
let onAllReady;
|
||||
const allReady = new Promise<void>((res, rej) => {
|
||||
onAllReady = res;
|
||||
onFatalError = rej;
|
||||
});
|
||||
|
||||
function onShellReady() {
|
||||
const stream: ReactDOMServerReadableStream = (new ReadableStream(
|
||||
{
|
||||
type: 'bytes',
|
||||
pull: (controller): ?Promise<void> => {
|
||||
startFlowing(request, controller);
|
||||
},
|
||||
cancel: (reason): ?Promise<void> => {
|
||||
abort(request);
|
||||
},
|
||||
},
|
||||
// $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
|
||||
{highWaterMark: 0},
|
||||
): any);
|
||||
// TODO: Move to sub-classing ReadableStream.
|
||||
stream.allReady = allReady;
|
||||
resolve(stream);
|
||||
}
|
||||
function onShellError(error: mixed) {
|
||||
// If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
|
||||
// However, `allReady` will be rejected by `onFatalError` as well.
|
||||
// So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
|
||||
allReady.catch(() => {});
|
||||
reject(error);
|
||||
}
|
||||
const request = createRequest(
|
||||
children,
|
||||
postponedState.resumableState,
|
||||
createRenderState(
|
||||
postponedState.resumableState,
|
||||
options ? options.nonce : undefined,
|
||||
),
|
||||
postponedState.rootFormatContext,
|
||||
postponedState.progressiveChunkSize,
|
||||
options ? options.onError : undefined,
|
||||
onAllReady,
|
||||
onShellReady,
|
||||
onShellError,
|
||||
onFatalError,
|
||||
options ? options.onPostpone : undefined,
|
||||
);
|
||||
if (options && options.signal) {
|
||||
const signal = options.signal;
|
||||
if (signal.aborted) {
|
||||
abort(request, (signal: any).reason);
|
||||
} else {
|
||||
const listener = () => {
|
||||
abort(request, (signal: any).reason);
|
||||
signal.removeEventListener('abort', listener);
|
||||
};
|
||||
signal.addEventListener('abort', listener);
|
||||
}
|
||||
}
|
||||
startWork(request);
|
||||
});
|
||||
}
|
||||
|
||||
export {renderToReadableStream, resume, ReactVersion as version};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {Request} from 'react-server/src/ReactFizzServer';
|
||||
import type {Request, PostponedState} from 'react-server/src/ReactFizzServer';
|
||||
import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
import type {Writable} from 'stream';
|
||||
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
|
@ -23,8 +23,8 @@ import {
|
|||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -53,6 +53,15 @@ type Options = {
|
|||
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
|
||||
};
|
||||
|
||||
type ResumeOptions = {
|
||||
nonce?: string,
|
||||
onShellReady?: () => void,
|
||||
onShellError?: (error: mixed) => void,
|
||||
onAllReady?: () => void,
|
||||
onError?: (error: mixed) => ?string,
|
||||
onPostpone?: (reason: string) => void,
|
||||
};
|
||||
|
||||
type PipeableStream = {
|
||||
// Cancel any pending I/O and put anything remaining into
|
||||
// client rendered mode.
|
||||
|
|
@ -61,19 +70,18 @@ type PipeableStream = {
|
|||
};
|
||||
|
||||
function createRequestImpl(children: ReactNodeList, options: void | Options) {
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
return createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
options ? options.nonce : undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, options ? options.nonce : undefined),
|
||||
createRootFormatContext(options ? options.namespaceURI : undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options ? options.onError : undefined,
|
||||
|
|
@ -121,4 +129,68 @@ function renderToPipeableStream(
|
|||
};
|
||||
}
|
||||
|
||||
export {renderToPipeableStream, ReactVersion as version};
|
||||
function resumeRequestImpl(
|
||||
children: ReactNodeList,
|
||||
postponedState: PostponedState,
|
||||
options: void | ResumeOptions,
|
||||
) {
|
||||
return createRequest(
|
||||
children,
|
||||
postponedState.resumableState,
|
||||
createRenderState(
|
||||
postponedState.resumableState,
|
||||
options ? options.nonce : undefined,
|
||||
),
|
||||
postponedState.rootFormatContext,
|
||||
postponedState.progressiveChunkSize,
|
||||
options ? options.onError : undefined,
|
||||
options ? options.onAllReady : undefined,
|
||||
options ? options.onShellReady : undefined,
|
||||
options ? options.onShellError : undefined,
|
||||
undefined,
|
||||
options ? options.onPostpone : undefined,
|
||||
);
|
||||
}
|
||||
|
||||
function resumeToPipeableStream(
|
||||
children: ReactNodeList,
|
||||
postponedState: PostponedState,
|
||||
options?: ResumeOptions,
|
||||
): PipeableStream {
|
||||
const request = resumeRequestImpl(children, postponedState, options);
|
||||
let hasStartedFlowing = false;
|
||||
startWork(request);
|
||||
return {
|
||||
pipe<T: Writable>(destination: T): T {
|
||||
if (hasStartedFlowing) {
|
||||
throw new Error(
|
||||
'React currently only supports piping to one writable stream.',
|
||||
);
|
||||
}
|
||||
hasStartedFlowing = true;
|
||||
startFlowing(request, destination);
|
||||
destination.on('drain', createDrainHandler(destination, request));
|
||||
destination.on(
|
||||
'error',
|
||||
createAbortHandler(
|
||||
request,
|
||||
'The destination stream errored while writing data.',
|
||||
),
|
||||
);
|
||||
destination.on(
|
||||
'close',
|
||||
createAbortHandler(request, 'The destination stream closed early.'),
|
||||
);
|
||||
return destination;
|
||||
},
|
||||
abort(reason: mixed) {
|
||||
abort(request, reason);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
renderToPipeableStream,
|
||||
resumeToPipeableStream,
|
||||
ReactVersion as version,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
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 ReactVersion from 'shared/ReactVersion';
|
||||
|
||||
|
|
@ -17,11 +18,12 @@ import {
|
|||
startWork,
|
||||
startFlowing,
|
||||
abort,
|
||||
getPostponedState,
|
||||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -39,6 +41,7 @@ type Options = {
|
|||
};
|
||||
|
||||
type StaticResult = {
|
||||
postponed: null | PostponedState,
|
||||
prelude: ReadableStream,
|
||||
};
|
||||
|
||||
|
|
@ -62,23 +65,23 @@ function prerender(
|
|||
);
|
||||
|
||||
const result = {
|
||||
postponed: getPostponedState(request),
|
||||
prelude: stream,
|
||||
};
|
||||
resolve(result);
|
||||
}
|
||||
const resources = createResources();
|
||||
const resources = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined, // nonce is not compatible with prerendered bootstrap scripts
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
createRenderState(resources, undefined),
|
||||
createRootFormatContext(options ? options.namespaceURI : undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options ? options.onError : undefined,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
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 ReactVersion from 'shared/ReactVersion';
|
||||
|
||||
|
|
@ -17,11 +18,12 @@ import {
|
|||
startWork,
|
||||
startFlowing,
|
||||
abort,
|
||||
getPostponedState,
|
||||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -39,6 +41,7 @@ type Options = {
|
|||
};
|
||||
|
||||
type StaticResult = {
|
||||
postponed: null | PostponedState,
|
||||
prelude: ReadableStream,
|
||||
};
|
||||
|
||||
|
|
@ -62,23 +65,23 @@ function prerender(
|
|||
);
|
||||
|
||||
const result = {
|
||||
postponed: getPostponedState(request),
|
||||
prelude: stream,
|
||||
};
|
||||
resolve(result);
|
||||
}
|
||||
const resources = createResources();
|
||||
const resources = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined, // nonce is not compatible with prerendered bootstrap scripts
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
createRenderState(resources, undefined),
|
||||
createRootFormatContext(options ? options.namespaceURI : undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options ? options.onError : undefined,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
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 {Writable, Readable} from 'stream';
|
||||
|
||||
|
|
@ -19,11 +20,12 @@ import {
|
|||
startWork,
|
||||
startFlowing,
|
||||
abort,
|
||||
getPostponedState,
|
||||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
|
|
@ -41,6 +43,7 @@ type Options = {
|
|||
};
|
||||
|
||||
type StaticResult = {
|
||||
postponed: null | PostponedState,
|
||||
prelude: Readable,
|
||||
};
|
||||
|
||||
|
|
@ -60,7 +63,7 @@ function createFakeWritable(readable: any): Writable {
|
|||
}: any);
|
||||
}
|
||||
|
||||
function prerenderToNodeStreams(
|
||||
function prerenderToNodeStream(
|
||||
children: ReactNodeList,
|
||||
options?: Options,
|
||||
): Promise<StaticResult> {
|
||||
|
|
@ -76,23 +79,23 @@ function prerenderToNodeStreams(
|
|||
const writable = createFakeWritable(readable);
|
||||
|
||||
const result = {
|
||||
postponed: getPostponedState(request),
|
||||
prelude: readable,
|
||||
};
|
||||
resolve(result);
|
||||
}
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined, // nonce is not compatible with prerendered bootstrap scripts
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, undefined),
|
||||
createRootFormatContext(options ? options.namespaceURI : undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options ? options.onError : undefined,
|
||||
|
|
@ -118,4 +121,4 @@ function prerenderToNodeStreams(
|
|||
});
|
||||
}
|
||||
|
||||
export {prerenderToNodeStreams, ReactVersion as version};
|
||||
export {prerenderToNodeStream, ReactVersion as version};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
import ReactVersion from 'shared/ReactVersion';
|
||||
|
||||
import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
|
||||
|
||||
import {
|
||||
createRequest,
|
||||
|
|
@ -20,8 +19,8 @@ import {
|
|||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOMLegacy';
|
||||
|
||||
|
|
@ -38,7 +37,6 @@ function renderToStringImpl(
|
|||
options: void | ServerOptions,
|
||||
generateStaticMarkup: boolean,
|
||||
abortReason: string,
|
||||
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
|
||||
): string {
|
||||
let didFatal = false;
|
||||
let fatalError = null;
|
||||
|
|
@ -62,16 +60,18 @@ function renderToStringImpl(
|
|||
function onShellReady() {
|
||||
readyToStream = true;
|
||||
}
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
generateStaticMarkup,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
unstable_externalRuntimeSrc,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, undefined, generateStaticMarkup),
|
||||
createRootFormatContext(),
|
||||
Infinity,
|
||||
onError,
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import {
|
|||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-dom-bindings/src/server/ReactFizzConfigDOMLegacy';
|
||||
|
||||
|
|
@ -71,15 +71,18 @@ function renderToNodeStreamImpl(
|
|||
startFlowing(request, destination);
|
||||
}
|
||||
const destination = new ReactMarkupReadableStream();
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
false,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, undefined, false),
|
||||
createRootFormatContext(),
|
||||
Infinity,
|
||||
onError,
|
||||
|
|
|
|||
10
packages/react-dom/src/server/react-dom-server.browser.js
Normal file
10
packages/react-dom/src/server/react-dom-server.browser.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export * from './ReactDOMFizzServerBrowser.js';
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export {renderToReadableStream, version} from './ReactDOMFizzServerBrowser.js';
|
||||
10
packages/react-dom/src/server/react-dom-server.bun.js
Normal file
10
packages/react-dom/src/server/react-dom-server.bun.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export * from './ReactDOMFizzServerBun.js';
|
||||
15
packages/react-dom/src/server/react-dom-server.bun.stable.js
Normal file
15
packages/react-dom/src/server/react-dom-server.bun.stable.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export {
|
||||
renderToReadableStream,
|
||||
renderToNodeStream,
|
||||
renderToStaticNodeStream,
|
||||
version,
|
||||
} from './ReactDOMFizzServerBun.js';
|
||||
10
packages/react-dom/src/server/react-dom-server.edge.js
Normal file
10
packages/react-dom/src/server/react-dom-server.edge.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export * from './ReactDOMFizzServerEdge.js';
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export {renderToReadableStream, version} from './ReactDOMFizzServerEdge.js';
|
||||
10
packages/react-dom/src/server/react-dom-server.node.js
Normal file
10
packages/react-dom/src/server/react-dom-server.node.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export * from './ReactDOMFizzServerNode.js';
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export {renderToPipeableStream, version} from './ReactDOMFizzServerNode.js';
|
||||
|
|
@ -8,6 +8,6 @@
|
|||
*/
|
||||
|
||||
export {
|
||||
prerenderToNodeStreams,
|
||||
prerenderToNodeStream,
|
||||
version,
|
||||
} from './src/server/ReactDOMFizzStaticNode';
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ type Destination = {
|
|||
stack: Array<Segment | Instance | SuspenseInstance>,
|
||||
};
|
||||
|
||||
type Resources = null;
|
||||
type RenderState = null;
|
||||
type BoundaryResources = null;
|
||||
|
||||
const POP = Buffer.from('/', 'utf8');
|
||||
|
|
@ -104,7 +104,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
pushTextInstance(
|
||||
target: Array<Uint8Array>,
|
||||
text: string,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
textEmbedded: boolean,
|
||||
): boolean {
|
||||
const textInstance: TextInstance = {
|
||||
|
|
@ -140,21 +140,21 @@ const ReactNoopServer = ReactFizzServer({
|
|||
// This is a noop in ReactNoop
|
||||
pushSegmentFinale(
|
||||
target: Array<Uint8Array>,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
lastPushedText: boolean,
|
||||
textEmbedded: boolean,
|
||||
): void {},
|
||||
|
||||
writeCompletedRoot(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
): boolean {
|
||||
return true;
|
||||
},
|
||||
|
||||
writePlaceholder(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
id: number,
|
||||
): boolean {
|
||||
const parent = destination.stack[destination.stack.length - 1];
|
||||
|
|
@ -166,7 +166,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
|
||||
writeStartCompletedSuspenseBoundary(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
suspenseInstance: SuspenseInstance,
|
||||
): boolean {
|
||||
suspenseInstance.state = 'complete';
|
||||
|
|
@ -176,7 +176,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
},
|
||||
writeStartPendingSuspenseBoundary(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
suspenseInstance: SuspenseInstance,
|
||||
): boolean {
|
||||
suspenseInstance.state = 'pending';
|
||||
|
|
@ -186,7 +186,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
},
|
||||
writeStartClientRenderedSuspenseBoundary(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
suspenseInstance: SuspenseInstance,
|
||||
): boolean {
|
||||
suspenseInstance.state = 'client-render';
|
||||
|
|
@ -206,7 +206,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
|
||||
writeStartSegment(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
formatContext: null,
|
||||
id: number,
|
||||
): boolean {
|
||||
|
|
@ -225,7 +225,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
|
||||
writeCompletedSegmentInstruction(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
contentSegmentID: number,
|
||||
): boolean {
|
||||
const segment = destination.segments.get(contentSegmentID);
|
||||
|
|
@ -245,7 +245,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
|
||||
writeCompletedBoundaryInstruction(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
boundary: SuspenseInstance,
|
||||
contentSegmentID: number,
|
||||
): boolean {
|
||||
|
|
@ -259,7 +259,7 @@ const ReactNoopServer = ReactFizzServer({
|
|||
|
||||
writeClientRenderBoundaryInstruction(
|
||||
destination: Destination,
|
||||
responseState: ResponseState,
|
||||
renderState: RenderState,
|
||||
boundary: SuspenseInstance,
|
||||
): boolean {
|
||||
boundary.status = 'client-render';
|
||||
|
|
@ -269,10 +269,6 @@ const ReactNoopServer = ReactFizzServer({
|
|||
writeHoistables() {},
|
||||
writePostamble() {},
|
||||
|
||||
createResources(): Resources {
|
||||
return null;
|
||||
},
|
||||
|
||||
createBoundaryResources(): BoundaryResources {
|
||||
return null;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import {
|
|||
} from 'react-server/src/ReactFizzServer';
|
||||
|
||||
import {
|
||||
createResources,
|
||||
createResponseState,
|
||||
createResumableState,
|
||||
createRenderState,
|
||||
createRootFormatContext,
|
||||
} from 'react-server/src/ReactFizzConfig';
|
||||
|
||||
|
|
@ -50,19 +50,18 @@ function renderToStream(children: ReactNodeList, options: Options): Stream {
|
|||
fatal: false,
|
||||
error: null,
|
||||
};
|
||||
const resources = createResources();
|
||||
const resumableState = createResumableState(
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
);
|
||||
const request = createRequest(
|
||||
children,
|
||||
resources,
|
||||
createResponseState(
|
||||
resources,
|
||||
options ? options.identifierPrefix : undefined,
|
||||
undefined,
|
||||
options ? options.bootstrapScriptContent : undefined,
|
||||
options ? options.bootstrapScripts : undefined,
|
||||
options ? options.bootstrapModules : undefined,
|
||||
options ? options.unstable_externalRuntimeSrc : undefined,
|
||||
),
|
||||
resumableState,
|
||||
createRenderState(resumableState, undefined),
|
||||
createRootFormatContext(undefined),
|
||||
options ? options.progressiveChunkSize : undefined,
|
||||
options.onError,
|
||||
|
|
|
|||
16
packages/react-server/src/ReactFizzHooks.js
vendored
16
packages/react-server/src/ReactFizzHooks.js
vendored
|
|
@ -16,7 +16,7 @@ import type {
|
|||
Usable,
|
||||
} from 'shared/ReactTypes';
|
||||
|
||||
import type {ResponseState} from './ReactFizzConfig';
|
||||
import type {ResumableState} from './ReactFizzConfig';
|
||||
import type {Task} from './ReactFizzServer';
|
||||
import type {ThenableState} from './ReactFizzThenable';
|
||||
import type {TransitionStatus} from './ReactFizzConfig';
|
||||
|
|
@ -554,15 +554,15 @@ function useId(): string {
|
|||
const task: Task = (currentlyRenderingTask: any);
|
||||
const treeId = getTreeId(task.treeContext);
|
||||
|
||||
const responseState = currentResponseState;
|
||||
if (responseState === null) {
|
||||
const resumableState = currentResumableState;
|
||||
if (resumableState === null) {
|
||||
throw new Error(
|
||||
'Invalid hook call. Hooks can only be called inside of the body of a function component.',
|
||||
);
|
||||
}
|
||||
|
||||
const localId = localIdCounter++;
|
||||
return makeId(responseState, treeId, localId);
|
||||
return makeId(resumableState, treeId, localId);
|
||||
}
|
||||
|
||||
function use<T>(usable: Usable<T>): T {
|
||||
|
|
@ -652,9 +652,9 @@ if (enableAsyncActions) {
|
|||
HooksDispatcher.useOptimistic = useOptimistic;
|
||||
}
|
||||
|
||||
export let currentResponseState: null | ResponseState = (null: any);
|
||||
export function setCurrentResponseState(
|
||||
responseState: null | ResponseState,
|
||||
export let currentResumableState: null | ResumableState = (null: any);
|
||||
export function setCurrentResumableState(
|
||||
resumableState: null | ResumableState,
|
||||
): void {
|
||||
currentResponseState = responseState;
|
||||
currentResumableState = resumableState;
|
||||
}
|
||||
|
|
|
|||
121
packages/react-server/src/ReactFizzServer.js
vendored
121
packages/react-server/src/ReactFizzServer.js
vendored
|
|
@ -23,9 +23,9 @@ import type {
|
|||
import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
|
||||
import type {
|
||||
SuspenseBoundaryID,
|
||||
ResponseState,
|
||||
RenderState,
|
||||
ResumableState,
|
||||
FormatContext,
|
||||
Resources,
|
||||
BoundaryResources,
|
||||
} from './ReactFizzConfig';
|
||||
import type {ContextSnapshot} from './ReactFizzNewContext';
|
||||
|
|
@ -100,8 +100,8 @@ import {
|
|||
checkDidRenderIdHook,
|
||||
resetHooksState,
|
||||
HooksDispatcher,
|
||||
currentResponseState,
|
||||
setCurrentResponseState,
|
||||
currentResumableState,
|
||||
setCurrentResumableState,
|
||||
getThenableStateAfterSuspending,
|
||||
unwrapThenable,
|
||||
} from './ReactFizzHooks';
|
||||
|
|
@ -222,14 +222,14 @@ const CLOSED = 2;
|
|||
export opaque type Request = {
|
||||
destination: null | Destination,
|
||||
flushScheduled: boolean,
|
||||
+responseState: ResponseState,
|
||||
+resumableState: ResumableState,
|
||||
+renderState: RenderState,
|
||||
+progressiveChunkSize: number,
|
||||
status: 0 | 1 | 2,
|
||||
fatalError: mixed,
|
||||
nextSegmentId: number,
|
||||
allPendingTasks: number, // when it reaches zero, we can close the connection.
|
||||
pendingRootTasks: number, // when this reaches zero, we've finished at least the root boundary.
|
||||
resources: Resources,
|
||||
completedRootSegment: null | Segment, // Completed but not yet flushed root segments.
|
||||
abortableTasks: Set<Task>,
|
||||
pingedTasks: Array<Task>, // High priority tasks that should be worked on first.
|
||||
|
|
@ -283,8 +283,8 @@ function noop(): void {}
|
|||
|
||||
export function createRequest(
|
||||
children: ReactNodeList,
|
||||
resources: Resources,
|
||||
responseState: ResponseState,
|
||||
resumableState: ResumableState,
|
||||
renderState: RenderState,
|
||||
rootFormatContext: FormatContext,
|
||||
progressiveChunkSize: void | number,
|
||||
onError: void | ((error: mixed) => ?string),
|
||||
|
|
@ -300,7 +300,8 @@ export function createRequest(
|
|||
const request: Request = {
|
||||
destination: null,
|
||||
flushScheduled: false,
|
||||
responseState,
|
||||
resumableState,
|
||||
renderState,
|
||||
progressiveChunkSize:
|
||||
progressiveChunkSize === undefined
|
||||
? DEFAULT_PROGRESSIVE_CHUNK_SIZE
|
||||
|
|
@ -310,7 +311,6 @@ export function createRequest(
|
|||
nextSegmentId: 0,
|
||||
allPendingTasks: 0,
|
||||
pendingRootTasks: 0,
|
||||
resources,
|
||||
completedRootSegment: null,
|
||||
abortableTasks: abortSet,
|
||||
pingedTasks: pingedTasks,
|
||||
|
|
@ -622,7 +622,7 @@ function renderSuspenseBoundary(
|
|||
task.blockedSegment = contentRootSegment;
|
||||
if (enableFloat) {
|
||||
setCurrentlyRenderingBoundaryResourcesTarget(
|
||||
request.resources,
|
||||
request.renderState,
|
||||
newBoundary.resources,
|
||||
);
|
||||
}
|
||||
|
|
@ -631,7 +631,7 @@ function renderSuspenseBoundary(
|
|||
renderNode(request, task, content, 0);
|
||||
pushSegmentFinale(
|
||||
contentRootSegment.chunks,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
contentRootSegment.lastPushedText,
|
||||
contentRootSegment.textEmbedded,
|
||||
);
|
||||
|
|
@ -672,7 +672,7 @@ function renderSuspenseBoundary(
|
|||
} finally {
|
||||
if (enableFloat) {
|
||||
setCurrentlyRenderingBoundaryResourcesTarget(
|
||||
request.resources,
|
||||
request.renderState,
|
||||
parentBoundary ? parentBoundary.resources : null,
|
||||
);
|
||||
}
|
||||
|
|
@ -734,8 +734,8 @@ function renderHostElement(
|
|||
segment.chunks,
|
||||
type,
|
||||
props,
|
||||
request.resources,
|
||||
request.responseState,
|
||||
request.resumableState,
|
||||
request.renderState,
|
||||
segment.formatContext,
|
||||
segment.lastPushedText,
|
||||
);
|
||||
|
|
@ -754,7 +754,7 @@ function renderHostElement(
|
|||
segment.chunks,
|
||||
type,
|
||||
props,
|
||||
request.responseState,
|
||||
request.resumableState,
|
||||
prevContext,
|
||||
);
|
||||
segment.lastPushedText = false;
|
||||
|
|
@ -1568,7 +1568,7 @@ function renderNodeDestructiveImpl(
|
|||
segment.lastPushedText = pushTextInstance(
|
||||
task.blockedSegment.chunks,
|
||||
node,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
segment.lastPushedText,
|
||||
);
|
||||
return;
|
||||
|
|
@ -1579,7 +1579,7 @@ function renderNodeDestructiveImpl(
|
|||
segment.lastPushedText = pushTextInstance(
|
||||
task.blockedSegment.chunks,
|
||||
'' + node,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
segment.lastPushedText,
|
||||
);
|
||||
return;
|
||||
|
|
@ -1975,7 +1975,7 @@ function retryTask(request: Request, task: Task): void {
|
|||
if (enableFloat) {
|
||||
const blockedBoundary = task.blockedBoundary;
|
||||
setCurrentlyRenderingBoundaryResourcesTarget(
|
||||
request.resources,
|
||||
request.renderState,
|
||||
blockedBoundary ? blockedBoundary.resources : null,
|
||||
);
|
||||
}
|
||||
|
|
@ -2009,7 +2009,7 @@ function retryTask(request: Request, task: Task): void {
|
|||
renderNodeDestructive(request, task, prevThenableState, task.node, 0);
|
||||
pushSegmentFinale(
|
||||
segment.chunks,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
segment.lastPushedText,
|
||||
segment.textEmbedded,
|
||||
);
|
||||
|
|
@ -2047,7 +2047,7 @@ function retryTask(request: Request, task: Task): void {
|
|||
}
|
||||
} finally {
|
||||
if (enableFloat) {
|
||||
setCurrentlyRenderingBoundaryResourcesTarget(request.resources, null);
|
||||
setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
|
||||
}
|
||||
if (__DEV__) {
|
||||
currentTaskInDEV = prevTaskInDEV;
|
||||
|
|
@ -2076,8 +2076,8 @@ export function performWork(request: Request): void {
|
|||
prevGetCurrentStackImpl = ReactDebugCurrentFrame.getCurrentStack;
|
||||
ReactDebugCurrentFrame.getCurrentStack = getCurrentStackInDEV;
|
||||
}
|
||||
const prevResponseState = currentResponseState;
|
||||
setCurrentResponseState(request.responseState);
|
||||
const prevResumableState = currentResumableState;
|
||||
setCurrentResumableState(request.resumableState);
|
||||
try {
|
||||
const pingedTasks = request.pingedTasks;
|
||||
let i;
|
||||
|
|
@ -2093,7 +2093,7 @@ export function performWork(request: Request): void {
|
|||
logRecoverableError(request, error);
|
||||
fatalError(request, error);
|
||||
} finally {
|
||||
setCurrentResponseState(prevResponseState);
|
||||
setCurrentResumableState(prevResumableState);
|
||||
ReactCurrentDispatcher.current = prevDispatcher;
|
||||
if (enableCache) {
|
||||
ReactCurrentCache.current = prevCacheDispatcher;
|
||||
|
|
@ -2130,7 +2130,7 @@ function flushSubtree(
|
|||
// When this segment finally completes it won't be embedded in text since it will flush separately
|
||||
segment.lastPushedText = false;
|
||||
segment.textEmbedded = false;
|
||||
return writePlaceholder(destination, request.responseState, segmentID);
|
||||
return writePlaceholder(destination, request.renderState, segmentID);
|
||||
}
|
||||
case COMPLETED: {
|
||||
segment.status = FLUSHED;
|
||||
|
|
@ -2183,7 +2183,7 @@ function flushSegment(
|
|||
|
||||
writeStartClientRenderedSuspenseBoundary(
|
||||
destination,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
boundary.errorDigest,
|
||||
boundary.errorMessage,
|
||||
boundary.errorComponentStack,
|
||||
|
|
@ -2193,7 +2193,7 @@ function flushSegment(
|
|||
|
||||
return writeEndClientRenderedSuspenseBoundary(
|
||||
destination,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
);
|
||||
} else if (boundary.pendingTasks > 0) {
|
||||
// This boundary is still loading. Emit a pending suspense boundary wrapper.
|
||||
|
|
@ -2206,14 +2206,17 @@ function flushSegment(
|
|||
}
|
||||
|
||||
/// This is the first time we should have referenced this ID.
|
||||
const id = (boundary.id = assignSuspenseBoundaryID(request.responseState));
|
||||
const id = (boundary.id = assignSuspenseBoundaryID(
|
||||
request.renderState,
|
||||
request.resumableState,
|
||||
));
|
||||
|
||||
writeStartPendingSuspenseBoundary(destination, request.responseState, id);
|
||||
writeStartPendingSuspenseBoundary(destination, request.renderState, id);
|
||||
|
||||
// Flush the fallback.
|
||||
flushSubtree(request, destination, segment);
|
||||
|
||||
return writeEndPendingSuspenseBoundary(destination, request.responseState);
|
||||
return writeEndPendingSuspenseBoundary(destination, request.renderState);
|
||||
} else if (boundary.byteSize > request.progressiveChunkSize) {
|
||||
// This boundary is large and will be emitted separately so that we can progressively show
|
||||
// other content. We add it to the queue during the flush because we have to ensure that
|
||||
|
|
@ -2228,20 +2231,20 @@ function flushSegment(
|
|||
// Emit a pending rendered suspense boundary wrapper.
|
||||
writeStartPendingSuspenseBoundary(
|
||||
destination,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
boundary.id,
|
||||
);
|
||||
|
||||
// Flush the fallback.
|
||||
flushSubtree(request, destination, segment);
|
||||
|
||||
return writeEndPendingSuspenseBoundary(destination, request.responseState);
|
||||
return writeEndPendingSuspenseBoundary(destination, request.renderState);
|
||||
} else {
|
||||
if (enableFloat) {
|
||||
hoistResources(request.resources, boundary.resources);
|
||||
hoistResources(request.renderState, boundary.resources);
|
||||
}
|
||||
// We can inline this boundary's content as a complete boundary.
|
||||
writeStartCompletedSuspenseBoundary(destination, request.responseState);
|
||||
writeStartCompletedSuspenseBoundary(destination, request.renderState);
|
||||
|
||||
const completedSegments = boundary.completedSegments;
|
||||
|
||||
|
|
@ -2254,10 +2257,7 @@ function flushSegment(
|
|||
const contentSegment = completedSegments[0];
|
||||
flushSegment(request, destination, contentSegment);
|
||||
|
||||
return writeEndCompletedSuspenseBoundary(
|
||||
destination,
|
||||
request.responseState,
|
||||
);
|
||||
return writeEndCompletedSuspenseBoundary(destination, request.renderState);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2268,7 +2268,8 @@ function flushClientRenderedBoundary(
|
|||
): boolean {
|
||||
return writeClientRenderBoundaryInstruction(
|
||||
destination,
|
||||
request.responseState,
|
||||
request.resumableState,
|
||||
request.renderState,
|
||||
boundary.id,
|
||||
boundary.errorDigest,
|
||||
boundary.errorMessage,
|
||||
|
|
@ -2283,7 +2284,7 @@ function flushSegmentContainer(
|
|||
): boolean {
|
||||
writeStartSegment(
|
||||
destination,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
segment.formatContext,
|
||||
segment.id,
|
||||
);
|
||||
|
|
@ -2298,7 +2299,7 @@ function flushCompletedBoundary(
|
|||
): boolean {
|
||||
if (enableFloat) {
|
||||
setCurrentlyRenderingBoundaryResourcesTarget(
|
||||
request.resources,
|
||||
request.renderState,
|
||||
boundary.resources,
|
||||
);
|
||||
}
|
||||
|
|
@ -2314,13 +2315,14 @@ function flushCompletedBoundary(
|
|||
writeResourcesForBoundary(
|
||||
destination,
|
||||
boundary.resources,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
);
|
||||
}
|
||||
|
||||
return writeCompletedBoundaryInstruction(
|
||||
destination,
|
||||
request.responseState,
|
||||
request.resumableState,
|
||||
request.renderState,
|
||||
boundary.id,
|
||||
boundary.rootSegmentID,
|
||||
boundary.resources,
|
||||
|
|
@ -2334,7 +2336,7 @@ function flushPartialBoundary(
|
|||
): boolean {
|
||||
if (enableFloat) {
|
||||
setCurrentlyRenderingBoundaryResourcesTarget(
|
||||
request.resources,
|
||||
request.renderState,
|
||||
boundary.resources,
|
||||
);
|
||||
}
|
||||
|
|
@ -2362,7 +2364,7 @@ function flushPartialBoundary(
|
|||
return writeResourcesForBoundary(
|
||||
destination,
|
||||
boundary.resources,
|
||||
request.responseState,
|
||||
request.renderState,
|
||||
);
|
||||
} else {
|
||||
return true;
|
||||
|
|
@ -2397,7 +2399,8 @@ function flushPartiallyCompletedSegment(
|
|||
flushSegmentContainer(request, destination, segment);
|
||||
return writeCompletedSegmentInstruction(
|
||||
destination,
|
||||
request.responseState,
|
||||
request.resumableState,
|
||||
request.renderState,
|
||||
segmentID,
|
||||
);
|
||||
}
|
||||
|
|
@ -2421,15 +2424,15 @@ function flushCompletedQueues(
|
|||
if (enableFloat) {
|
||||
writePreamble(
|
||||
destination,
|
||||
request.resources,
|
||||
request.responseState,
|
||||
request.resumableState,
|
||||
request.renderState,
|
||||
request.allPendingTasks === 0,
|
||||
);
|
||||
}
|
||||
|
||||
flushSegment(request, destination, completedRootSegment);
|
||||
request.completedRootSegment = null;
|
||||
writeCompletedRoot(destination, request.responseState);
|
||||
writeCompletedRoot(destination, request.resumableState);
|
||||
} else {
|
||||
// We haven't flushed the root yet so we don't need to check any other branches further down
|
||||
return;
|
||||
|
|
@ -2440,7 +2443,7 @@ function flushCompletedQueues(
|
|||
}
|
||||
|
||||
if (enableFloat) {
|
||||
writeHoistables(destination, request.resources, request.responseState);
|
||||
writeHoistables(destination, request.resumableState, request.renderState);
|
||||
}
|
||||
|
||||
// We emit client rendering instructions for already emitted boundaries first.
|
||||
|
|
@ -2519,7 +2522,7 @@ function flushCompletedQueues(
|
|||
) {
|
||||
request.flushScheduled = false;
|
||||
if (enableFloat) {
|
||||
writePostamble(destination, request.responseState);
|
||||
writePostamble(destination, request.resumableState);
|
||||
}
|
||||
completeWriting(destination);
|
||||
flushBuffered(destination);
|
||||
|
|
@ -2610,6 +2613,18 @@ export function flushResources(request: Request): void {
|
|||
enqueueFlush(request);
|
||||
}
|
||||
|
||||
export function getResources(request: Request): Resources {
|
||||
return request.resources;
|
||||
export function getResumableState(request: Request): ResumableState {
|
||||
return request.resumableState;
|
||||
}
|
||||
|
||||
export type PostponedState = {
|
||||
nextSegmentId: number,
|
||||
rootFormatContext: FormatContext,
|
||||
progressiveChunkSize: number,
|
||||
resumableState: ResumableState,
|
||||
};
|
||||
|
||||
// Returns the state of a postponed request or null if nothing was postponed.
|
||||
export function getPostponedState(request: Request): null | PostponedState {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import type {TransitionStatus} from 'react-reconciler/src/ReactFiberConfig';
|
|||
|
||||
declare var $$$config: any;
|
||||
export opaque type Destination = mixed; // eslint-disable-line no-undef
|
||||
export opaque type ResponseState = mixed;
|
||||
export opaque type Resources = mixed;
|
||||
export opaque type RenderState = mixed;
|
||||
export opaque type ResumableState = mixed;
|
||||
export opaque type BoundaryResources = mixed;
|
||||
export opaque type FormatContext = mixed;
|
||||
export opaque type SuspenseBoundaryID = mixed;
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ const bundles = [
|
|||
{
|
||||
bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],
|
||||
moduleType: RENDERER,
|
||||
entry: 'react-dom/src/server/ReactDOMFizzServerBrowser.js',
|
||||
entry: 'react-dom/src/server/react-dom-server.browser.js',
|
||||
name: 'react-dom-server.browser',
|
||||
global: 'ReactDOMServer',
|
||||
minifyWithProdErrorCodes: true,
|
||||
|
|
@ -243,7 +243,7 @@ const bundles = [
|
|||
{
|
||||
bundleTypes: [NODE_DEV, NODE_PROD],
|
||||
moduleType: RENDERER,
|
||||
entry: 'react-dom/src/server/ReactDOMFizzServerNode.js',
|
||||
entry: 'react-dom/src/server/react-dom-server.node.js',
|
||||
name: 'react-dom-server.node',
|
||||
global: 'ReactDOMServer',
|
||||
minifyWithProdErrorCodes: false,
|
||||
|
|
@ -264,7 +264,7 @@ const bundles = [
|
|||
{
|
||||
bundleTypes: [NODE_DEV, NODE_PROD],
|
||||
moduleType: RENDERER,
|
||||
entry: 'react-dom/src/server/ReactDOMFizzServerEdge.js',
|
||||
entry: 'react-dom/src/server/react-dom-server.edge.js',
|
||||
name: 'react-dom-server.edge', // 'node_modules/react/*.js',
|
||||
|
||||
global: 'ReactDOMServer',
|
||||
|
|
@ -277,7 +277,7 @@ const bundles = [
|
|||
{
|
||||
bundleTypes: [BUN_DEV, BUN_PROD],
|
||||
moduleType: RENDERER,
|
||||
entry: 'react-dom/src/server/ReactDOMFizzServerBun.js',
|
||||
entry: 'react-dom/src/server/react-dom-server.bun.js',
|
||||
name: 'react-dom-server.bun', // 'node_modules/react/*.js',
|
||||
|
||||
global: 'ReactDOMServer',
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module.exports = [
|
|||
entryPoints: [
|
||||
'react-dom',
|
||||
'react-dom/unstable_testing',
|
||||
'react-dom/src/server/ReactDOMFizzServerNode.js',
|
||||
'react-dom/src/server/react-dom-server.node.js',
|
||||
'react-dom/static.node',
|
||||
'react-dom/server-rendering-stub',
|
||||
'react-dom/unstable_server-external-runtime',
|
||||
|
|
@ -27,6 +27,7 @@ module.exports = [
|
|||
'react-dom/server.node',
|
||||
'react-dom/static',
|
||||
'react-dom/static.node',
|
||||
'react-dom/src/server/react-dom-server.node',
|
||||
'react-dom/src/server/ReactDOMFizzServerNode.js', // react-dom/server.node
|
||||
'react-dom/src/server/ReactDOMFizzStaticNode.js',
|
||||
'react-server-dom-webpack',
|
||||
|
|
@ -46,10 +47,11 @@ module.exports = [
|
|||
},
|
||||
{
|
||||
shortName: 'dom-bun',
|
||||
entryPoints: ['react-dom', 'react-dom/src/server/ReactDOMFizzServerBun.js'],
|
||||
entryPoints: ['react-dom', 'react-dom/src/server/react-dom-server.bun.js'],
|
||||
paths: [
|
||||
'react-dom',
|
||||
'react-dom/server.bun',
|
||||
'react-dom/src/server/react-dom-server.bun',
|
||||
'react-dom/src/server/ReactDOMFizzServerBun.js',
|
||||
'react-dom-bindings',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
|
|
@ -62,7 +64,7 @@ module.exports = [
|
|||
entryPoints: [
|
||||
'react-dom',
|
||||
'react-dom/unstable_testing',
|
||||
'react-dom/src/server/ReactDOMFizzServerBrowser.js',
|
||||
'react-dom/src/server/react-dom-server.browser.js',
|
||||
'react-dom/static.browser',
|
||||
'react-dom/server-rendering-stub',
|
||||
'react-dom/unstable_server-external-runtime',
|
||||
|
|
@ -76,6 +78,7 @@ module.exports = [
|
|||
'react-dom/server.browser',
|
||||
'react-dom/static.browser',
|
||||
'react-dom/unstable_testing',
|
||||
'react-dom/src/server/react-dom-server.browser',
|
||||
'react-dom/src/server/ReactDOMFizzServerBrowser.js', // react-dom/server.browser
|
||||
'react-dom/src/server/ReactDOMFizzStaticBrowser.js',
|
||||
'react-server-dom-webpack',
|
||||
|
|
@ -118,7 +121,7 @@ module.exports = [
|
|||
{
|
||||
shortName: 'dom-edge-webpack',
|
||||
entryPoints: [
|
||||
'react-dom/src/server/ReactDOMFizzServerEdge.js',
|
||||
'react-dom/src/server/react-dom-server.edge.js',
|
||||
'react-dom/static.edge',
|
||||
'react-server-dom-webpack/server.edge',
|
||||
'react-server-dom-webpack/client.edge',
|
||||
|
|
@ -130,6 +133,7 @@ module.exports = [
|
|||
'react-dom/server.edge',
|
||||
'react-dom/static.edge',
|
||||
'react-dom/unstable_testing',
|
||||
'react-dom/src/server/react-dom-server.edge',
|
||||
'react-dom/src/server/ReactDOMFizzServerEdge.js', // react-dom/server.edge
|
||||
'react-dom/src/server/ReactDOMFizzStaticEdge.js',
|
||||
'react-server-dom-webpack',
|
||||
|
|
@ -160,6 +164,7 @@ module.exports = [
|
|||
'react-dom/server.node',
|
||||
'react-dom/static',
|
||||
'react-dom/static.node',
|
||||
'react-dom/src/server/react-dom-server.node',
|
||||
'react-dom/src/server/ReactDOMFizzServerNode.js', // react-dom/server.node
|
||||
'react-dom/src/server/ReactDOMFizzStaticNode.js',
|
||||
'react-server-dom-webpack',
|
||||
|
|
@ -193,6 +198,7 @@ module.exports = [
|
|||
'react-dom/server.node',
|
||||
'react-dom/static',
|
||||
'react-dom/static.node',
|
||||
'react-dom/src/server/react-dom-server.node',
|
||||
'react-dom/src/server/ReactDOMFizzServerNode.js', // react-dom/server.node
|
||||
'react-dom/src/server/ReactDOMFizzStaticNode.js',
|
||||
'react-server-dom-esm',
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user