@bleedingdev/modern-js-runtime 3.9.0-ultramodern.3 → 3.9.0-ultramodern.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/code.js +3 -1
- package/dist/cjs/cli/ssr/index.js +2 -74
- package/dist/cjs/core/browser/hydrate.js +6 -1
- package/dist/cjs/core/context/index.js +4 -43
- package/dist/cjs/core/context/public.js +4 -7
- package/dist/cjs/core/context/runtime.js +17 -5
- package/dist/cjs/core/react/wrapper.js +22 -65
- package/dist/cjs/core/server/helmet.js +5 -4
- package/dist/cjs/core/server/requestResponse.js +4 -4
- package/dist/cjs/core/server/routerCleanup.js +2 -2
- package/dist/cjs/core/server/shared.js +171 -4
- package/dist/cjs/core/server/stream/afterTemplate.js +21 -16
- package/dist/cjs/core/server/stream/beforeTemplate.js +34 -25
- package/dist/cjs/core/server/stream/beforeTemplate.worker.js +28 -21
- package/dist/cjs/core/server/stream/createReadableStream.js +208 -123
- package/dist/cjs/core/server/stream/createReadableStream.worker.js +159 -90
- package/dist/cjs/core/server/stream/deferredScript.js +3 -3
- package/dist/cjs/core/server/stream/shared.js +2 -2
- package/dist/cjs/core/server/string/index.js +100 -64
- package/dist/cjs/core/server/string/loadable.js +34 -19
- package/dist/cjs/core/server/string/ssrData.js +5 -12
- package/dist/cjs/core/server/utils.js +1 -2
- package/dist/cjs/exports/head.js +7 -14
- package/dist/cjs/router/runtime/PrefetchLink.js +67 -123
- package/dist/cjs/router/runtime/hooks.js +13 -2
- package/dist/cjs/router/runtime/internal.js +7 -45
- package/dist/cjs/router/runtime/plugin.js +2 -8
- package/dist/cjs/router/runtime/plugin.node.js +2 -30
- package/dist/cjs/router/runtime/redirect.js +1 -1
- package/dist/esm/cli/code.mjs +3 -1
- package/dist/esm/cli/ssr/index.mjs +3 -72
- package/dist/esm/core/browser/hydrate.mjs +7 -2
- package/dist/esm/core/context/index.mjs +2 -5
- package/dist/esm/core/context/public.mjs +1 -5
- package/dist/esm/core/context/runtime.mjs +13 -4
- package/dist/esm/core/react/wrapper.mjs +21 -67
- package/dist/esm/core/server/helmet.mjs +5 -4
- package/dist/esm/core/server/requestResponse.mjs +3 -3
- package/dist/esm/core/server/routerCleanup.mjs +1 -1
- package/dist/esm/core/server/shared.mjs +153 -1
- package/dist/esm/core/server/stream/afterTemplate.mjs +23 -18
- package/dist/esm/core/server/stream/beforeTemplate.mjs +37 -28
- package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +31 -24
- package/dist/esm/core/server/stream/createReadableStream.mjs +207 -122
- package/dist/esm/core/server/stream/createReadableStream.worker.mjs +149 -90
- package/dist/esm/core/server/stream/deferredScript.mjs +3 -3
- package/dist/esm/core/server/stream/shared.mjs +2 -2
- package/dist/esm/core/server/string/index.mjs +104 -68
- package/dist/esm/core/server/string/loadable.mjs +34 -19
- package/dist/esm/core/server/string/ssrData.mjs +5 -12
- package/dist/esm/core/server/utils.mjs +1 -2
- package/dist/esm/exports/head.mjs +7 -14
- package/dist/esm/router/runtime/PrefetchLink.mjs +67 -123
- package/dist/esm/router/runtime/hooks.mjs +9 -1
- package/dist/esm/router/runtime/internal.mjs +2 -33
- package/dist/esm/router/runtime/plugin.mjs +1 -7
- package/dist/esm/router/runtime/plugin.node.mjs +1 -29
- package/dist/esm/router/runtime/redirect.mjs +1 -1
- package/dist/esm-node/cli/code.mjs +3 -1
- package/dist/esm-node/cli/ssr/index.mjs +3 -72
- package/dist/esm-node/core/browser/hydrate.mjs +7 -2
- package/dist/esm-node/core/context/index.mjs +2 -5
- package/dist/esm-node/core/context/public.mjs +1 -5
- package/dist/esm-node/core/context/runtime.mjs +13 -4
- package/dist/esm-node/core/react/wrapper.mjs +21 -67
- package/dist/esm-node/core/server/helmet.mjs +5 -4
- package/dist/esm-node/core/server/requestResponse.mjs +3 -3
- package/dist/esm-node/core/server/routerCleanup.mjs +1 -1
- package/dist/esm-node/core/server/shared.mjs +153 -1
- package/dist/esm-node/core/server/stream/afterTemplate.mjs +23 -18
- package/dist/esm-node/core/server/stream/beforeTemplate.mjs +37 -28
- package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +31 -24
- package/dist/esm-node/core/server/stream/createReadableStream.mjs +207 -122
- package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +149 -90
- package/dist/esm-node/core/server/stream/deferredScript.mjs +3 -3
- package/dist/esm-node/core/server/stream/shared.mjs +2 -2
- package/dist/esm-node/core/server/string/index.mjs +104 -68
- package/dist/esm-node/core/server/string/loadable.mjs +34 -19
- package/dist/esm-node/core/server/string/ssrData.mjs +5 -12
- package/dist/esm-node/core/server/utils.mjs +1 -2
- package/dist/esm-node/exports/head.mjs +7 -14
- package/dist/esm-node/router/runtime/PrefetchLink.mjs +67 -123
- package/dist/esm-node/router/runtime/hooks.mjs +9 -1
- package/dist/esm-node/router/runtime/internal.mjs +2 -33
- package/dist/esm-node/router/runtime/plugin.mjs +1 -7
- package/dist/esm-node/router/runtime/plugin.node.mjs +1 -29
- package/dist/esm-node/router/runtime/redirect.mjs +1 -1
- package/dist/types/cli/ssr/index.d.ts +0 -3
- package/dist/types/core/context/index.d.ts +4 -6
- package/dist/types/core/context/public.d.ts +1 -23
- package/dist/types/core/context/runtime.d.ts +26 -2
- package/dist/types/core/react/wrapper.d.ts +6 -0
- package/dist/types/core/server/helmet.d.ts +4 -5
- package/dist/types/core/server/shared.d.ts +23 -0
- package/dist/types/core/server/stream/afterTemplate.d.ts +2 -1
- package/dist/types/core/server/stream/beforeTemplate.d.ts +4 -1
- package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +4 -1
- package/dist/types/core/server/stream/shared.d.ts +1 -1
- package/dist/types/core/server/string/loadable.d.ts +6 -3
- package/dist/types/core/server/string/ssrData.d.ts +2 -1
- package/dist/types/core/server/string/types.d.ts +1 -5
- package/dist/types/exports/head.d.ts +2 -2
- package/dist/types/router/runtime/PrefetchLink.d.ts +27 -2
- package/dist/types/router/runtime/hooks.d.ts +19 -2
- package/dist/types/router/runtime/internal.d.ts +4 -21
- package/dist/types/router/runtime/types.d.ts +2 -43
- package/package.json +9 -38
- package/rstest.config.mts +32 -2
- package/dist/cjs/boundary-debugger/index.js +0 -317
- package/dist/cjs/core/context/extensions.js +0 -74
- package/dist/cjs/core/context/helmetContext.js +0 -54
- package/dist/cjs/core/server/federatedCss.js +0 -58
- package/dist/cjs/core/server/scriptOrder.js +0 -140
- package/dist/cjs/module-federation/consume-surface.js +0 -199
- package/dist/cjs/module-federation/distributed-ssr.js +0 -135
- package/dist/cjs/module-federation/index.js +0 -316
- package/dist/cjs/module-federation/last-known-good.js +0 -157
- package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +0 -129
- package/dist/cjs/module-federation/surface-resolution-types.js +0 -61
- package/dist/cjs/router/runtime/lifecycle.js +0 -167
- package/dist/cjs/router/runtime/provider.js +0 -153
- package/dist/esm/boundary-debugger/index.mjs +0 -277
- package/dist/esm/core/context/extensions.mjs +0 -33
- package/dist/esm/core/context/helmetContext.mjs +0 -13
- package/dist/esm/core/server/federatedCss.mjs +0 -20
- package/dist/esm/core/server/scriptOrder.mjs +0 -90
- package/dist/esm/module-federation/consume-surface.mjs +0 -158
- package/dist/esm/module-federation/distributed-ssr.mjs +0 -82
- package/dist/esm/module-federation/index.mjs +0 -115
- package/dist/esm/module-federation/last-known-good.mjs +0 -113
- package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +0 -89
- package/dist/esm/module-federation/surface-resolution-types.mjs +0 -8
- package/dist/esm/router/runtime/lifecycle.mjs +0 -105
- package/dist/esm/router/runtime/provider.mjs +0 -100
- package/dist/esm-node/boundary-debugger/index.mjs +0 -278
- package/dist/esm-node/core/context/extensions.mjs +0 -34
- package/dist/esm-node/core/context/helmetContext.mjs +0 -14
- package/dist/esm-node/core/server/federatedCss.mjs +0 -21
- package/dist/esm-node/core/server/scriptOrder.mjs +0 -91
- package/dist/esm-node/module-federation/consume-surface.mjs +0 -159
- package/dist/esm-node/module-federation/distributed-ssr.mjs +0 -83
- package/dist/esm-node/module-federation/index.mjs +0 -116
- package/dist/esm-node/module-federation/last-known-good.mjs +0 -114
- package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +0 -90
- package/dist/esm-node/module-federation/surface-resolution-types.mjs +0 -9
- package/dist/esm-node/router/runtime/lifecycle.mjs +0 -106
- package/dist/esm-node/router/runtime/provider.mjs +0 -101
- package/dist/types/boundary-debugger/index.d.ts +0 -28
- package/dist/types/core/context/extensions.d.ts +0 -35
- package/dist/types/core/context/helmetContext.d.ts +0 -10
- package/dist/types/core/server/federatedCss.d.ts +0 -5
- package/dist/types/core/server/scriptOrder.d.ts +0 -25
- package/dist/types/module-federation/consume-surface.d.ts +0 -104
- package/dist/types/module-federation/distributed-ssr.d.ts +0 -61
- package/dist/types/module-federation/index.d.ts +0 -71
- package/dist/types/module-federation/last-known-good.d.ts +0 -52
- package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +0 -25
- package/dist/types/module-federation/surface-resolution-types.d.ts +0 -23
- package/dist/types/router/runtime/lifecycle.d.ts +0 -27
- package/dist/types/router/runtime/provider.d.ts +0 -78
|
@@ -1,147 +1,232 @@
|
|
|
1
1
|
import { storage } from "@modern-js/runtime-utils/node";
|
|
2
2
|
import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
|
|
3
|
-
import { PassThrough, Readable, Transform } from "stream";
|
|
3
|
+
import { PassThrough, Readable, Transform, finished, pipeline } from "stream";
|
|
4
4
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
|
|
5
5
|
import { RenderLevel } from "../../constants.mjs";
|
|
6
|
-
import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
|
|
6
|
+
import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "../../context/index.mjs";
|
|
7
7
|
import { getMonitors } from "../../context/monitors/index.mjs";
|
|
8
|
+
import { wrapRuntimeComponentResolver } from "../../react/wrapper.mjs";
|
|
8
9
|
import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
|
|
10
|
+
import { createSSRRenderLifecycle, createSSRStreamErrorReporter, observeSSRStream, orderSSRStreamTransforms } from "../shared.mjs";
|
|
9
11
|
import { enqueueFromEntries } from "./deferredScript.mjs";
|
|
10
12
|
import { ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
|
|
11
13
|
import { getTemplates } from "./template.mjs";
|
|
12
|
-
import * as __rspack_external__modern_js_runtime_extensions_node_f016b1ee from "@modern-js/runtime-extensions/node";
|
|
13
|
-
const defaultExtender = {
|
|
14
|
-
modifyRootElement: (rootElement)=>rootElement,
|
|
15
|
-
getStyleTags: ()=>'',
|
|
16
|
-
processStream: (stream)=>stream
|
|
17
|
-
};
|
|
18
14
|
const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
19
15
|
const { renderToPipeableStream } = await import("react-dom/server");
|
|
20
|
-
const { runtimeContext, htmlTemplate, config, ssrConfig, entryName,
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
const { runtimeContext, htmlTemplate, config, ssrConfig, entryName, resource } = options;
|
|
17
|
+
const hooks = getGlobalInternalRuntimeContext().hooks;
|
|
18
|
+
const isRsc = true === getGlobalEnableRsc();
|
|
19
|
+
const extenders = hooks.extendStreamSSR.call({
|
|
20
|
+
runtimeContext,
|
|
21
|
+
request,
|
|
22
|
+
resource,
|
|
23
|
+
config,
|
|
24
|
+
platform: 'node',
|
|
25
|
+
mode: 'stream',
|
|
26
|
+
isRsc,
|
|
27
|
+
terminalMarker: ESCAPED_SHELL_STREAM_END_MARK
|
|
28
|
+
}) || [];
|
|
29
|
+
const lifecycle = createSSRRenderLifecycle(extenders);
|
|
30
|
+
const reportError = createSSRStreamErrorReporter(options.onError);
|
|
23
31
|
const forceStream2String = Boolean(process.env.MODERN_JS_STREAM_TO_STRING);
|
|
24
32
|
const { onReady } = resolveStreamingMode(request, forceStream2String);
|
|
25
|
-
|
|
26
|
-
const hooks = internalRuntimeContext.hooks;
|
|
27
|
-
const extenders = hooks.extendStreamSSR.call() || [];
|
|
28
|
-
if (0 === extenders.length) extenders.push(defaultExtender);
|
|
29
|
-
extenders.forEach((extender)=>{
|
|
30
|
-
if (extender.init) extender.init({
|
|
31
|
-
rootElement,
|
|
32
|
-
forceStream2String
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
let processedRootElement = rootElement;
|
|
36
|
-
extenders.forEach((extender)=>{
|
|
37
|
-
if (extender.modifyRootElement) processedRootElement = extender.modifyRootElement(processedRootElement);
|
|
38
|
-
});
|
|
39
|
-
const chunkVec = [];
|
|
33
|
+
let renderLevel = RenderLevel.SERVER_RENDER;
|
|
40
34
|
let hasStartedPipe = false;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
let failed = false;
|
|
36
|
+
let reactStream;
|
|
37
|
+
const ownedStreams = new Set();
|
|
38
|
+
const streamCompletions = [];
|
|
39
|
+
let teardown;
|
|
40
|
+
return new Promise((resolve, reject)=>{
|
|
41
|
+
const destroyOwnedStreams = (reason)=>{
|
|
42
|
+
if (teardown) return teardown;
|
|
43
|
+
const error = void 0 === reason ? void 0 : reason instanceof Error ? reason : new Error(String(reason));
|
|
44
|
+
for (const stream of ownedStreams){
|
|
45
|
+
const destroyable = stream;
|
|
46
|
+
destroyable.destroy?.(error);
|
|
47
|
+
}
|
|
48
|
+
teardown = Promise.all(streamCompletions).then((errors)=>{
|
|
49
|
+
const cleanupError = errors.find((value)=>void 0 !== value && value !== error && 'ERR_STREAM_PREMATURE_CLOSE' !== value.code);
|
|
50
|
+
if (cleanupError) throw cleanupError;
|
|
51
|
+
});
|
|
52
|
+
return teardown;
|
|
53
|
+
};
|
|
54
|
+
const abortReact = (reason)=>reactStream?.abort(reason);
|
|
55
|
+
const fail = (error)=>{
|
|
56
|
+
if (failed) return;
|
|
57
|
+
failed = true;
|
|
58
|
+
request.signal.removeEventListener('abort', onStartupAbort);
|
|
59
|
+
if (request.signal.aborted) lifecycle.finish({
|
|
60
|
+
status: 'cancelled',
|
|
61
|
+
reason: request.signal.reason
|
|
62
|
+
});
|
|
63
|
+
else {
|
|
64
|
+
lifecycle.finish({
|
|
65
|
+
status: 'error',
|
|
66
|
+
error
|
|
53
67
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
68
|
+
reportError(error);
|
|
69
|
+
}
|
|
70
|
+
abortReact(error);
|
|
71
|
+
destroyOwnedStreams(error).then(()=>reject(error), ()=>reject(error));
|
|
72
|
+
};
|
|
73
|
+
const own = (stream)=>{
|
|
74
|
+
if (!ownedStreams.has(stream)) {
|
|
75
|
+
ownedStreams.add(stream);
|
|
76
|
+
streamCompletions.push(new Promise((done)=>{
|
|
77
|
+
finished(stream, (error)=>done(error ?? void 0));
|
|
78
|
+
}));
|
|
79
|
+
stream.on('error', fail);
|
|
80
|
+
}
|
|
81
|
+
return stream;
|
|
82
|
+
};
|
|
83
|
+
const onStartupAbort = ()=>fail(request.signal.reason);
|
|
84
|
+
const deliver = (source)=>{
|
|
85
|
+
const stream = observeSSRStream(source, {
|
|
86
|
+
lifecycle,
|
|
87
|
+
signal: request.signal,
|
|
88
|
+
async onError (error) {
|
|
89
|
+
failed = true;
|
|
90
|
+
abortReact(error);
|
|
91
|
+
await destroyOwnedStreams(error);
|
|
92
|
+
reportError(error);
|
|
93
|
+
},
|
|
94
|
+
onCancel (reason) {
|
|
95
|
+
failed = true;
|
|
96
|
+
const cleanup = destroyOwnedStreams();
|
|
97
|
+
abortReact(reason);
|
|
98
|
+
return cleanup;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
request.signal.removeEventListener('abort', onStartupAbort);
|
|
102
|
+
resolve(stream);
|
|
103
|
+
};
|
|
104
|
+
const templateOptions = ()=>({
|
|
105
|
+
request,
|
|
106
|
+
ssrConfig,
|
|
107
|
+
renderLevel,
|
|
108
|
+
runtimeContext,
|
|
109
|
+
config,
|
|
110
|
+
entryName,
|
|
111
|
+
lifecycle
|
|
112
|
+
});
|
|
113
|
+
const startOutput = async ()=>{
|
|
114
|
+
if (hasStartedPipe || failed) return;
|
|
115
|
+
hasStartedPipe = true;
|
|
116
|
+
const styledComponentsStyleTags = extenders.map((extender)=>extender.getStyleTags?.() ?? '').join('');
|
|
117
|
+
options[onReady]?.();
|
|
118
|
+
const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
|
|
119
|
+
...templateOptions(),
|
|
120
|
+
styledComponentsStyleTags
|
|
121
|
+
});
|
|
122
|
+
if (failed) return;
|
|
123
|
+
const chunks = [];
|
|
124
|
+
const marker = Buffer.from(ESCAPED_SHELL_STREAM_END_MARK);
|
|
125
|
+
const pendingScripts = [];
|
|
126
|
+
let shellChunkStatus = ShellChunkStatus.START;
|
|
127
|
+
const emitShell = (destination, buffered, markerIndex)=>{
|
|
128
|
+
const beforeMark = lifecycle.completedBody(buffered.subarray(0, markerIndex).toString('utf8'), 'shell');
|
|
129
|
+
const completedShellBefore = createReplaceHelemt(getHelmetData(extenders))(shellBefore);
|
|
130
|
+
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
131
|
+
chunks.length = 0;
|
|
132
|
+
destination.push(`${completedShellBefore}${beforeMark}${shellAfter}`);
|
|
133
|
+
const afterMark = buffered.subarray(markerIndex + marker.length);
|
|
134
|
+
if (afterMark.length > 0) destination.push(afterMark);
|
|
135
|
+
for (const script of pendingScripts)destination.push(script);
|
|
136
|
+
pendingScripts.length = 0;
|
|
137
|
+
};
|
|
138
|
+
const body = new Transform({
|
|
139
|
+
transform (chunk, _encoding, callback) {
|
|
140
|
+
try {
|
|
141
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) this.push(chunk);
|
|
142
|
+
else {
|
|
143
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
144
|
+
const buffered = Buffer.concat(chunks);
|
|
145
|
+
const markerIndex = buffered.indexOf(marker);
|
|
146
|
+
if (-1 !== markerIndex) emitShell(this, buffered, markerIndex);
|
|
88
147
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (extender.processStream) processedStream = extender.processStream(processedStream);
|
|
96
|
-
});
|
|
97
|
-
__rspack_external__modern_js_runtime_extensions_node_f016b1ee.pipeNodeHeadStream({
|
|
98
|
-
source: processedStream,
|
|
99
|
-
destination: body,
|
|
100
|
-
context: runtimeContext,
|
|
101
|
-
terminalMarker: ESCAPED_SHELL_STREAM_END_MARK,
|
|
102
|
-
onError: reportError
|
|
103
|
-
});
|
|
104
|
-
reactStreamingPipe(passThrough);
|
|
148
|
+
callback();
|
|
149
|
+
} catch (error) {
|
|
150
|
+
callback(error instanceof Error ? error : new Error(String(error)));
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
flush (callback) {
|
|
105
154
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (entries.length > 0) {
|
|
110
|
-
const enqueueScript = (s)=>{
|
|
111
|
-
if (shellChunkStatus === ShellChunkStatus.FINISH) body.write(s);
|
|
112
|
-
else pendingScripts.push(s);
|
|
113
|
-
};
|
|
114
|
-
enqueueFromEntries(entries, config.nonce, (s)=>enqueueScript(s));
|
|
155
|
+
if (shellChunkStatus !== ShellChunkStatus.FINISH) {
|
|
156
|
+
const buffered = Buffer.concat(chunks);
|
|
157
|
+
emitShell(this, buffered, buffered.length);
|
|
115
158
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
159
|
+
callback();
|
|
160
|
+
} catch (error) {
|
|
161
|
+
callback(error instanceof Error ? error : new Error(String(error)));
|
|
119
162
|
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
own(body);
|
|
166
|
+
const passThrough = new PassThrough();
|
|
167
|
+
let processedStream = own(passThrough);
|
|
168
|
+
for (const extender of orderSSRStreamTransforms(extenders))if (extender.processStream) processedStream = own(extender.processStream(processedStream));
|
|
169
|
+
pipeline(processedStream, body, (error)=>{
|
|
170
|
+
if (null != error && !failed) fail(error);
|
|
171
|
+
});
|
|
172
|
+
deliver(Readable.toWeb(body));
|
|
173
|
+
reactStream.pipe(passThrough);
|
|
174
|
+
try {
|
|
175
|
+
const activeDeferreds = storage.useContext?.()?.activeDeferreds;
|
|
176
|
+
const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
|
|
177
|
+
enqueueFromEntries(entries, config.nonce, (script)=>{
|
|
178
|
+
if (failed || body.destroyed || body.writableEnded) return;
|
|
179
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) body.write(script);
|
|
180
|
+
else pendingScripts.push(script);
|
|
120
181
|
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
__rspack_external__modern_js_runtime_extensions_node_f016b1ee.abortHeadRender(runtimeContext);
|
|
124
|
-
renderLevel = RenderLevel.CLIENT_RENDER;
|
|
125
|
-
getTemplates(htmlTemplate, {
|
|
126
|
-
request,
|
|
127
|
-
ssrConfig,
|
|
128
|
-
renderLevel,
|
|
129
|
-
runtimeContext,
|
|
130
|
-
entryName,
|
|
131
|
-
config,
|
|
132
|
-
moduleFederationCssAssets
|
|
133
|
-
}).then(({ shellAfter, shellBefore })=>{
|
|
134
|
-
const fallbackHtml = `${shellBefore}${shellAfter}`;
|
|
135
|
-
const readableStream = getReadableStreamFromString(fallbackHtml);
|
|
136
|
-
resolve(readableStream);
|
|
137
|
-
options?.onShellError?.(error);
|
|
138
|
-
});
|
|
139
|
-
},
|
|
140
|
-
onError (error) {
|
|
141
|
-
renderLevel = RenderLevel.CLIENT_RENDER;
|
|
142
|
-
reportError(error);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
getMonitors().error("cannot inject router data script", error);
|
|
143
184
|
}
|
|
185
|
+
};
|
|
186
|
+
const renderFallback = async (error)=>{
|
|
187
|
+
if (failed || hasStartedPipe) return;
|
|
188
|
+
lifecycle.finish({
|
|
189
|
+
status: 'fallback',
|
|
190
|
+
error
|
|
191
|
+
});
|
|
192
|
+
renderLevel = RenderLevel.CLIENT_RENDER;
|
|
193
|
+
const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
|
|
194
|
+
...templateOptions(),
|
|
195
|
+
helmetData: getHelmetData(extenders)
|
|
196
|
+
});
|
|
197
|
+
if (failed) return;
|
|
198
|
+
options.onShellError?.(error);
|
|
199
|
+
deliver(getReadableStreamFromString(`${shellBefore}${shellAfter}`));
|
|
200
|
+
};
|
|
201
|
+
request.signal.addEventListener('abort', onStartupAbort, {
|
|
202
|
+
once: true
|
|
144
203
|
});
|
|
204
|
+
try {
|
|
205
|
+
request.signal.throwIfAborted();
|
|
206
|
+
for (const extender of extenders)extender.init?.({
|
|
207
|
+
rootElement,
|
|
208
|
+
forceStream2String
|
|
209
|
+
});
|
|
210
|
+
let processedRootElement = isRsc && false === runtimeContext.isBrowser ? wrapRuntimeComponentResolver(rootElement, hooks) : rootElement;
|
|
211
|
+
for (const extender of extenders)processedRootElement = extender.modifyRootElement?.(processedRootElement) ?? processedRootElement;
|
|
212
|
+
lifecycle.beforeReact();
|
|
213
|
+
reactStream = renderToPipeableStream(processedRootElement, {
|
|
214
|
+
nonce: config.nonce,
|
|
215
|
+
identifierPrefix: SSR_HYDRATION_ID_PREFIX,
|
|
216
|
+
[onReady] () {
|
|
217
|
+
startOutput().catch(fail);
|
|
218
|
+
},
|
|
219
|
+
onShellError (error) {
|
|
220
|
+
renderFallback(error).catch(fail);
|
|
221
|
+
},
|
|
222
|
+
onError (error) {
|
|
223
|
+
renderLevel = RenderLevel.CLIENT_RENDER;
|
|
224
|
+
if (!request.signal.aborted && !failed) reportError(error);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
} catch (error) {
|
|
228
|
+
fail(error);
|
|
229
|
+
}
|
|
145
230
|
});
|
|
146
231
|
};
|
|
147
232
|
export { createReadableStreamFromElement };
|
|
@@ -1,121 +1,180 @@
|
|
|
1
1
|
import { renderSSRStream } from "@modern-js/render/ssr";
|
|
2
2
|
import { storage } from "@modern-js/runtime-utils/node";
|
|
3
|
+
import react from "react";
|
|
3
4
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
|
|
4
5
|
import { RenderLevel } from "../../constants.mjs";
|
|
6
|
+
import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "../../context/index.mjs";
|
|
7
|
+
import { wrapRuntimeComponentResolver } from "../../react/wrapper.mjs";
|
|
5
8
|
import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
|
|
9
|
+
import { createSSRRenderLifecycle, createSSRStreamErrorReporter, observeSSRStream, orderSSRStreamTransforms } from "../shared.mjs";
|
|
6
10
|
import { enqueueFromEntries } from "./deferredScript.mjs";
|
|
7
|
-
import { ShellChunkStatus,
|
|
11
|
+
import { ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
|
|
8
12
|
import { getTemplates } from "./template.mjs";
|
|
9
|
-
import * as __rspack_external__modern_js_runtime_extensions_ce611631 from "@modern-js/runtime-extensions";
|
|
10
13
|
const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, resource, rscManifest, rscRoot } = options;
|
|
15
|
+
const hooks = getGlobalInternalRuntimeContext().hooks;
|
|
16
|
+
const isRsc = true === getGlobalEnableRsc();
|
|
17
|
+
const extenders = hooks.extendStreamSSR.call({
|
|
18
|
+
runtimeContext,
|
|
19
|
+
request,
|
|
20
|
+
resource,
|
|
21
|
+
config,
|
|
22
|
+
platform: 'web',
|
|
23
|
+
mode: 'stream',
|
|
24
|
+
isRsc,
|
|
25
|
+
terminalMarker: ESCAPED_SHELL_STREAM_END_MARK
|
|
26
|
+
}) || [];
|
|
27
|
+
const lifecycle = createSSRRenderLifecycle(extenders);
|
|
28
|
+
const reportOnce = createSSRStreamErrorReporter(options.onError);
|
|
29
|
+
const reportError = (error)=>{
|
|
30
|
+
if (!request.signal.aborted && lifecycle.terminal?.status !== 'cancelled') reportOnce(error);
|
|
31
|
+
};
|
|
32
|
+
const forceStream2String = Boolean("u" > typeof process && process.env?.MODERN_JS_STREAM_TO_STRING);
|
|
33
|
+
let pendingSource;
|
|
34
|
+
let bodyOpen = true;
|
|
35
|
+
let bodyPipe;
|
|
36
|
+
const templateOptions = {
|
|
17
37
|
runtimeContext,
|
|
18
38
|
ssrConfig,
|
|
19
39
|
request,
|
|
20
40
|
config,
|
|
21
41
|
entryName,
|
|
22
|
-
|
|
23
|
-
}
|
|
42
|
+
lifecycle
|
|
43
|
+
};
|
|
24
44
|
try {
|
|
45
|
+
request.signal.throwIfAborted();
|
|
46
|
+
for (const extender of extenders)extender.init?.({
|
|
47
|
+
rootElement,
|
|
48
|
+
forceStream2String
|
|
49
|
+
});
|
|
25
50
|
const readableOriginal = await renderSSRStream(rootElement, {
|
|
26
51
|
request,
|
|
52
|
+
signal: request.signal,
|
|
27
53
|
nonce: config.nonce,
|
|
28
54
|
rscManifest,
|
|
29
55
|
rscRoot: rscRoot,
|
|
30
56
|
routes: runtimeContext.routes,
|
|
31
|
-
onError
|
|
32
|
-
|
|
57
|
+
onError: reportError,
|
|
58
|
+
wrapHtmlRoot (root) {
|
|
59
|
+
let element = react.isValidElement(root) ? root : react.createElement(react.Fragment, null, root);
|
|
60
|
+
if (isRsc && false === runtimeContext.isBrowser) element = wrapRuntimeComponentResolver(element, hooks);
|
|
61
|
+
for (const extender of extenders)element = extender.modifyRootElement?.(element) ?? element;
|
|
62
|
+
lifecycle.beforeReact();
|
|
63
|
+
return element;
|
|
33
64
|
}
|
|
34
65
|
});
|
|
66
|
+
pendingSource = readableOriginal;
|
|
35
67
|
options.onShellReady?.();
|
|
36
|
-
readableOriginal.allReady.then(()=>
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
const forceStreamToString = Boolean("u" > typeof process && process.env?.MODERN_JS_STREAM_TO_STRING);
|
|
40
|
-
const { waitForAllReady } = resolveStreamingMode(request, forceStreamToString);
|
|
68
|
+
readableOriginal.allReady.then(()=>options.onAllReady?.()).catch(reportError);
|
|
69
|
+
const { waitForAllReady } = resolveStreamingMode(request, forceStream2String);
|
|
41
70
|
if (waitForAllReady) await readableOriginal.allReady;
|
|
42
|
-
|
|
43
|
-
const
|
|
71
|
+
request.signal.throwIfAborted();
|
|
72
|
+
const styledComponentsStyleTags = extenders.map((extender)=>extender.getStyleTags?.() ?? '').join('');
|
|
73
|
+
const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
|
|
74
|
+
...templateOptions,
|
|
75
|
+
renderLevel: RenderLevel.SERVER_RENDER,
|
|
76
|
+
styledComponentsStyleTags
|
|
77
|
+
});
|
|
78
|
+
for (const extender of orderSSRStreamTransforms(extenders))if (void 0 !== extender.processReadableStream) pendingSource = extender.processReadableStream(pendingSource);
|
|
79
|
+
const decoder = new TextDecoder();
|
|
80
|
+
const encoder = new TextEncoder();
|
|
81
|
+
const pendingScripts = [];
|
|
82
|
+
let buffered = '';
|
|
83
|
+
let shellChunkStatus = ShellChunkStatus.START;
|
|
84
|
+
let bodyController;
|
|
85
|
+
const emit = (chunk, controller)=>{
|
|
86
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) {
|
|
87
|
+
if (chunk.length > 0) controller.enqueue(encoder.encode(chunk));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
buffered += chunk;
|
|
91
|
+
const markerIndex = buffered.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
|
|
92
|
+
if (-1 === markerIndex) return;
|
|
93
|
+
const beforeMark = lifecycle.completedBody(buffered.slice(0, markerIndex), 'shell');
|
|
94
|
+
const afterMark = buffered.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
|
|
95
|
+
const completedShellBefore = createReplaceHelemt(getHelmetData(extenders))(shellBefore);
|
|
96
|
+
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
97
|
+
buffered = '';
|
|
98
|
+
controller.enqueue(encoder.encode(`${completedShellBefore}${beforeMark}${shellAfter}`));
|
|
99
|
+
if (afterMark.length > 0) controller.enqueue(encoder.encode(afterMark));
|
|
100
|
+
for (const script of pendingScripts)controller.enqueue(encoder.encode(script));
|
|
101
|
+
pendingScripts.length = 0;
|
|
102
|
+
};
|
|
103
|
+
const body = new TransformStream({
|
|
44
104
|
start (controller) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} catch {
|
|
52
|
-
isClosed = true;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
const closeController = ()=>{
|
|
56
|
-
if (!isClosed) {
|
|
57
|
-
isClosed = true;
|
|
58
|
-
try {
|
|
59
|
-
controller.close();
|
|
60
|
-
} catch {}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const flushPendingScripts = ()=>{
|
|
64
|
-
for (const s of pendingScripts)safeEnqueue(encodeForWebStream(s));
|
|
65
|
-
pendingScripts.length = 0;
|
|
66
|
-
};
|
|
67
|
-
const enqueueScript = (script)=>{
|
|
68
|
-
if (shellChunkStatus === ShellChunkStatus.FINISH) safeEnqueue(encodeForWebStream(script));
|
|
69
|
-
else pendingScripts.push(script);
|
|
70
|
-
};
|
|
71
|
-
const storageContext = storage.useContext?.();
|
|
72
|
-
const activeDeferreds = storageContext?.activeDeferreds;
|
|
73
|
-
const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
|
|
74
|
-
if (entries.length > 0) enqueueFromEntries(entries, config.nonce, enqueueScript);
|
|
75
|
-
async function push() {
|
|
76
|
-
try {
|
|
77
|
-
const { done, value } = await reader.read();
|
|
78
|
-
if (done) return void closeController();
|
|
79
|
-
if (isClosed) return;
|
|
80
|
-
if (shellChunkStatus !== ShellChunkStatus.FINISH) {
|
|
81
|
-
chunkVec.push(new TextDecoder().decode(value));
|
|
82
|
-
const concatedChunk = chunkVec.join('');
|
|
83
|
-
const markerIndex = concatedChunk.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
|
|
84
|
-
if (-1 !== markerIndex) {
|
|
85
|
-
const beforeMark = concatedChunk.slice(0, markerIndex);
|
|
86
|
-
const afterMark = concatedChunk.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
|
|
87
|
-
__rspack_external__modern_js_runtime_extensions_ce611631.publishHeadRender(runtimeContext);
|
|
88
|
-
const completedShellBefore = createReplaceHelemt(getHelmetData(runtimeContext))(shellBefore);
|
|
89
|
-
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
90
|
-
safeEnqueue(encodeForWebStream(`${completedShellBefore}${beforeMark}${shellAfter}`));
|
|
91
|
-
if (afterMark.length > 0) safeEnqueue(encodeForWebStream(afterMark));
|
|
92
|
-
flushPendingScripts();
|
|
93
|
-
}
|
|
94
|
-
} else safeEnqueue(value);
|
|
95
|
-
if (!isClosed) push();
|
|
96
|
-
} catch (error) {
|
|
97
|
-
__rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
|
|
98
|
-
if (!isClosed) {
|
|
99
|
-
isClosed = true;
|
|
100
|
-
try {
|
|
101
|
-
controller.error(error);
|
|
102
|
-
} catch {}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
push();
|
|
105
|
+
bodyController = controller;
|
|
106
|
+
},
|
|
107
|
+
transform (chunk, controller) {
|
|
108
|
+
emit(decoder.decode(chunk, {
|
|
109
|
+
stream: true
|
|
110
|
+
}), controller);
|
|
107
111
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
flush (controller) {
|
|
113
|
+
bodyOpen = false;
|
|
114
|
+
emit(decoder.decode(), controller);
|
|
115
|
+
if (shellChunkStatus !== ShellChunkStatus.FINISH) throw new Error('React SSR stream ended before the shell marker');
|
|
111
116
|
}
|
|
112
117
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
|
|
118
|
+
bodyPipe = pendingSource.pipeTo(body.writable);
|
|
119
|
+
bodyPipe.catch(()=>{});
|
|
120
|
+
pendingSource = body.readable;
|
|
121
|
+
const activeDeferreds = storage.useContext?.()?.activeDeferreds;
|
|
122
|
+
const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
|
|
123
|
+
enqueueFromEntries(entries, config.nonce, (script)=>{
|
|
124
|
+
if (!bodyOpen) return;
|
|
125
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) try {
|
|
126
|
+
bodyController.enqueue(encoder.encode(script));
|
|
127
|
+
} catch {
|
|
128
|
+
bodyOpen = false;
|
|
129
|
+
}
|
|
130
|
+
else pendingScripts.push(script);
|
|
131
|
+
});
|
|
132
|
+
return observeSSRStream(pendingSource, {
|
|
133
|
+
lifecycle,
|
|
134
|
+
async onError (error) {
|
|
135
|
+
bodyOpen = false;
|
|
136
|
+
await bodyPipe?.catch(()=>{});
|
|
137
|
+
reportError(error);
|
|
138
|
+
},
|
|
139
|
+
signal: request.signal,
|
|
140
|
+
async onCancel (reason) {
|
|
141
|
+
bodyOpen = false;
|
|
142
|
+
await bodyPipe?.catch((error)=>{
|
|
143
|
+
if (error !== reason) throw error;
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
onComplete: ()=>bodyPipe
|
|
147
|
+
});
|
|
148
|
+
} catch (error) {
|
|
149
|
+
bodyOpen = false;
|
|
150
|
+
if (void 0 !== pendingSource) try {
|
|
151
|
+
await pendingSource.cancel(error);
|
|
152
|
+
await bodyPipe?.catch(()=>{});
|
|
153
|
+
} catch (cancelError) {
|
|
154
|
+
if (!request.signal.aborted) reportError(cancelError);
|
|
155
|
+
}
|
|
156
|
+
if (request.signal.aborted) {
|
|
157
|
+
lifecycle.finish({
|
|
158
|
+
status: 'cancelled',
|
|
159
|
+
reason: request.signal.reason
|
|
160
|
+
});
|
|
161
|
+
throw request.signal.reason;
|
|
162
|
+
}
|
|
163
|
+
lifecycle.finish({
|
|
164
|
+
status: 'fallback',
|
|
165
|
+
error
|
|
166
|
+
});
|
|
167
|
+
reportError(error);
|
|
168
|
+
const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
|
|
169
|
+
...templateOptions,
|
|
170
|
+
renderLevel: RenderLevel.CLIENT_RENDER,
|
|
171
|
+
helmetData: getHelmetData(extenders)
|
|
172
|
+
});
|
|
173
|
+
return observeSSRStream(getReadableStreamFromString(`${shellBefore}${shellAfter}`), {
|
|
174
|
+
lifecycle,
|
|
175
|
+
onError: reportError,
|
|
176
|
+
signal: request.signal
|
|
177
|
+
});
|
|
119
178
|
}
|
|
120
179
|
};
|
|
121
180
|
export { createReadableStreamFromElement };
|
|
@@ -20,13 +20,13 @@ function isDeferredDataLike(v) {
|
|
|
20
20
|
return hasPending && hasData;
|
|
21
21
|
}
|
|
22
22
|
function isPromiseLike(value) {
|
|
23
|
-
return
|
|
23
|
+
return Boolean(value) && 'function' == typeof value.then;
|
|
24
24
|
}
|
|
25
25
|
function toErrorInfo(error) {
|
|
26
26
|
if (shouldRedactServerError()) return {
|
|
27
27
|
message: 'Unexpected Server Error'
|
|
28
28
|
};
|
|
29
|
-
if (error && 'object' == typeof error) {
|
|
29
|
+
if (null !== error && 'object' == typeof error) {
|
|
30
30
|
const maybeMsg = error.message;
|
|
31
31
|
const maybeStack = error.stack;
|
|
32
32
|
return {
|
|
@@ -41,7 +41,7 @@ function toErrorInfo(error) {
|
|
|
41
41
|
function buildDeferredDataScript(nonce, args) {
|
|
42
42
|
const payload = JSON.stringify(args);
|
|
43
43
|
const escaped = escapeAttr(payload);
|
|
44
|
-
const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
|
|
44
|
+
const nonceAttr = void 0 !== nonce && '' !== nonce ? ` nonce="${nonce}"` : '';
|
|
45
45
|
return `<script async${nonceAttr} data-fn-name="r" data-script-src="modern-run-router-data-fn" data-fn-args='${escaped}' suppressHydrationWarning>${runRouterDataFnStr}</script>`;
|
|
46
46
|
}
|
|
47
47
|
function enqueueFromEntries(entries, nonce, emit) {
|