@modern-js/runtime 3.9.1 → 3.9.3
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/template.server.js +1 -2
- package/dist/cjs/core/browser/hydrate.js +13 -11
- package/dist/cjs/core/server/requestHandler.js +2 -0
- package/dist/cjs/core/server/stream/beforeTemplate.js +3 -3
- package/dist/cjs/core/server/stream/createReadableStream.js +51 -8
- package/dist/cjs/core/server/stream/createReadableStream.worker.js +37 -15
- package/dist/cjs/core/server/stream/deferredScript.js +12 -6
- package/dist/cjs/core/server/stream/deferredScriptOutputCoordinator.js +370 -0
- package/dist/cjs/core/server/string/loadable.js +4 -4
- package/dist/cjs/router/cli/code/nestedRoutes.js +1 -2
- package/dist/cjs/router/cli/code/templates.js +1 -1
- package/dist/cjs/router/cli/code/utils.js +2 -2
- package/dist/cjs/router/runtime/DeferredDataScripts.node.js +13 -10
- package/dist/cjs/router/runtime/plugin.node.js +1 -1
- package/dist/esm/cli/template.server.mjs +1 -2
- package/dist/esm/core/browser/hydrate.mjs +13 -11
- package/dist/esm/core/server/requestHandler.mjs +2 -0
- package/dist/esm/core/server/stream/beforeTemplate.mjs +3 -3
- package/dist/esm/core/server/stream/createReadableStream.mjs +51 -8
- package/dist/esm/core/server/stream/createReadableStream.worker.mjs +37 -15
- package/dist/esm/core/server/stream/deferredScript.mjs +12 -6
- package/dist/esm/core/server/stream/deferredScriptOutputCoordinator.mjs +332 -0
- package/dist/esm/core/server/string/loadable.mjs +4 -4
- package/dist/esm/router/cli/code/nestedRoutes.mjs +1 -2
- package/dist/esm/router/cli/code/templates.mjs +1 -1
- package/dist/esm/router/cli/code/utils.mjs +2 -2
- package/dist/esm/router/runtime/DeferredDataScripts.node.mjs +13 -10
- package/dist/esm/router/runtime/plugin.node.mjs +1 -1
- package/dist/esm-node/cli/template.server.mjs +1 -2
- package/dist/esm-node/core/browser/hydrate.mjs +13 -11
- package/dist/esm-node/core/server/requestHandler.mjs +2 -0
- package/dist/esm-node/core/server/stream/beforeTemplate.mjs +3 -3
- package/dist/esm-node/core/server/stream/createReadableStream.mjs +51 -8
- package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +37 -15
- package/dist/esm-node/core/server/stream/deferredScript.mjs +12 -6
- package/dist/esm-node/core/server/stream/deferredScriptOutputCoordinator.mjs +333 -0
- package/dist/esm-node/core/server/string/loadable.mjs +4 -4
- package/dist/esm-node/router/cli/code/nestedRoutes.mjs +1 -2
- package/dist/esm-node/router/cli/code/templates.mjs +1 -1
- package/dist/esm-node/router/cli/code/utils.mjs +2 -2
- package/dist/esm-node/router/runtime/DeferredDataScripts.node.mjs +13 -10
- package/dist/esm-node/router/runtime/plugin.node.mjs +1 -1
- package/dist/types/core/server/stream/deferredScript.d.ts +1 -1
- package/dist/types/core/server/stream/deferredScriptOutputCoordinator.d.ts +72 -0
- package/package.json +12 -12
|
@@ -13,7 +13,8 @@ const DeferredDataScripts = (props)=>{
|
|
|
13
13
|
}, []);
|
|
14
14
|
const deferredScripts = useMemo(()=>{
|
|
15
15
|
if (!staticContext) return null;
|
|
16
|
-
const
|
|
16
|
+
const requestStorage = storage.useContext();
|
|
17
|
+
const activeDeferreds = requestStorage.activeDeferreds;
|
|
17
18
|
const _ROUTER_DATA = {
|
|
18
19
|
loaderData: staticContext.loaderData,
|
|
19
20
|
errors: serializeErrors(staticContext.errors)
|
|
@@ -26,6 +27,7 @@ const DeferredDataScripts = (props)=>{
|
|
|
26
27
|
const deferredDataScripts = [];
|
|
27
28
|
const initialScripts = Array.from(activeDeferreds.entries()).map(([routeId, deferredData])=>{
|
|
28
29
|
const pendingKeys = new Set(deferredData.pendingKeys);
|
|
30
|
+
requestStorage.deferredScriptKeys?.set(routeId, Array.from(pendingKeys));
|
|
29
31
|
const { deferredKeys } = deferredData;
|
|
30
32
|
const deferredKeyPromiseManifests = deferredKeys.map((key)=>{
|
|
31
33
|
if (pendingKeys.has(key)) return {
|
|
@@ -36,7 +38,7 @@ const DeferredDataScripts = (props)=>{
|
|
|
36
38
|
serializeJson(key)
|
|
37
39
|
]
|
|
38
40
|
};
|
|
39
|
-
{
|
|
41
|
+
else {
|
|
40
42
|
const trackedPromise = deferredData.data[key];
|
|
41
43
|
if (void 0 !== trackedPromise._error) {
|
|
42
44
|
const error = {
|
|
@@ -51,15 +53,16 @@ const DeferredDataScripts = (props)=>{
|
|
|
51
53
|
serializeJson(error)
|
|
52
54
|
]
|
|
53
55
|
};
|
|
56
|
+
} else {
|
|
57
|
+
if (void 0 === trackedPromise._data) throw new Error(`The deferred data for ${key} was not resolved, did you forget to return data from a deferred promise`);
|
|
58
|
+
return {
|
|
59
|
+
key,
|
|
60
|
+
routerDataFnName: 'p',
|
|
61
|
+
routerDataFnArgs: [
|
|
62
|
+
serializeJson(trackedPromise._data)
|
|
63
|
+
]
|
|
64
|
+
};
|
|
54
65
|
}
|
|
55
|
-
if (void 0 === trackedPromise._data) throw new Error(`The deferred data for ${key} was not resolved, did you forget to return data from a deferred promise`);
|
|
56
|
-
return {
|
|
57
|
-
key,
|
|
58
|
-
routerDataFnName: 'p',
|
|
59
|
-
routerDataFnArgs: [
|
|
60
|
-
serializeJson(trackedPromise._data)
|
|
61
|
-
]
|
|
62
|
-
};
|
|
63
66
|
}
|
|
64
67
|
});
|
|
65
68
|
return {
|
|
@@ -106,7 +106,7 @@ const routerPlugin = (userConfig = {})=>({
|
|
|
106
106
|
}) : /*#__PURE__*/ jsx(RSCStaticRouter, {
|
|
107
107
|
basename: basename
|
|
108
108
|
});
|
|
109
|
-
{
|
|
109
|
+
else {
|
|
110
110
|
const routerWrapper = /*#__PURE__*/ jsxs(Fragment, {
|
|
111
111
|
children: [
|
|
112
112
|
/*#__PURE__*/ jsx(StaticRouterProvider, {
|
|
@@ -109,8 +109,7 @@ function genHandlerCode({ mode, metaName, customServerEntry, srcDirectory, inter
|
|
|
109
109
|
return `
|
|
110
110
|
export * from '${realEntryPath}';
|
|
111
111
|
export { default as requestHandler } from '${realEntryPath}'`;
|
|
112
|
-
}
|
|
113
|
-
{
|
|
112
|
+
} else {
|
|
114
113
|
const entrySource = enableRsc ? SERVER_ENTRY_RSC : SERVER_ENTRY;
|
|
115
114
|
const serverEntry = transformServerEntry(entrySource, {
|
|
116
115
|
metaName: metaName || 'modern-js',
|
|
@@ -27,7 +27,7 @@ function hydrate_hydrateRoot(App, context, ModernRender, ModernHydrate) {
|
|
|
27
27
|
if ('stream' === renderMode) return streamSSRHydrate();
|
|
28
28
|
function streamSSRHydrate() {
|
|
29
29
|
if (renderLevel !== RenderLevel.SERVER_RENDER) return ModernRender(wrapRuntimeContextProvider(App, context));
|
|
30
|
-
{
|
|
30
|
+
else {
|
|
31
31
|
const SSRApp = ()=>/*#__PURE__*/ jsx(WithCallback, {
|
|
32
32
|
callback: callback,
|
|
33
33
|
children: App
|
|
@@ -38,19 +38,21 @@ function hydrate_hydrateRoot(App, context, ModernRender, ModernHydrate) {
|
|
|
38
38
|
return stringSSRHydrate();
|
|
39
39
|
function stringSSRHydrate() {
|
|
40
40
|
if (renderLevel === RenderLevel.CLIENT_RENDER) return ModernRender(wrapRuntimeContextProvider(App, context));
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
else {
|
|
42
|
+
if (renderLevel === RenderLevel.SERVER_RENDER) return new Promise((resolve)=>{
|
|
43
|
+
loadableReady(()=>{
|
|
44
|
+
const SSRApp = ()=>/*#__PURE__*/ jsx(WithCallback, {
|
|
45
|
+
callback: callback,
|
|
46
|
+
children: App
|
|
47
|
+
});
|
|
48
|
+
ModernHydrate(wrapRuntimeContextProvider(/*#__PURE__*/ jsx(SSRApp, {}), hydrateContext)).then((root)=>{
|
|
49
|
+
resolve(root);
|
|
46
50
|
});
|
|
47
|
-
ModernHydrate(wrapRuntimeContextProvider(/*#__PURE__*/ jsx(SSRApp, {}), hydrateContext)).then((root)=>{
|
|
48
|
-
resolve(root);
|
|
49
51
|
});
|
|
50
52
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
console.warn(`unknow render level: ${renderLevel}, execute render()`);
|
|
54
|
+
return ModernRender(wrapRuntimeContextProvider(App, context));
|
|
55
|
+
}
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
export { hydrateWithReact, hydrate_hydrateRoot as hydrateRoot };
|
|
@@ -102,12 +102,14 @@ const createRequestHandler = async (handleRequest, createRequestOptions)=>{
|
|
|
102
102
|
status: -1
|
|
103
103
|
};
|
|
104
104
|
const activeDeferreds = new Map();
|
|
105
|
+
const deferredScriptKeys = new Map();
|
|
105
106
|
return storage.run({
|
|
106
107
|
headers: headersData,
|
|
107
108
|
request,
|
|
108
109
|
monitors: options.monitors,
|
|
109
110
|
responseProxy,
|
|
110
111
|
activeDeferreds,
|
|
112
|
+
deferredScriptKeys,
|
|
111
113
|
serverPayload: void 0
|
|
112
114
|
}, async ()=>{
|
|
113
115
|
const Root = createRoot();
|
|
@@ -16,8 +16,8 @@ const readAsset = async (chunk)=>{
|
|
|
16
16
|
};
|
|
17
17
|
const checkIsInline = (chunk, enableInline)=>{
|
|
18
18
|
if ('production' !== process.env.NODE_ENV) return false;
|
|
19
|
-
if (enableInline instanceof RegExp) return enableInline.test(chunk);
|
|
20
|
-
return Boolean(enableInline);
|
|
19
|
+
else if (enableInline instanceof RegExp) return enableInline.test(chunk);
|
|
20
|
+
else return Boolean(enableInline);
|
|
21
21
|
};
|
|
22
22
|
async function buildShellBeforeTemplate(beforeAppTemplate, options) {
|
|
23
23
|
const { config, runtimeContext, styledComponentsStyleTags, entryName } = options;
|
|
@@ -58,7 +58,7 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
|
|
|
58
58
|
const styles = await Promise.all(cssChunks.map(async (chunk)=>{
|
|
59
59
|
const link = `<link href="${chunk}" rel="stylesheet" />`;
|
|
60
60
|
if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
|
|
61
|
-
return link;
|
|
61
|
+
else return link;
|
|
62
62
|
}));
|
|
63
63
|
return `${styles.join('')}`;
|
|
64
64
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { PassThrough, Readable, Transform } from "stream";
|
|
3
|
+
import { StringDecoder } from "string_decoder";
|
|
3
4
|
import { storage } from "@modern-js/runtime-utils/node";
|
|
4
5
|
import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
|
|
5
6
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
|
|
@@ -7,6 +8,7 @@ import { RenderLevel } from "../../constants.mjs";
|
|
|
7
8
|
import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
|
|
8
9
|
import { getMonitors } from "../../context/monitors/index.mjs";
|
|
9
10
|
import { enqueueFromEntries } from "./deferredScript.mjs";
|
|
11
|
+
import { DeferredScriptOutputCoordinator } from "./deferredScriptOutputCoordinator.mjs";
|
|
10
12
|
import { ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
|
|
11
13
|
import { getTemplates } from "./template.mjs";
|
|
12
14
|
const defaultExtender = {
|
|
@@ -55,7 +57,14 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
55
57
|
entryName,
|
|
56
58
|
styledComponentsStyleTags
|
|
57
59
|
}).then(({ shellAfter, shellBefore })=>{
|
|
60
|
+
const decoder = new StringDecoder('utf8');
|
|
58
61
|
const pendingScripts = [];
|
|
62
|
+
const outputState = {};
|
|
63
|
+
let deferredResolversComplete = Promise.resolve();
|
|
64
|
+
const writeReact = (content)=>{
|
|
65
|
+
if (!outputState.coordinator) throw new Error("Deferred script coordinator is not ready");
|
|
66
|
+
outputState.coordinator.writeReact(content);
|
|
67
|
+
};
|
|
59
68
|
const body = new Transform({
|
|
60
69
|
transform (chunk, _encoding, callback) {
|
|
61
70
|
try {
|
|
@@ -67,17 +76,49 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
67
76
|
const beforeMark = concatedChunk.slice(0, markerIndex);
|
|
68
77
|
const afterMark = concatedChunk.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
|
|
69
78
|
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
70
|
-
|
|
71
|
-
if (afterMark)
|
|
72
|
-
if (
|
|
79
|
+
writeReact(`${shellBefore}${beforeMark}${shellAfter}`);
|
|
80
|
+
if (afterMark) writeReact(afterMark);
|
|
81
|
+
if (outputState.coordinator) {
|
|
82
|
+
outputState.coordinator.markShellFinished();
|
|
83
|
+
for (const script of pendingScripts)outputState.coordinator.enqueueResolver(script);
|
|
84
|
+
pendingScripts.length = 0;
|
|
85
|
+
}
|
|
73
86
|
}
|
|
74
|
-
} else
|
|
87
|
+
} else {
|
|
88
|
+
const decodedChunk = decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
89
|
+
writeReact(decodedChunk);
|
|
90
|
+
}
|
|
75
91
|
callback();
|
|
76
92
|
} catch (e) {
|
|
77
93
|
e instanceof Error ? callback(e) : callback(new Error('Received unknown error when streaming'));
|
|
78
94
|
}
|
|
95
|
+
},
|
|
96
|
+
flush (callback) {
|
|
97
|
+
try {
|
|
98
|
+
writeReact(decoder.end());
|
|
99
|
+
} catch (error) {
|
|
100
|
+
callback(error instanceof Error ? error : new Error('Received unknown error when streaming'));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
deferredResolversComplete.then(()=>{
|
|
104
|
+
try {
|
|
105
|
+
outputState.coordinator?.finish();
|
|
106
|
+
callback();
|
|
107
|
+
} catch (error) {
|
|
108
|
+
callback(error instanceof Error ? error : new Error('Received unknown error when streaming'));
|
|
109
|
+
}
|
|
110
|
+
}, (error)=>{
|
|
111
|
+
callback(error instanceof Error ? error : new Error('Received unknown error when streaming'));
|
|
112
|
+
});
|
|
79
113
|
}
|
|
80
114
|
});
|
|
115
|
+
const coordinator = new DeferredScriptOutputCoordinator((content)=>{
|
|
116
|
+
body.push(content);
|
|
117
|
+
});
|
|
118
|
+
outputState.coordinator = coordinator;
|
|
119
|
+
body.once('close', ()=>{
|
|
120
|
+
coordinator.abort();
|
|
121
|
+
});
|
|
81
122
|
const passThrough = new PassThrough();
|
|
82
123
|
const stream = Readable.toWeb(body);
|
|
83
124
|
resolve(stream);
|
|
@@ -85,23 +126,25 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
85
126
|
extenders.forEach((extender)=>{
|
|
86
127
|
if (extender.processStream) processedStream = extender.processStream(processedStream);
|
|
87
128
|
});
|
|
88
|
-
reactStreamingPipe(passThrough);
|
|
89
|
-
processedStream.pipe(body);
|
|
90
129
|
try {
|
|
91
130
|
const storageContext = storage.useContext?.();
|
|
92
131
|
const activeDeferreds = storageContext?.activeDeferreds;
|
|
132
|
+
const deferredScriptKeys = storageContext?.deferredScriptKeys;
|
|
93
133
|
const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
|
|
94
134
|
if (entries.length > 0) {
|
|
95
135
|
const enqueueScript = (s)=>{
|
|
96
|
-
if (
|
|
136
|
+
if (!outputState.coordinator) throw new Error("Deferred script coordinator is not ready");
|
|
137
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) outputState.coordinator.enqueueResolver(s);
|
|
97
138
|
else pendingScripts.push(s);
|
|
98
139
|
};
|
|
99
|
-
enqueueFromEntries(entries, config.nonce,
|
|
140
|
+
deferredResolversComplete = enqueueFromEntries(entries, deferredScriptKeys, config.nonce, enqueueScript);
|
|
100
141
|
}
|
|
101
142
|
} catch (err) {
|
|
102
143
|
const monitors = getMonitors();
|
|
103
144
|
monitors.error("cannot inject router data script", err);
|
|
104
145
|
}
|
|
146
|
+
reactStreamingPipe(passThrough);
|
|
147
|
+
processedStream.pipe(body);
|
|
105
148
|
});
|
|
106
149
|
},
|
|
107
150
|
onShellError (error) {
|
|
@@ -4,6 +4,7 @@ import { storage } from "@modern-js/runtime-utils/node";
|
|
|
4
4
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
|
|
5
5
|
import { RenderLevel } from "../../constants.mjs";
|
|
6
6
|
import { enqueueFromEntries } from "./deferredScript.mjs";
|
|
7
|
+
import { DeferredScriptOutputCoordinator } from "./deferredScriptOutputCoordinator.mjs";
|
|
7
8
|
import { ShellChunkStatus, encodeForWebStream, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
|
|
8
9
|
import { getTemplates } from "./template.mjs";
|
|
9
10
|
const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
@@ -36,10 +37,13 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
36
37
|
const { waitForAllReady } = resolveStreamingMode(request, forceStreamToString);
|
|
37
38
|
if (waitForAllReady) await readableOriginal.allReady;
|
|
38
39
|
const reader = readableOriginal.getReader();
|
|
40
|
+
let coordinator;
|
|
39
41
|
const stream = new ReadableStream({
|
|
40
42
|
start (controller) {
|
|
43
|
+
const decoder = new TextDecoder();
|
|
41
44
|
const pendingScripts = [];
|
|
42
45
|
let isClosed = false;
|
|
46
|
+
let deferredResolversComplete = Promise.resolve();
|
|
43
47
|
const safeEnqueue = (chunk)=>{
|
|
44
48
|
if (isClosed) return;
|
|
45
49
|
try {
|
|
@@ -56,38 +60,55 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
56
60
|
} catch {}
|
|
57
61
|
}
|
|
58
62
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
};
|
|
63
|
-
const enqueueScript = (script)=>{
|
|
64
|
-
if (shellChunkStatus === ShellChunkStatus.FINISH) safeEnqueue(encodeForWebStream(script));
|
|
65
|
-
else pendingScripts.push(script);
|
|
66
|
-
};
|
|
63
|
+
coordinator = new DeferredScriptOutputCoordinator((content)=>{
|
|
64
|
+
safeEnqueue(encodeForWebStream(content));
|
|
65
|
+
});
|
|
67
66
|
const storageContext = storage.useContext?.();
|
|
68
67
|
const activeDeferreds = storageContext?.activeDeferreds;
|
|
68
|
+
const deferredScriptKeys = storageContext?.deferredScriptKeys;
|
|
69
69
|
const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
|
|
70
|
-
if (entries.length > 0) enqueueFromEntries(entries, config.nonce,
|
|
70
|
+
if (entries.length > 0) deferredResolversComplete = enqueueFromEntries(entries, deferredScriptKeys, config.nonce, (script)=>{
|
|
71
|
+
if (!coordinator) throw new Error("Deferred script coordinator is not ready");
|
|
72
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) coordinator.enqueueResolver(script);
|
|
73
|
+
else pendingScripts.push(script);
|
|
74
|
+
});
|
|
71
75
|
async function push() {
|
|
72
76
|
try {
|
|
73
77
|
const { done, value } = await reader.read();
|
|
74
|
-
if (done)
|
|
78
|
+
if (done) {
|
|
79
|
+
const trailingText = decoder.decode();
|
|
80
|
+
if (trailingText) coordinator?.writeReact(trailingText);
|
|
81
|
+
await deferredResolversComplete;
|
|
82
|
+
coordinator?.finish();
|
|
83
|
+
closeController();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
75
86
|
if (isClosed) return;
|
|
76
87
|
if (shellChunkStatus !== ShellChunkStatus.FINISH) {
|
|
77
|
-
chunkVec.push(
|
|
88
|
+
chunkVec.push(decoder.decode(value, {
|
|
89
|
+
stream: true
|
|
90
|
+
}));
|
|
78
91
|
const concatedChunk = chunkVec.join('');
|
|
79
92
|
const markerIndex = concatedChunk.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
|
|
80
93
|
if (-1 !== markerIndex) {
|
|
81
94
|
const beforeMark = concatedChunk.slice(0, markerIndex);
|
|
82
95
|
const afterMark = concatedChunk.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
|
|
83
96
|
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
84
|
-
|
|
85
|
-
if (afterMark)
|
|
86
|
-
|
|
97
|
+
coordinator?.writeReact(`${shellBefore}${beforeMark}${shellAfter}`);
|
|
98
|
+
if (afterMark) coordinator?.writeReact(afterMark);
|
|
99
|
+
coordinator?.markShellFinished();
|
|
100
|
+
for (const script of pendingScripts)coordinator?.enqueueResolver(script);
|
|
101
|
+
pendingScripts.length = 0;
|
|
87
102
|
}
|
|
88
|
-
} else
|
|
103
|
+
} else {
|
|
104
|
+
const decodedChunk = decoder.decode(value, {
|
|
105
|
+
stream: true
|
|
106
|
+
});
|
|
107
|
+
if (decodedChunk) coordinator?.writeReact(decodedChunk);
|
|
108
|
+
}
|
|
89
109
|
if (!isClosed) push();
|
|
90
110
|
} catch (error) {
|
|
111
|
+
coordinator?.abort();
|
|
91
112
|
if (!isClosed) {
|
|
92
113
|
isClosed = true;
|
|
93
114
|
try {
|
|
@@ -99,6 +120,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
99
120
|
push();
|
|
100
121
|
},
|
|
101
122
|
cancel (reason) {
|
|
123
|
+
coordinator?.abort();
|
|
102
124
|
reader.cancel(reason).catch(()=>{});
|
|
103
125
|
}
|
|
104
126
|
});
|
|
@@ -41,23 +41,29 @@ function buildDeferredDataScript(nonce, args) {
|
|
|
41
41
|
const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
|
|
42
42
|
return `<script async${nonceAttr} data-fn-name="r" data-script-src="modern-run-router-data-fn" data-fn-args='${escaped}' suppressHydrationWarning>${runRouterDataFnStr}</script>`;
|
|
43
43
|
}
|
|
44
|
-
function enqueueFromEntries(entries, nonce, emit) {
|
|
44
|
+
function enqueueFromEntries(entries, deferredScriptKeys, nonce, emit) {
|
|
45
|
+
const pendingResolvers = [];
|
|
45
46
|
entries.forEach(([routeId, value])=>{
|
|
46
47
|
if (!isDeferredDataLike(value)) return;
|
|
47
|
-
const
|
|
48
|
-
|
|
48
|
+
const serializedKeys = deferredScriptKeys ? deferredScriptKeys.get(routeId) ?? [] : value.pendingKeys ?? [];
|
|
49
|
+
serializedKeys.forEach((key)=>{
|
|
49
50
|
const tracked = value.data?.[key];
|
|
50
|
-
if (isPromiseLike(tracked)) tracked.then((val)=>
|
|
51
|
+
if (isPromiseLike(tracked)) pendingResolvers.push(Promise.resolve(tracked).then((val)=>{
|
|
52
|
+
emit(buildDeferredDataScript(nonce, [
|
|
51
53
|
routeId,
|
|
52
54
|
key,
|
|
53
55
|
val
|
|
54
|
-
]))
|
|
56
|
+
]));
|
|
57
|
+
}, (err)=>{
|
|
58
|
+
emit(buildDeferredDataScript(nonce, [
|
|
55
59
|
routeId,
|
|
56
60
|
key,
|
|
57
61
|
void 0,
|
|
58
62
|
toErrorInfo(err)
|
|
59
|
-
]))
|
|
63
|
+
]));
|
|
64
|
+
}));
|
|
60
65
|
});
|
|
61
66
|
});
|
|
67
|
+
return Promise.all(pendingResolvers).then(()=>void 0);
|
|
62
68
|
}
|
|
63
69
|
export { buildDeferredDataScript, enqueueFromEntries, escapeAttr, isDeferredDataLike, isPromiseLike, isRecord, toErrorInfo };
|