@modern-js/runtime 3.9.2 → 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/core/server/requestHandler.js +2 -0
- 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/router/runtime/DeferredDataScripts.node.js +3 -1
- package/dist/esm/core/server/requestHandler.mjs +2 -0
- 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/router/runtime/DeferredDataScripts.node.mjs +3 -1
- package/dist/esm-node/core/server/requestHandler.mjs +2 -0
- 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/router/runtime/DeferredDataScripts.node.mjs +3 -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
|
@@ -143,12 +143,14 @@ const createRequestHandler = async (handleRequest, createRequestOptions)=>{
|
|
|
143
143
|
status: -1
|
|
144
144
|
};
|
|
145
145
|
const activeDeferreds = new Map();
|
|
146
|
+
const deferredScriptKeys = new Map();
|
|
146
147
|
return node_namespaceObject.storage.run({
|
|
147
148
|
headers: headersData,
|
|
148
149
|
request,
|
|
149
150
|
monitors: options.monitors,
|
|
150
151
|
responseProxy,
|
|
151
152
|
activeDeferreds,
|
|
153
|
+
deferredScriptKeys,
|
|
152
154
|
serverPayload: void 0
|
|
153
155
|
}, async ()=>{
|
|
154
156
|
const Root = (0, external_react_index_js_namespaceObject.createRoot)();
|
|
@@ -31,6 +31,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
31
31
|
createReadableStreamFromElement: ()=>createReadableStreamFromElement
|
|
32
32
|
});
|
|
33
33
|
const external_stream_namespaceObject = require("stream");
|
|
34
|
+
const external_string_decoder_namespaceObject = require("string_decoder");
|
|
34
35
|
const node_namespaceObject = require("@modern-js/runtime-utils/node");
|
|
35
36
|
const constants_namespaceObject = require("@modern-js/utils/universal/constants");
|
|
36
37
|
const external_common_js_namespaceObject = require("../../../common.js");
|
|
@@ -38,6 +39,7 @@ const external_constants_js_namespaceObject = require("../../constants.js");
|
|
|
38
39
|
const index_js_namespaceObject = require("../../context/index.js");
|
|
39
40
|
const monitors_index_js_namespaceObject = require("../../context/monitors/index.js");
|
|
40
41
|
const external_deferredScript_js_namespaceObject = require("./deferredScript.js");
|
|
42
|
+
const external_deferredScriptOutputCoordinator_js_namespaceObject = require("./deferredScriptOutputCoordinator.js");
|
|
41
43
|
const external_shared_js_namespaceObject = require("./shared.js");
|
|
42
44
|
const external_template_js_namespaceObject = require("./template.js");
|
|
43
45
|
const defaultExtender = {
|
|
@@ -86,7 +88,14 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
86
88
|
entryName,
|
|
87
89
|
styledComponentsStyleTags
|
|
88
90
|
}).then(({ shellAfter, shellBefore })=>{
|
|
91
|
+
const decoder = new external_string_decoder_namespaceObject.StringDecoder('utf8');
|
|
89
92
|
const pendingScripts = [];
|
|
93
|
+
const outputState = {};
|
|
94
|
+
let deferredResolversComplete = Promise.resolve();
|
|
95
|
+
const writeReact = (content)=>{
|
|
96
|
+
if (!outputState.coordinator) throw new Error("Deferred script coordinator is not ready");
|
|
97
|
+
outputState.coordinator.writeReact(content);
|
|
98
|
+
};
|
|
90
99
|
const body = new external_stream_namespaceObject.Transform({
|
|
91
100
|
transform (chunk, _encoding, callback) {
|
|
92
101
|
try {
|
|
@@ -98,17 +107,49 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
98
107
|
const beforeMark = concatedChunk.slice(0, markerIndex);
|
|
99
108
|
const afterMark = concatedChunk.slice(markerIndex + external_common_js_namespaceObject.ESCAPED_SHELL_STREAM_END_MARK.length);
|
|
100
109
|
shellChunkStatus = external_shared_js_namespaceObject.ShellChunkStatus.FINISH;
|
|
101
|
-
|
|
102
|
-
if (afterMark)
|
|
103
|
-
if (
|
|
110
|
+
writeReact(`${shellBefore}${beforeMark}${shellAfter}`);
|
|
111
|
+
if (afterMark) writeReact(afterMark);
|
|
112
|
+
if (outputState.coordinator) {
|
|
113
|
+
outputState.coordinator.markShellFinished();
|
|
114
|
+
for (const script of pendingScripts)outputState.coordinator.enqueueResolver(script);
|
|
115
|
+
pendingScripts.length = 0;
|
|
116
|
+
}
|
|
104
117
|
}
|
|
105
|
-
} else
|
|
118
|
+
} else {
|
|
119
|
+
const decodedChunk = decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
120
|
+
writeReact(decodedChunk);
|
|
121
|
+
}
|
|
106
122
|
callback();
|
|
107
123
|
} catch (e) {
|
|
108
124
|
e instanceof Error ? callback(e) : callback(new Error('Received unknown error when streaming'));
|
|
109
125
|
}
|
|
126
|
+
},
|
|
127
|
+
flush (callback) {
|
|
128
|
+
try {
|
|
129
|
+
writeReact(decoder.end());
|
|
130
|
+
} catch (error) {
|
|
131
|
+
callback(error instanceof Error ? error : new Error('Received unknown error when streaming'));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
deferredResolversComplete.then(()=>{
|
|
135
|
+
try {
|
|
136
|
+
outputState.coordinator?.finish();
|
|
137
|
+
callback();
|
|
138
|
+
} catch (error) {
|
|
139
|
+
callback(error instanceof Error ? error : new Error('Received unknown error when streaming'));
|
|
140
|
+
}
|
|
141
|
+
}, (error)=>{
|
|
142
|
+
callback(error instanceof Error ? error : new Error('Received unknown error when streaming'));
|
|
143
|
+
});
|
|
110
144
|
}
|
|
111
145
|
});
|
|
146
|
+
const coordinator = new external_deferredScriptOutputCoordinator_js_namespaceObject.DeferredScriptOutputCoordinator((content)=>{
|
|
147
|
+
body.push(content);
|
|
148
|
+
});
|
|
149
|
+
outputState.coordinator = coordinator;
|
|
150
|
+
body.once('close', ()=>{
|
|
151
|
+
coordinator.abort();
|
|
152
|
+
});
|
|
112
153
|
const passThrough = new external_stream_namespaceObject.PassThrough();
|
|
113
154
|
const stream = external_stream_namespaceObject.Readable.toWeb(body);
|
|
114
155
|
resolve(stream);
|
|
@@ -116,23 +157,25 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
116
157
|
extenders.forEach((extender)=>{
|
|
117
158
|
if (extender.processStream) processedStream = extender.processStream(processedStream);
|
|
118
159
|
});
|
|
119
|
-
reactStreamingPipe(passThrough);
|
|
120
|
-
processedStream.pipe(body);
|
|
121
160
|
try {
|
|
122
161
|
const storageContext = node_namespaceObject.storage.useContext?.();
|
|
123
162
|
const activeDeferreds = storageContext?.activeDeferreds;
|
|
163
|
+
const deferredScriptKeys = storageContext?.deferredScriptKeys;
|
|
124
164
|
const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
|
|
125
165
|
if (entries.length > 0) {
|
|
126
166
|
const enqueueScript = (s)=>{
|
|
127
|
-
if (
|
|
167
|
+
if (!outputState.coordinator) throw new Error("Deferred script coordinator is not ready");
|
|
168
|
+
if (shellChunkStatus === external_shared_js_namespaceObject.ShellChunkStatus.FINISH) outputState.coordinator.enqueueResolver(s);
|
|
128
169
|
else pendingScripts.push(s);
|
|
129
170
|
};
|
|
130
|
-
(0, external_deferredScript_js_namespaceObject.enqueueFromEntries)(entries, config.nonce,
|
|
171
|
+
deferredResolversComplete = (0, external_deferredScript_js_namespaceObject.enqueueFromEntries)(entries, deferredScriptKeys, config.nonce, enqueueScript);
|
|
131
172
|
}
|
|
132
173
|
} catch (err) {
|
|
133
174
|
const monitors = (0, monitors_index_js_namespaceObject.getMonitors)();
|
|
134
175
|
monitors.error("cannot inject router data script", err);
|
|
135
176
|
}
|
|
177
|
+
reactStreamingPipe(passThrough);
|
|
178
|
+
processedStream.pipe(body);
|
|
136
179
|
});
|
|
137
180
|
},
|
|
138
181
|
onShellError (error) {
|
|
@@ -35,6 +35,7 @@ const node_namespaceObject = require("@modern-js/runtime-utils/node");
|
|
|
35
35
|
const external_common_js_namespaceObject = require("../../../common.js");
|
|
36
36
|
const external_constants_js_namespaceObject = require("../../constants.js");
|
|
37
37
|
const external_deferredScript_js_namespaceObject = require("./deferredScript.js");
|
|
38
|
+
const external_deferredScriptOutputCoordinator_js_namespaceObject = require("./deferredScriptOutputCoordinator.js");
|
|
38
39
|
const external_shared_js_namespaceObject = require("./shared.js");
|
|
39
40
|
const external_template_js_namespaceObject = require("./template.js");
|
|
40
41
|
const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
@@ -67,10 +68,13 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
67
68
|
const { waitForAllReady } = (0, external_shared_js_namespaceObject.resolveStreamingMode)(request, forceStreamToString);
|
|
68
69
|
if (waitForAllReady) await readableOriginal.allReady;
|
|
69
70
|
const reader = readableOriginal.getReader();
|
|
71
|
+
let coordinator;
|
|
70
72
|
const stream = new ReadableStream({
|
|
71
73
|
start (controller) {
|
|
74
|
+
const decoder = new TextDecoder();
|
|
72
75
|
const pendingScripts = [];
|
|
73
76
|
let isClosed = false;
|
|
77
|
+
let deferredResolversComplete = Promise.resolve();
|
|
74
78
|
const safeEnqueue = (chunk)=>{
|
|
75
79
|
if (isClosed) return;
|
|
76
80
|
try {
|
|
@@ -87,38 +91,55 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
87
91
|
} catch {}
|
|
88
92
|
}
|
|
89
93
|
};
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
};
|
|
94
|
-
const enqueueScript = (script)=>{
|
|
95
|
-
if (shellChunkStatus === external_shared_js_namespaceObject.ShellChunkStatus.FINISH) safeEnqueue((0, external_shared_js_namespaceObject.encodeForWebStream)(script));
|
|
96
|
-
else pendingScripts.push(script);
|
|
97
|
-
};
|
|
94
|
+
coordinator = new external_deferredScriptOutputCoordinator_js_namespaceObject.DeferredScriptOutputCoordinator((content)=>{
|
|
95
|
+
safeEnqueue((0, external_shared_js_namespaceObject.encodeForWebStream)(content));
|
|
96
|
+
});
|
|
98
97
|
const storageContext = node_namespaceObject.storage.useContext?.();
|
|
99
98
|
const activeDeferreds = storageContext?.activeDeferreds;
|
|
99
|
+
const deferredScriptKeys = storageContext?.deferredScriptKeys;
|
|
100
100
|
const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
|
|
101
|
-
if (entries.length > 0) (0, external_deferredScript_js_namespaceObject.enqueueFromEntries)(entries, config.nonce,
|
|
101
|
+
if (entries.length > 0) deferredResolversComplete = (0, external_deferredScript_js_namespaceObject.enqueueFromEntries)(entries, deferredScriptKeys, config.nonce, (script)=>{
|
|
102
|
+
if (!coordinator) throw new Error("Deferred script coordinator is not ready");
|
|
103
|
+
if (shellChunkStatus === external_shared_js_namespaceObject.ShellChunkStatus.FINISH) coordinator.enqueueResolver(script);
|
|
104
|
+
else pendingScripts.push(script);
|
|
105
|
+
});
|
|
102
106
|
async function push() {
|
|
103
107
|
try {
|
|
104
108
|
const { done, value } = await reader.read();
|
|
105
|
-
if (done)
|
|
109
|
+
if (done) {
|
|
110
|
+
const trailingText = decoder.decode();
|
|
111
|
+
if (trailingText) coordinator?.writeReact(trailingText);
|
|
112
|
+
await deferredResolversComplete;
|
|
113
|
+
coordinator?.finish();
|
|
114
|
+
closeController();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
106
117
|
if (isClosed) return;
|
|
107
118
|
if (shellChunkStatus !== external_shared_js_namespaceObject.ShellChunkStatus.FINISH) {
|
|
108
|
-
chunkVec.push(
|
|
119
|
+
chunkVec.push(decoder.decode(value, {
|
|
120
|
+
stream: true
|
|
121
|
+
}));
|
|
109
122
|
const concatedChunk = chunkVec.join('');
|
|
110
123
|
const markerIndex = concatedChunk.indexOf(external_common_js_namespaceObject.ESCAPED_SHELL_STREAM_END_MARK);
|
|
111
124
|
if (-1 !== markerIndex) {
|
|
112
125
|
const beforeMark = concatedChunk.slice(0, markerIndex);
|
|
113
126
|
const afterMark = concatedChunk.slice(markerIndex + external_common_js_namespaceObject.ESCAPED_SHELL_STREAM_END_MARK.length);
|
|
114
127
|
shellChunkStatus = external_shared_js_namespaceObject.ShellChunkStatus.FINISH;
|
|
115
|
-
|
|
116
|
-
if (afterMark)
|
|
117
|
-
|
|
128
|
+
coordinator?.writeReact(`${shellBefore}${beforeMark}${shellAfter}`);
|
|
129
|
+
if (afterMark) coordinator?.writeReact(afterMark);
|
|
130
|
+
coordinator?.markShellFinished();
|
|
131
|
+
for (const script of pendingScripts)coordinator?.enqueueResolver(script);
|
|
132
|
+
pendingScripts.length = 0;
|
|
118
133
|
}
|
|
119
|
-
} else
|
|
134
|
+
} else {
|
|
135
|
+
const decodedChunk = decoder.decode(value, {
|
|
136
|
+
stream: true
|
|
137
|
+
});
|
|
138
|
+
if (decodedChunk) coordinator?.writeReact(decodedChunk);
|
|
139
|
+
}
|
|
120
140
|
if (!isClosed) push();
|
|
121
141
|
} catch (error) {
|
|
142
|
+
coordinator?.abort();
|
|
122
143
|
if (!isClosed) {
|
|
123
144
|
isClosed = true;
|
|
124
145
|
try {
|
|
@@ -130,6 +151,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
|
|
|
130
151
|
push();
|
|
131
152
|
},
|
|
132
153
|
cancel (reason) {
|
|
154
|
+
coordinator?.abort();
|
|
133
155
|
reader.cancel(reason).catch(()=>{});
|
|
134
156
|
}
|
|
135
157
|
});
|
|
@@ -78,24 +78,30 @@ function buildDeferredDataScript(nonce, args) {
|
|
|
78
78
|
const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
|
|
79
79
|
return `<script async${nonceAttr} data-fn-name="r" data-script-src="modern-run-router-data-fn" data-fn-args='${escaped}' suppressHydrationWarning>${constants_js_namespaceObject.runRouterDataFnStr}</script>`;
|
|
80
80
|
}
|
|
81
|
-
function enqueueFromEntries(entries, nonce, emit) {
|
|
81
|
+
function enqueueFromEntries(entries, deferredScriptKeys, nonce, emit) {
|
|
82
|
+
const pendingResolvers = [];
|
|
82
83
|
entries.forEach(([routeId, value])=>{
|
|
83
84
|
if (!isDeferredDataLike(value)) return;
|
|
84
|
-
const
|
|
85
|
-
|
|
85
|
+
const serializedKeys = deferredScriptKeys ? deferredScriptKeys.get(routeId) ?? [] : value.pendingKeys ?? [];
|
|
86
|
+
serializedKeys.forEach((key)=>{
|
|
86
87
|
const tracked = value.data?.[key];
|
|
87
|
-
if (isPromiseLike(tracked)) tracked.then((val)=>
|
|
88
|
+
if (isPromiseLike(tracked)) pendingResolvers.push(Promise.resolve(tracked).then((val)=>{
|
|
89
|
+
emit(buildDeferredDataScript(nonce, [
|
|
88
90
|
routeId,
|
|
89
91
|
key,
|
|
90
92
|
val
|
|
91
|
-
]))
|
|
93
|
+
]));
|
|
94
|
+
}, (err)=>{
|
|
95
|
+
emit(buildDeferredDataScript(nonce, [
|
|
92
96
|
routeId,
|
|
93
97
|
key,
|
|
94
98
|
void 0,
|
|
95
99
|
toErrorInfo(err)
|
|
96
|
-
]))
|
|
100
|
+
]));
|
|
101
|
+
}));
|
|
97
102
|
});
|
|
98
103
|
});
|
|
104
|
+
return Promise.all(pendingResolvers).then(()=>void 0);
|
|
99
105
|
}
|
|
100
106
|
exports.buildDeferredDataScript = __webpack_exports__.buildDeferredDataScript;
|
|
101
107
|
exports.enqueueFromEntries = __webpack_exports__.enqueueFromEntries;
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
+
var define = (defs, kind)=>{
|
|
6
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
[kind]: defs[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
define(getters, "get");
|
|
12
|
+
define(values, "value");
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.r = (exports1)=>{
|
|
20
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
+
value: 'Module'
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
+
value: true
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
var __webpack_exports__ = {};
|
|
29
|
+
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
31
|
+
DeferredScriptOutputCoordinator: ()=>DeferredScriptOutputCoordinator
|
|
32
|
+
});
|
|
33
|
+
const constants_namespaceObject = require("@modern-js/utils/universal/constants");
|
|
34
|
+
const VOID_ELEMENTS = new Set([
|
|
35
|
+
'area',
|
|
36
|
+
'base',
|
|
37
|
+
'br',
|
|
38
|
+
'col',
|
|
39
|
+
'embed',
|
|
40
|
+
'hr',
|
|
41
|
+
'img',
|
|
42
|
+
'input',
|
|
43
|
+
'link',
|
|
44
|
+
'meta',
|
|
45
|
+
'param',
|
|
46
|
+
'source',
|
|
47
|
+
'track',
|
|
48
|
+
'wbr'
|
|
49
|
+
]);
|
|
50
|
+
const RAW_TEXT_ELEMENTS = new Set([
|
|
51
|
+
'iframe',
|
|
52
|
+
'noembed',
|
|
53
|
+
'noframes',
|
|
54
|
+
"script",
|
|
55
|
+
'style',
|
|
56
|
+
'textarea',
|
|
57
|
+
'title',
|
|
58
|
+
'xmp'
|
|
59
|
+
]);
|
|
60
|
+
const REACT_SEGMENT_ID_PATTERN = new RegExp(`^${constants_namespaceObject.SSR_HYDRATION_ID_PREFIX}S:[0-9a-f]+$`);
|
|
61
|
+
const TABLE_SEGMENT_CHILDREN = new Set([
|
|
62
|
+
'tbody',
|
|
63
|
+
'tr',
|
|
64
|
+
'colgroup'
|
|
65
|
+
]);
|
|
66
|
+
function isAsciiAlpha(char) {
|
|
67
|
+
return /[A-Za-z]/.test(char);
|
|
68
|
+
}
|
|
69
|
+
function isWhitespace(char) {
|
|
70
|
+
return /[\t\n\f\r ]/.test(char);
|
|
71
|
+
}
|
|
72
|
+
function getSuffix(value, pattern) {
|
|
73
|
+
const start = Math.max(0, value.length - pattern.length);
|
|
74
|
+
for(let index = start; index < value.length; index++){
|
|
75
|
+
const suffix = value.slice(index);
|
|
76
|
+
if (pattern.startsWith(suffix)) return suffix;
|
|
77
|
+
}
|
|
78
|
+
return '';
|
|
79
|
+
}
|
|
80
|
+
class DeferredScriptOutputCoordinator {
|
|
81
|
+
enqueueResolver(script) {
|
|
82
|
+
if (this.closed) return;
|
|
83
|
+
this.pendingResolvers.push(script);
|
|
84
|
+
this.flushResolvers();
|
|
85
|
+
}
|
|
86
|
+
markShellFinished() {
|
|
87
|
+
if (this.closed) return;
|
|
88
|
+
this.shellFinished = true;
|
|
89
|
+
this.flushResolvers();
|
|
90
|
+
}
|
|
91
|
+
writeReact(chunk) {
|
|
92
|
+
if (this.closed || !chunk) return;
|
|
93
|
+
this.flushResolvers();
|
|
94
|
+
let emittedUntil = 0;
|
|
95
|
+
for(let index = 0; index < chunk.length; index++){
|
|
96
|
+
const wasSafe = this.isSafeBoundary();
|
|
97
|
+
this.consume(chunk[index]);
|
|
98
|
+
if (!wasSafe && this.isSafeBoundary() && this.pendingResolvers.length) {
|
|
99
|
+
this.emit(chunk.slice(emittedUntil, index + 1));
|
|
100
|
+
emittedUntil = index + 1;
|
|
101
|
+
this.flushResolvers();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (emittedUntil < chunk.length) this.emit(chunk.slice(emittedUntil));
|
|
105
|
+
}
|
|
106
|
+
finish() {
|
|
107
|
+
if (this.closed) return;
|
|
108
|
+
this.flushResolvers();
|
|
109
|
+
this.closed = true;
|
|
110
|
+
if (this.pendingResolvers.length > 0) throw new Error("Cannot emit deferred resolver scripts because the React stream ended outside a safe HTML boundary.");
|
|
111
|
+
}
|
|
112
|
+
abort() {
|
|
113
|
+
this.closed = true;
|
|
114
|
+
this.pendingResolvers.length = 0;
|
|
115
|
+
}
|
|
116
|
+
isSafeBoundary() {
|
|
117
|
+
return this.shellFinished && 'data' === this.state && 0 === this.openElements.length && !this.awaitingContinuationProtocol;
|
|
118
|
+
}
|
|
119
|
+
flushResolvers() {
|
|
120
|
+
if (!this.isSafeBoundary() || 0 === this.pendingResolvers.length) return;
|
|
121
|
+
while(this.pendingResolvers.length > 0){
|
|
122
|
+
const resolver = this.pendingResolvers.shift();
|
|
123
|
+
if (resolver) this.emit(resolver);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
consume(char) {
|
|
127
|
+
switch(this.state){
|
|
128
|
+
case 'data':
|
|
129
|
+
if ('<' === char) this.state = 'tag-open';
|
|
130
|
+
return;
|
|
131
|
+
case 'tag-open':
|
|
132
|
+
if ('/' === char) {
|
|
133
|
+
this.currentTagName = '';
|
|
134
|
+
this.state = 'end-tag-name';
|
|
135
|
+
} else if ('!' === char) {
|
|
136
|
+
this.declarationPrefix = '';
|
|
137
|
+
this.state = 'markup-declaration';
|
|
138
|
+
} else if ('?' === char) this.state = 'bogus-comment';
|
|
139
|
+
else if (isAsciiAlpha(char)) {
|
|
140
|
+
this.startTag(char);
|
|
141
|
+
this.state = 'start-tag-name';
|
|
142
|
+
} else this.state = 'data';
|
|
143
|
+
return;
|
|
144
|
+
case 'start-tag-name':
|
|
145
|
+
if (isWhitespace(char)) this.state = 'before-attribute-name';
|
|
146
|
+
else if ('/' === char) this.state = 'self-closing-start-tag';
|
|
147
|
+
else if ('>' === char) this.completeStartTag(false);
|
|
148
|
+
else this.currentTagName += char.toLowerCase();
|
|
149
|
+
return;
|
|
150
|
+
case 'before-attribute-name':
|
|
151
|
+
if (isWhitespace(char)) return;
|
|
152
|
+
if ('/' === char) this.state = 'self-closing-start-tag';
|
|
153
|
+
else if ('>' === char) this.completeStartTag(false);
|
|
154
|
+
else {
|
|
155
|
+
this.startAttribute(char);
|
|
156
|
+
this.state = 'attribute-name';
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
case 'attribute-name':
|
|
160
|
+
if (isWhitespace(char)) this.state = 'after-attribute-name';
|
|
161
|
+
else if ('=' === char) {
|
|
162
|
+
this.currentAttributeHasValue = true;
|
|
163
|
+
this.state = 'before-attribute-value';
|
|
164
|
+
} else if ('/' === char) {
|
|
165
|
+
this.completeAttribute();
|
|
166
|
+
this.state = 'self-closing-start-tag';
|
|
167
|
+
} else if ('>' === char) this.completeStartTag(false);
|
|
168
|
+
else this.currentAttributeName += char.toLowerCase();
|
|
169
|
+
return;
|
|
170
|
+
case 'after-attribute-name':
|
|
171
|
+
if (isWhitespace(char)) return;
|
|
172
|
+
if ('=' === char) {
|
|
173
|
+
this.currentAttributeHasValue = true;
|
|
174
|
+
this.state = 'before-attribute-value';
|
|
175
|
+
} else if ('/' === char) {
|
|
176
|
+
this.completeAttribute();
|
|
177
|
+
this.state = 'self-closing-start-tag';
|
|
178
|
+
} else if ('>' === char) this.completeStartTag(false);
|
|
179
|
+
else {
|
|
180
|
+
this.completeAttribute();
|
|
181
|
+
this.startAttribute(char);
|
|
182
|
+
this.state = 'attribute-name';
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
case 'before-attribute-value':
|
|
186
|
+
if (isWhitespace(char)) return;
|
|
187
|
+
if ('"' === char) this.state = 'attribute-value-double-quoted';
|
|
188
|
+
else if ("'" === char) this.state = 'attribute-value-single-quoted';
|
|
189
|
+
else if ('>' === char) this.completeStartTag(false);
|
|
190
|
+
else {
|
|
191
|
+
this.currentAttributeValue += char;
|
|
192
|
+
this.state = 'attribute-value-unquoted';
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
case 'attribute-value-double-quoted':
|
|
196
|
+
if ('"' === char) {
|
|
197
|
+
this.completeAttribute();
|
|
198
|
+
this.state = 'before-attribute-name';
|
|
199
|
+
} else this.currentAttributeValue += char;
|
|
200
|
+
return;
|
|
201
|
+
case 'attribute-value-single-quoted':
|
|
202
|
+
if ("'" === char) {
|
|
203
|
+
this.completeAttribute();
|
|
204
|
+
this.state = 'before-attribute-name';
|
|
205
|
+
} else this.currentAttributeValue += char;
|
|
206
|
+
return;
|
|
207
|
+
case 'attribute-value-unquoted':
|
|
208
|
+
if (isWhitespace(char)) {
|
|
209
|
+
this.completeAttribute();
|
|
210
|
+
this.state = 'before-attribute-name';
|
|
211
|
+
} else if ('>' === char) this.completeStartTag(false);
|
|
212
|
+
else this.currentAttributeValue += char;
|
|
213
|
+
return;
|
|
214
|
+
case 'self-closing-start-tag':
|
|
215
|
+
if ('>' === char) this.completeStartTag(true);
|
|
216
|
+
else if (!isWhitespace(char)) {
|
|
217
|
+
this.startAttribute(char);
|
|
218
|
+
this.state = 'attribute-name';
|
|
219
|
+
}
|
|
220
|
+
return;
|
|
221
|
+
case 'end-tag-name':
|
|
222
|
+
if (isWhitespace(char)) this.state = 'after-end-tag-name';
|
|
223
|
+
else if ('>' === char) this.completeEndTag();
|
|
224
|
+
else this.currentTagName += char.toLowerCase();
|
|
225
|
+
return;
|
|
226
|
+
case 'after-end-tag-name':
|
|
227
|
+
if ('>' === char) this.completeEndTag();
|
|
228
|
+
return;
|
|
229
|
+
case 'markup-declaration':
|
|
230
|
+
if (this.declarationPrefix.length < 2 && '-' === char) {
|
|
231
|
+
this.declarationPrefix += char;
|
|
232
|
+
if ('--' === this.declarationPrefix) {
|
|
233
|
+
this.commentTail = '';
|
|
234
|
+
this.state = 'comment';
|
|
235
|
+
}
|
|
236
|
+
} else this.state = '>' === char ? 'data' : 'declaration';
|
|
237
|
+
return;
|
|
238
|
+
case 'declaration':
|
|
239
|
+
if ('>' === char) this.state = 'data';
|
|
240
|
+
return;
|
|
241
|
+
case 'comment':
|
|
242
|
+
this.commentTail = `${this.commentTail}${char}`.slice(-3);
|
|
243
|
+
if ('-->' === this.commentTail) this.state = 'data';
|
|
244
|
+
return;
|
|
245
|
+
case 'bogus-comment':
|
|
246
|
+
if ('>' === char) this.state = 'data';
|
|
247
|
+
return;
|
|
248
|
+
case 'raw-text':
|
|
249
|
+
this.consumeRawText(char);
|
|
250
|
+
return;
|
|
251
|
+
case 'raw-end-tag':
|
|
252
|
+
if ('>' === char) this.completeRawTextEndTag();
|
|
253
|
+
else if (!isWhitespace(char)) {
|
|
254
|
+
this.state = 'raw-text';
|
|
255
|
+
this.rawTextSearch = getSuffix(`${this.rawTextSearch}${char.toLowerCase()}`, `</${this.rawTextElement}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
startTag(char) {
|
|
260
|
+
this.currentTagName = char.toLowerCase();
|
|
261
|
+
this.currentAttributes = new Map();
|
|
262
|
+
this.currentAttributeName = '';
|
|
263
|
+
this.currentAttributeValue = '';
|
|
264
|
+
this.currentAttributeHasValue = false;
|
|
265
|
+
}
|
|
266
|
+
startAttribute(char) {
|
|
267
|
+
this.currentAttributeName = char.toLowerCase();
|
|
268
|
+
this.currentAttributeValue = '';
|
|
269
|
+
this.currentAttributeHasValue = false;
|
|
270
|
+
}
|
|
271
|
+
completeAttribute() {
|
|
272
|
+
if (!this.currentAttributeName) return;
|
|
273
|
+
this.currentAttributes.set(this.currentAttributeName, this.currentAttributeHasValue ? this.currentAttributeValue : true);
|
|
274
|
+
this.currentAttributeName = '';
|
|
275
|
+
this.currentAttributeValue = '';
|
|
276
|
+
this.currentAttributeHasValue = false;
|
|
277
|
+
}
|
|
278
|
+
completeStartTag(selfClosing) {
|
|
279
|
+
this.completeAttribute();
|
|
280
|
+
const tagName = this.currentTagName;
|
|
281
|
+
const id = this.currentAttributes.get('id');
|
|
282
|
+
const hasReactSegmentId = 'string' == typeof id && REACT_SEGMENT_ID_PATTERN.test(id);
|
|
283
|
+
const hasHiddenAttribute = this.currentAttributes.has('hidden');
|
|
284
|
+
const isHiddenSegmentTable = 'table' === tagName && hasHiddenAttribute && !hasReactSegmentId;
|
|
285
|
+
const isTableSegmentChild = hasReactSegmentId && TABLE_SEGMENT_CHILDREN.has(tagName) && this.openElements[this.openElements.length - 1]?.isSegmentTableWrapper === true;
|
|
286
|
+
const isContinuationContainer = hasReactSegmentId && ('div' === tagName && hasHiddenAttribute || ('svg' === tagName || 'math' === tagName) && void 0 !== id && 'true' === this.currentAttributes.get('aria-hidden') && 'display:none' === this.currentAttributes.get('style') || 'table' === tagName && hasHiddenAttribute || isTableSegmentChild);
|
|
287
|
+
this.continuationProtocolScript = "script" === tagName && this.awaitingContinuationProtocol;
|
|
288
|
+
this.continuationProtocolTail = '';
|
|
289
|
+
this.hasContinuationProtocolCall = false;
|
|
290
|
+
if (!selfClosing && !VOID_ELEMENTS.has(tagName)) this.openElements.push({
|
|
291
|
+
tagName,
|
|
292
|
+
isContinuationContainer,
|
|
293
|
+
isSegmentTableWrapper: isHiddenSegmentTable
|
|
294
|
+
});
|
|
295
|
+
this.currentTagName = '';
|
|
296
|
+
this.currentAttributes = new Map();
|
|
297
|
+
this.currentAttributeName = '';
|
|
298
|
+
this.currentAttributeValue = '';
|
|
299
|
+
this.currentAttributeHasValue = false;
|
|
300
|
+
if (!selfClosing && RAW_TEXT_ELEMENTS.has(tagName)) {
|
|
301
|
+
this.rawTextElement = tagName;
|
|
302
|
+
this.rawTextSearch = '';
|
|
303
|
+
this.state = 'raw-text';
|
|
304
|
+
} else this.state = 'data';
|
|
305
|
+
}
|
|
306
|
+
completeEndTag() {
|
|
307
|
+
this.closeOpenElement(this.currentTagName);
|
|
308
|
+
this.currentTagName = '';
|
|
309
|
+
this.state = 'data';
|
|
310
|
+
}
|
|
311
|
+
consumeRawText(char) {
|
|
312
|
+
const rawTextElement = this.rawTextElement;
|
|
313
|
+
if (!rawTextElement) {
|
|
314
|
+
this.state = 'data';
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const endTagPrefix = `</${rawTextElement}`;
|
|
318
|
+
if (this.continuationProtocolScript) {
|
|
319
|
+
this.continuationProtocolTail = `${this.continuationProtocolTail}${char}`.slice(-4);
|
|
320
|
+
if (/\$(?:RC|RS|RX|RB|RR)\b/.test(this.continuationProtocolTail)) this.hasContinuationProtocolCall = true;
|
|
321
|
+
}
|
|
322
|
+
this.rawTextSearch = getSuffix(`${this.rawTextSearch}${char.toLowerCase()}`, endTagPrefix);
|
|
323
|
+
if (this.rawTextSearch === endTagPrefix) this.state = 'raw-end-tag';
|
|
324
|
+
}
|
|
325
|
+
completeRawTextEndTag() {
|
|
326
|
+
const rawTextElement = this.rawTextElement;
|
|
327
|
+
if (rawTextElement) this.closeOpenElement(rawTextElement);
|
|
328
|
+
if ("script" === rawTextElement && this.continuationProtocolScript && this.hasContinuationProtocolCall) this.awaitingContinuationProtocol = false;
|
|
329
|
+
this.rawTextElement = void 0;
|
|
330
|
+
this.rawTextSearch = '';
|
|
331
|
+
this.continuationProtocolScript = false;
|
|
332
|
+
this.continuationProtocolTail = '';
|
|
333
|
+
this.hasContinuationProtocolCall = false;
|
|
334
|
+
this.state = 'data';
|
|
335
|
+
}
|
|
336
|
+
closeOpenElement(tagName) {
|
|
337
|
+
const matchingIndex = this.openElements.map((element)=>element.tagName).lastIndexOf(tagName);
|
|
338
|
+
if (-1 === matchingIndex) return;
|
|
339
|
+
const closedElements = this.openElements.splice(matchingIndex);
|
|
340
|
+
const closedContinuation = closedElements.some((element)=>element.isContinuationContainer);
|
|
341
|
+
if (closedContinuation) this.awaitingContinuationProtocol = true;
|
|
342
|
+
}
|
|
343
|
+
constructor(emit){
|
|
344
|
+
this.emit = emit;
|
|
345
|
+
this.pendingResolvers = [];
|
|
346
|
+
this.openElements = [];
|
|
347
|
+
this.shellFinished = false;
|
|
348
|
+
this.closed = false;
|
|
349
|
+
this.state = 'data';
|
|
350
|
+
this.currentTagName = '';
|
|
351
|
+
this.currentAttributes = new Map();
|
|
352
|
+
this.currentAttributeName = '';
|
|
353
|
+
this.currentAttributeValue = '';
|
|
354
|
+
this.currentAttributeHasValue = false;
|
|
355
|
+
this.declarationPrefix = '';
|
|
356
|
+
this.commentTail = '';
|
|
357
|
+
this.rawTextSearch = '';
|
|
358
|
+
this.continuationProtocolScript = false;
|
|
359
|
+
this.continuationProtocolTail = '';
|
|
360
|
+
this.hasContinuationProtocolCall = false;
|
|
361
|
+
this.awaitingContinuationProtocol = false;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
exports.DeferredScriptOutputCoordinator = __webpack_exports__.DeferredScriptOutputCoordinator;
|
|
365
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
366
|
+
"DeferredScriptOutputCoordinator"
|
|
367
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
368
|
+
Object.defineProperty(exports, '__esModule', {
|
|
369
|
+
value: true
|
|
370
|
+
});
|
|
@@ -45,7 +45,8 @@ const DeferredDataScripts = (props)=>{
|
|
|
45
45
|
}, []);
|
|
46
46
|
const deferredScripts = (0, external_react_namespaceObject.useMemo)(()=>{
|
|
47
47
|
if (!staticContext) return null;
|
|
48
|
-
const
|
|
48
|
+
const requestStorage = node_namespaceObject.storage.useContext();
|
|
49
|
+
const activeDeferreds = requestStorage.activeDeferreds;
|
|
49
50
|
const _ROUTER_DATA = {
|
|
50
51
|
loaderData: staticContext.loaderData,
|
|
51
52
|
errors: (0, external_utils_js_namespaceObject.serializeErrors)(staticContext.errors)
|
|
@@ -58,6 +59,7 @@ const DeferredDataScripts = (props)=>{
|
|
|
58
59
|
const deferredDataScripts = [];
|
|
59
60
|
const initialScripts = Array.from(activeDeferreds.entries()).map(([routeId, deferredData])=>{
|
|
60
61
|
const pendingKeys = new Set(deferredData.pendingKeys);
|
|
62
|
+
requestStorage.deferredScriptKeys?.set(routeId, Array.from(pendingKeys));
|
|
61
63
|
const { deferredKeys } = deferredData;
|
|
62
64
|
const deferredKeyPromiseManifests = deferredKeys.map((key)=>{
|
|
63
65
|
if (pendingKeys.has(key)) return {
|