React DOM fizz static node
一、作用
二、预渲染到节点流
备注
startFlowing()由 ReactFizzServer#startFlowing 实现enableHalt由 ReactFeatureFlags#enableHalt 提供getPostponedState()由 ReactFizzServer#getPostponedState 实现createResumableState()由 ReactFizzConfigDOM#createResumableState 实现createPrerenderRequest()由 ReactFizzServer#createPrerenderRequest 实现createRenderState()由 ReactFizzConfigDOM#createRenderState 实现createRootFormatContext()由 ReactFizzConfigDOM#createRootFormatContext 实现abort()由 ReactFizzServer#abort 实现startWork()由 ReactFizzServer#startWork 实现
function prerenderToNodeStream(
children: ReactNodeList,
options?: Options,
): Promise<StaticResult> {
return new Promise((resolve, reject) => {
const onFatalError = reject;
function onAllReady() {
const readable: Readable = new Readable({
read() {
startFlowing(request, writable);
},
});
const writable = createFakeWritableFromReadable(readable);
const result: StaticResult = enableHalt
? {
postponed: getPostponedState(request),
prelude: readable,
}
: ({
prelude: readable,
} as any);
resolve(result);
}
const resumableState = createResumableState(
options ? options.identifierPrefix : undefined,
options ? options.unstable_externalRuntimeSrc : undefined,
options ? options.bootstrapScriptContent : undefined,
options ? options.bootstrapScripts : undefined,
options ? options.bootstrapModules : undefined,
);
const request = createPrerenderRequest(
children,
resumableState,
createRenderState(
resumableState,
// nonce 与预渲染的引导脚本不兼容
undefined, // nonce is not compatible with prerendered bootstrap scripts
options ? options.unstable_externalRuntimeSrc : undefined,
options ? options.importMap : undefined,
options ? options.onHeaders : undefined,
options ? options.maxHeadersLength : undefined,
),
createRootFormatContext(options ? options.namespaceURI : undefined),
options ? options.progressiveChunkSize : undefined,
options ? options.onError : undefined,
onAllReady,
undefined,
undefined,
onFatalError,
);
if (options && options.signal) {
const signal = options.signal;
if (signal.aborted) {
abort(request, (signal as any).reason);
} else {
const listener = () => {
abort(request, (signal as any).reason);
signal.removeEventListener('abort', listener);
};
signal.addEventListener('abort', listener);
}
}
startWork(request);
});
}
三、预渲染
备注
startFlowing()由 ReactFizzServer#startFlowing 实现stopFlowing()由 ReactFizzServer#stopFlowing 实现abort()由 ReactFizzServer#abort 实现enableHalt由 ReactFeatureFlags#enableHalt 提供getPostponedState()由 ReactFizzServer#getPostponedState 实现createResumableState()由 ReactFizzConfigDOM#createResumableState 实现createPrerenderRequest()由 ReactFizzServer#createPrerenderRequest 实现createRenderState()由 ReactFizzConfigDOM#createRenderState 实现createRootFormatContext()由 ReactFizzConfigDOM#createRootFormatContext 实现startWork()由 ReactFizzServer#startWork 实现
function prerender(
children: ReactNodeList,
options?: Omit<Options, 'onHeaders'> & {
onHeaders?: (headers: Headers) => void;
},
): Promise<{
postponed: null | PostponedState;
prelude: ReadableStream;
}> {
return new Promise((resolve, reject) => {
const onFatalError = reject;
function onAllReady() {
let writable: Writable;
const stream = new ReadableStream(
{
type: 'bytes',
start: (controller): ?Promise<void> => {
writable =
createFakeWritableFromReadableStreamController(controller);
},
pull: (controller): ?Promise<void> => {
startFlowing(request, writable);
},
cancel: (reason): ?Promise<void> => {
stopFlowing(request);
abort(request, reason);
},
},
{ highWaterMark: 0 },
);
const result = enableHalt
? {
postponed: getPostponedState(request),
prelude: stream,
}
: ({
prelude: stream,
} as any);
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,
options ? options.bootstrapScriptContent : undefined,
options ? options.bootstrapScripts : undefined,
options ? options.bootstrapModules : undefined,
);
const request = createPrerenderRequest(
children,
resources,
createRenderState(
resources,
// 预渲染到节点流
undefined, // nonce is not compatible with prerendered bootstrap scripts
options ? options.unstable_externalRuntimeSrc : undefined,
options ? options.importMap : undefined,
onHeadersImpl,
options ? options.maxHeadersLength : undefined,
),
createRootFormatContext(options ? options.namespaceURI : undefined),
options ? options.progressiveChunkSize : undefined,
options ? options.onError : undefined,
onAllReady,
undefined,
undefined,
onFatalError,
);
if (options && options.signal) {
const signal = options.signal;
if (signal.aborted) {
abort(request, (signal as any).reason);
} else {
const listener = () => {
abort(request, (signal as any).reason);
signal.removeEventListener('abort', listener);
};
signal.addEventListener('abort', listener);
}
}
startWork(request);
});
}
四、恢复并预渲染到 Node 流
备注
startFlowing()由 ReactFizzServer#startFlowing 实现getPostponedState()由 ReactFizzServer#getPostponedState 实现resumeAndPrerenderRequest()由 ReactFizzServer#resumeAndPrerenderRequest 实现resumeRenderState()由 ReactFizzServer#resumeAndPrerenderRequest 实现abort()由 ReactFizzServer#abort 实现startWork()由 ReactFizzServer#startWork 实现
function resumeAndPrerenderToNodeStream(
children: ReactNodeList,
postponedState: PostponedState,
options?: Omit<ResumeOptions, 'nonce'>,
): Promise<StaticResult> {
return new Promise((resolve, reject) => {
const onFatalError = reject;
function onAllReady() {
const readable: Readable = new Readable({
read() {
startFlowing(request, writable);
},
});
const writable = createFakeWritableFromReadable(readable);
const result = {
postponed: getPostponedState(request),
prelude: readable,
};
resolve(result);
}
const request = resumeAndPrerenderRequest(
children,
postponedState,
resumeRenderState(postponedState.resumableState, undefined),
options ? options.onError : undefined,
onAllReady,
undefined,
undefined,
onFatalError,
);
if (options && options.signal) {
const signal = options.signal;
if (signal.aborted) {
abort(request, (signal as any).reason);
} else {
const listener = () => {
abort(request, (signal as any).reason);
signal.removeEventListener('abort', listener);
};
signal.addEventListener('abort', listener);
}
}
startWork(request);
});
}
五、恢复并预渲染
备注
startFlowing()由 ReactFizzServer#startFlowing 实现stopFlowing()由 ReactFizzServer#stopFlowing 实现abort()由 ReactFizzServer#abort 实现getPostponedState()由 ReactFizzServer#getPostponedState 实现resumeAndPrerenderRequest()由 ReactFizzServer#resumeAndPrerenderRequest 实现resumeRenderState()由 ReactFizzConfigDOM#resumeRenderState 实现startWork()由 ReactFizzServer#startWork 实现
function resumeAndPrerender(
children: ReactNodeList,
postponedState: PostponedState,
options?: Omit<ResumeOptions, 'nonce'>,
): Promise<{
postponed: null | PostponedState;
prelude: ReadableStream;
}> {
return new Promise((resolve, reject) => {
const onFatalError = reject;
function onAllReady() {
let writable: Writable;
const stream = new ReadableStream(
{
type: 'bytes',
start: (controller): ?Promise<void> => {
writable =
createFakeWritableFromReadableStreamController(controller);
},
pull: (controller): ?Promise<void> => {
startFlowing(request, writable);
},
cancel: (reason): ?Promise<void> => {
stopFlowing(request);
abort(request, reason);
},
},
{ highWaterMark: 0 },
);
const result = {
postponed: getPostponedState(request),
prelude: stream,
};
resolve(result);
}
const request = resumeAndPrerenderRequest(
children,
postponedState,
resumeRenderState(postponedState.resumableState, undefined),
options ? options.onError : undefined,
onAllReady,
undefined,
undefined,
onFatalError,
);
if (options && options.signal) {
const signal = options.signal;
if (signal.aborted) {
abort(request, (signal as any).reason);
} else {
const listener = () => {
abort(request, (signal as any).reason);
signal.removeEventListener('abort', listener);
};
signal.addEventListener('abort', listener);
}
}
startWork(request);
});
}
六、工具
1. 确保正确的同构 React 版本
在头部执行了检测当前 React 版本是否正确的全局副作用。
ensureCorrectIsomorphicReactVersion();
2. 从可读流控制器创建假可写对象
备注
textEncoder()由 ReactServerStreamConfigNode#textEncoder 实现
function createFakeWritableFromReadableStreamController(
controller: ReadableStreamController,
): Writable {
// The current host config expects a Writable so we create
// a fake writable for now to push into the Readable.
return {
write(chunk: string | Uint8Array) {
if (typeof chunk === 'string') {
chunk = textEncoder.encode(chunk);
}
controller.enqueue(chunk);
// in web streams there is no backpressure so we can alwas write more
// 在网络流中没有背压,所以我们总是可以写入更多
return true;
},
end() {
controller.close();
},
destroy(error) {
if (typeof controller.error === 'function') {
controller.error(error);
} else {
controller.close();
}
},
} as any;
}
3. 从可读创建伪可写
function createFakeWritableFromReadable(readable: any): Writable {
// The current host config expects a Writable so we create
// a fake writable for now to push into the Readable.
// 当前宿主配置需要一个可写流,所以我们暂时创建一个假的可写流来推入可读流。
return {
write(chunk) {
return readable.push(chunk);
},
end() {
readable.push(null);
},
destroy(error) {
readable.destroy(error);
},
} as any;
}
七、类型
1. 一次性选项
// 一次性选项
type NonceOption =
| string
| {
script?: string;
style?: string;
};
// 选项
type Options = {
identifierPrefix?: string;
namespaceURI?: string;
bootstrapScriptContent?: string;
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>;
bootstrapModules?: Array<string | BootstrapScriptDescriptor>;
progressiveChunkSize?: number;
signal?: AbortSignal;
onError?: (error: mixed, errorInfo: ErrorInfo) => ?string;
unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor;
importMap?: ImportMap;
onHeaders?: (headers: HeadersDescriptor) => void;
maxHeadersLength?: number;
};
// 静态结果
type StaticResult = {
postponed: null | PostponedState;
prelude: Readable;
};
2. 恢复选项
type ResumeOptions = {
nonce?: NonceOption;
signal?: AbortSignal;
onError?: (error: mixed, errorInfo: ErrorInfo) => ?string;
};
八、转导
- 从 ReactVersion 转导了
ReactVersion as version