@modern-js/runtime 2.68.10 → 2.68.12
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/stream/createReadableStream.js +27 -0
- package/dist/cjs/core/server/stream/createReadableStream.worker.js +23 -0
- package/dist/cjs/core/server/stream/deferredScript.js +106 -0
- package/dist/cjs/router/runtime/DeferredDataScripts.node.js +34 -92
- package/dist/esm/core/server/stream/createReadableStream.js +47 -1
- package/dist/esm/core/server/stream/createReadableStream.worker.js +44 -1
- package/dist/esm/core/server/stream/deferredScript.js +85 -0
- package/dist/esm/router/runtime/DeferredDataScripts.node.js +34 -96
- package/dist/esm-node/core/server/stream/createReadableStream.js +28 -1
- package/dist/esm-node/core/server/stream/createReadableStream.worker.js +23 -0
- package/dist/esm-node/core/server/stream/deferredScript.js +76 -0
- package/dist/esm-node/router/runtime/DeferredDataScripts.node.js +36 -94
- package/dist/types/core/server/stream/deferredScript.d.ts +15 -0
- package/package.json +12 -12
|
@@ -37,6 +37,8 @@ var import_isbot = __toESM(require("isbot"));
|
|
|
37
37
|
var import_styled_components = require("styled-components");
|
|
38
38
|
var import_common = require("../../../common");
|
|
39
39
|
var import_constants = require("../../constants");
|
|
40
|
+
var import_monitors = require("../../context/monitors");
|
|
41
|
+
var import_deferredScript = require("./deferredScript");
|
|
40
42
|
var import_shared = require("./shared");
|
|
41
43
|
var import_template = require("./template");
|
|
42
44
|
const createReadableStreamFromElement = async (request, rootElement, options) => {
|
|
@@ -66,6 +68,7 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
66
68
|
entryName,
|
|
67
69
|
styledComponentsStyleTags
|
|
68
70
|
}).then(({ shellAfter, shellBefore }) => {
|
|
71
|
+
const pendingScripts = [];
|
|
69
72
|
const body = new import_stream.Transform({
|
|
70
73
|
transform(chunk, _encoding, callback) {
|
|
71
74
|
try {
|
|
@@ -76,6 +79,11 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
76
79
|
concatedChunk = concatedChunk.replace(import_common.ESCAPED_SHELL_STREAM_END_MARK, "");
|
|
77
80
|
shellChunkStatus = import_shared.ShellChunkStatus.FINISH;
|
|
78
81
|
this.push(`${shellBefore}${concatedChunk}${shellAfter}`);
|
|
82
|
+
if (pendingScripts.length > 0) {
|
|
83
|
+
for (const s of pendingScripts) {
|
|
84
|
+
this.push(s);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
79
87
|
}
|
|
80
88
|
} else {
|
|
81
89
|
this.push(chunk);
|
|
@@ -96,6 +104,25 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
96
104
|
const styledStream = sheet.interleaveWithNodeStream(passThrough);
|
|
97
105
|
reactStreamingPipe(passThrough);
|
|
98
106
|
styledStream.pipe(body);
|
|
107
|
+
try {
|
|
108
|
+
var _storage_useContext, _options_runtimeContext, _storageContext_activeDeferreds;
|
|
109
|
+
const storageContext = (_storage_useContext = import_node.storage.useContext) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.call(import_node.storage);
|
|
110
|
+
const routerContext = (_options_runtimeContext = options.runtimeContext) === null || _options_runtimeContext === void 0 ? void 0 : _options_runtimeContext.routerContext;
|
|
111
|
+
const entries = (storageContext === null || storageContext === void 0 ? void 0 : storageContext.activeDeferreds) instanceof Map && ((_storageContext_activeDeferreds = storageContext.activeDeferreds) === null || _storageContext_activeDeferreds === void 0 ? void 0 : _storageContext_activeDeferreds.size) > 0 ? Array.from(storageContext.activeDeferreds.entries()) : (routerContext === null || routerContext === void 0 ? void 0 : routerContext.activeDeferreds) ? Object.entries(routerContext.activeDeferreds) : [];
|
|
112
|
+
if (entries.length > 0) {
|
|
113
|
+
const enqueueScript = (s) => {
|
|
114
|
+
if (shellChunkStatus === import_shared.ShellChunkStatus.FINISH) {
|
|
115
|
+
body.write(s);
|
|
116
|
+
} else {
|
|
117
|
+
pendingScripts.push(s);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
(0, import_deferredScript.enqueueFromEntries)(entries, config.nonce, (s) => enqueueScript(s));
|
|
121
|
+
}
|
|
122
|
+
} catch (err) {
|
|
123
|
+
const monitors = (0, import_monitors.getMonitors)();
|
|
124
|
+
monitors.error("cannot inject router data script", err);
|
|
125
|
+
}
|
|
99
126
|
});
|
|
100
127
|
},
|
|
101
128
|
onShellError(error) {
|
|
@@ -32,9 +32,11 @@ __export(createReadableStream_worker_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(createReadableStream_worker_exports);
|
|
34
34
|
var import_ssr = require("@modern-js/render/ssr");
|
|
35
|
+
var import_node = require("@modern-js/runtime-utils/node");
|
|
35
36
|
var import_isbot = __toESM(require("isbot"));
|
|
36
37
|
var import_common = require("../../../common");
|
|
37
38
|
var import_constants = require("../../constants");
|
|
39
|
+
var import_deferredScript = require("./deferredScript");
|
|
38
40
|
var import_shared = require("./shared");
|
|
39
41
|
var import_template = require("./template");
|
|
40
42
|
const createReadableStreamFromElement = async (request, rootElement, options) => {
|
|
@@ -74,6 +76,21 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
74
76
|
const reader = readableOriginal.getReader();
|
|
75
77
|
const stream = new ReadableStream({
|
|
76
78
|
start(controller) {
|
|
79
|
+
var _storage_useContext, _options_runtimeContext, _storageContext_activeDeferreds;
|
|
80
|
+
const pendingScripts = [];
|
|
81
|
+
const enqueueScript = (script) => {
|
|
82
|
+
if (shellChunkStatus === import_shared.ShellChunkStatus.FINISH) {
|
|
83
|
+
controller.enqueue((0, import_shared.encodeForWebStream)(script));
|
|
84
|
+
} else {
|
|
85
|
+
pendingScripts.push(script);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const storageContext = (_storage_useContext = import_node.storage.useContext) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.call(import_node.storage);
|
|
89
|
+
const routerContext = (_options_runtimeContext = options.runtimeContext) === null || _options_runtimeContext === void 0 ? void 0 : _options_runtimeContext.routerContext;
|
|
90
|
+
const entries = (storageContext === null || storageContext === void 0 ? void 0 : storageContext.activeDeferreds) instanceof Map && ((_storageContext_activeDeferreds = storageContext.activeDeferreds) === null || _storageContext_activeDeferreds === void 0 ? void 0 : _storageContext_activeDeferreds.size) > 0 ? Array.from(storageContext.activeDeferreds.entries()) : (routerContext === null || routerContext === void 0 ? void 0 : routerContext.activeDeferreds) ? Object.entries(routerContext.activeDeferreds) : [];
|
|
91
|
+
if (entries.length > 0) {
|
|
92
|
+
(0, import_deferredScript.enqueueFromEntries)(entries, config.nonce, (s) => enqueueScript(s));
|
|
93
|
+
}
|
|
77
94
|
async function push() {
|
|
78
95
|
const { done, value } = await reader.read();
|
|
79
96
|
if (done) {
|
|
@@ -88,6 +105,12 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
88
105
|
concatedChunk = concatedChunk.replace(import_common.ESCAPED_SHELL_STREAM_END_MARK, "");
|
|
89
106
|
shellChunkStatus = import_shared.ShellChunkStatus.FINISH;
|
|
90
107
|
controller.enqueue((0, import_shared.encodeForWebStream)(`${shellBefore}${concatedChunk}${shellAfter}`));
|
|
108
|
+
if (pendingScripts.length > 0) {
|
|
109
|
+
for (const s of pendingScripts) {
|
|
110
|
+
controller.enqueue((0, import_shared.encodeForWebStream)(s));
|
|
111
|
+
}
|
|
112
|
+
pendingScripts.length = 0;
|
|
113
|
+
}
|
|
91
114
|
}
|
|
92
115
|
} else {
|
|
93
116
|
controller.enqueue(value);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var deferredScript_exports = {};
|
|
20
|
+
__export(deferredScript_exports, {
|
|
21
|
+
buildDeferredDataScript: () => buildDeferredDataScript,
|
|
22
|
+
enqueueFromEntries: () => enqueueFromEntries,
|
|
23
|
+
escapeAttr: () => escapeAttr,
|
|
24
|
+
isDeferredDataLike: () => isDeferredDataLike,
|
|
25
|
+
isPromiseLike: () => isPromiseLike,
|
|
26
|
+
isRecord: () => isRecord,
|
|
27
|
+
toErrorInfo: () => toErrorInfo
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(deferredScript_exports);
|
|
30
|
+
var import_constants = require("../../../router/runtime/constants");
|
|
31
|
+
const HTML_ESCAPE_MAP = {
|
|
32
|
+
"&": "&",
|
|
33
|
+
"<": "<",
|
|
34
|
+
">": ">",
|
|
35
|
+
'"': """,
|
|
36
|
+
"'": "'"
|
|
37
|
+
};
|
|
38
|
+
function escapeAttr(value) {
|
|
39
|
+
return value.replace(/[&<>"']/g, (ch) => HTML_ESCAPE_MAP[ch]);
|
|
40
|
+
}
|
|
41
|
+
function isRecord(v) {
|
|
42
|
+
return typeof v === "object" && v !== null;
|
|
43
|
+
}
|
|
44
|
+
function isDeferredDataLike(v) {
|
|
45
|
+
if (!isRecord(v))
|
|
46
|
+
return false;
|
|
47
|
+
const hasPending = "pendingKeys" in v && Array.isArray(v.pendingKeys);
|
|
48
|
+
const hasData = "data" in v && isRecord(v.data);
|
|
49
|
+
return hasPending && hasData;
|
|
50
|
+
}
|
|
51
|
+
function isPromiseLike(value) {
|
|
52
|
+
return !!value && typeof value.then === "function";
|
|
53
|
+
}
|
|
54
|
+
function toErrorInfo(error) {
|
|
55
|
+
if (error && typeof error === "object") {
|
|
56
|
+
const maybeMsg = error.message;
|
|
57
|
+
const maybeStack = error.stack;
|
|
58
|
+
return {
|
|
59
|
+
message: typeof maybeMsg === "string" ? maybeMsg : String(maybeMsg !== null && maybeMsg !== void 0 ? maybeMsg : error),
|
|
60
|
+
stack: process.env.NODE_ENV !== "production" ? maybeStack : void 0
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
message: String(error)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function buildDeferredDataScript(nonce, args) {
|
|
68
|
+
const payload = JSON.stringify(args);
|
|
69
|
+
const escaped = escapeAttr(payload);
|
|
70
|
+
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
71
|
+
return `<script async${nonceAttr} data-fn-name="r" data-script-src="modern-run-router-data-fn" data-fn-args='${escaped}' suppressHydrationWarning>${import_constants.runRouterDataFnStr}</script>`;
|
|
72
|
+
}
|
|
73
|
+
function enqueueFromEntries(entries, nonce, emit) {
|
|
74
|
+
entries.forEach(([routeId, value]) => {
|
|
75
|
+
if (!isDeferredDataLike(value))
|
|
76
|
+
return;
|
|
77
|
+
var _value_pendingKeys;
|
|
78
|
+
const pendingKeys = new Set((_value_pendingKeys = value.pendingKeys) !== null && _value_pendingKeys !== void 0 ? _value_pendingKeys : []);
|
|
79
|
+
pendingKeys.forEach((key) => {
|
|
80
|
+
var _value_data;
|
|
81
|
+
const tracked = (_value_data = value.data) === null || _value_data === void 0 ? void 0 : _value_data[key];
|
|
82
|
+
if (isPromiseLike(tracked)) {
|
|
83
|
+
tracked.then((val) => emit(buildDeferredDataScript(nonce, [
|
|
84
|
+
routeId,
|
|
85
|
+
key,
|
|
86
|
+
val
|
|
87
|
+
])), (err) => emit(buildDeferredDataScript(nonce, [
|
|
88
|
+
routeId,
|
|
89
|
+
key,
|
|
90
|
+
void 0,
|
|
91
|
+
toErrorInfo(err)
|
|
92
|
+
])));
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
98
|
+
0 && (module.exports = {
|
|
99
|
+
buildDeferredDataScript,
|
|
100
|
+
enqueueFromEntries,
|
|
101
|
+
escapeAttr,
|
|
102
|
+
isDeferredDataLike,
|
|
103
|
+
isPromiseLike,
|
|
104
|
+
isRecord,
|
|
105
|
+
toErrorInfo
|
|
106
|
+
});
|
|
@@ -23,7 +23,6 @@ __export(DeferredDataScripts_node_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(DeferredDataScripts_node_exports);
|
|
24
24
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
25
|
var import_node = require("@modern-js/runtime-utils/node");
|
|
26
|
-
var import_router = require("@modern-js/runtime-utils/router");
|
|
27
26
|
var import_react = require("react");
|
|
28
27
|
var import_constants = require("../../core/constants");
|
|
29
28
|
var import_constants2 = require("./constants");
|
|
@@ -57,12 +56,6 @@ const DeferredDataScripts = (props) => {
|
|
|
57
56
|
const { deferredKeys } = deferredData;
|
|
58
57
|
const deferredKeyPromiseManifests = deferredKeys.map((key) => {
|
|
59
58
|
if (pendingKeys.has(key)) {
|
|
60
|
-
deferredDataScripts.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeferredDataScript, {
|
|
61
|
-
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
62
|
-
data: deferredData.data[key],
|
|
63
|
-
dataKey: key,
|
|
64
|
-
routeId
|
|
65
|
-
}, `${routeId} | ${key}`));
|
|
66
59
|
return {
|
|
67
60
|
key,
|
|
68
61
|
routerDataFnName: "s",
|
|
@@ -120,91 +113,40 @@ const DeferredDataScripts = (props) => {
|
|
|
120
113
|
if (!deferredScripts) {
|
|
121
114
|
return null;
|
|
122
115
|
}
|
|
123
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
124
|
-
children:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}),
|
|
158
|
-
!hydratedRef.current && deferredScripts[3]
|
|
159
|
-
]
|
|
160
|
-
});
|
|
161
|
-
};
|
|
162
|
-
const DeferredDataScript = ({ data, routeId, dataKey, nonce }) => {
|
|
163
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, {
|
|
164
|
-
children: typeof document === "undefined" && data && dataKey && routeId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_router.Await, {
|
|
165
|
-
resolve: data,
|
|
166
|
-
errorElement: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorDeferredDataScript, {
|
|
167
|
-
routeId,
|
|
168
|
-
dataKey,
|
|
169
|
-
nonce
|
|
170
|
-
}),
|
|
171
|
-
children: (data2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", {
|
|
172
|
-
async: true,
|
|
173
|
-
nonce,
|
|
174
|
-
"data-fn-name": "r",
|
|
175
|
-
"data-script-src": "modern-run-router-data-fn",
|
|
176
|
-
"data-fn-args": `${JSON.stringify([
|
|
177
|
-
routeId,
|
|
178
|
-
dataKey,
|
|
179
|
-
data2
|
|
180
|
-
])}`,
|
|
181
|
-
suppressHydrationWarning: true,
|
|
182
|
-
dangerouslySetInnerHTML: {
|
|
183
|
-
__html: import_constants2.runRouterDataFnStr
|
|
184
|
-
}
|
|
185
|
-
})
|
|
186
|
-
}) : null
|
|
187
|
-
});
|
|
188
|
-
};
|
|
189
|
-
const ErrorDeferredDataScript = ({ routeId, dataKey, nonce }) => {
|
|
190
|
-
const error = (0, import_router.useAsyncError)();
|
|
191
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", {
|
|
192
|
-
"data-fn-name": "r",
|
|
193
|
-
"data-script-src": "modern-run-router-data-fn",
|
|
194
|
-
"data-fn-args": `${JSON.stringify([
|
|
195
|
-
routeId,
|
|
196
|
-
dataKey,
|
|
197
|
-
void 0,
|
|
198
|
-
{
|
|
199
|
-
message: error.message,
|
|
200
|
-
stack: error.stack
|
|
201
|
-
}
|
|
202
|
-
])}`,
|
|
203
|
-
nonce,
|
|
204
|
-
suppressHydrationWarning: true,
|
|
205
|
-
dangerouslySetInnerHTML: {
|
|
206
|
-
__html: import_constants2.runRouterDataFnStr
|
|
207
|
-
}
|
|
116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {
|
|
117
|
+
children: !hydratedRef.current && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
|
|
118
|
+
children: [
|
|
119
|
+
deferredScripts[0].length !== 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", {
|
|
120
|
+
type: "application/json",
|
|
121
|
+
id: import_constants.ROUTER_DATA_JSON_ID,
|
|
122
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
123
|
+
suppressHydrationWarning: true,
|
|
124
|
+
dangerouslySetInnerHTML: {
|
|
125
|
+
__html: deferredScripts[0]
|
|
126
|
+
}
|
|
127
|
+
}),
|
|
128
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", {
|
|
129
|
+
async: true,
|
|
130
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
131
|
+
"data-script-src": "modern-inline",
|
|
132
|
+
suppressHydrationWarning: true,
|
|
133
|
+
dangerouslySetInnerHTML: {
|
|
134
|
+
__html: deferredScripts[1]
|
|
135
|
+
}
|
|
136
|
+
}),
|
|
137
|
+
deferredScripts[2].map(({ fnName, fnArgs, fnRun, fnScriptSrc }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", {
|
|
138
|
+
async: true,
|
|
139
|
+
"data-script-src": fnScriptSrc,
|
|
140
|
+
"data-fn-name": fnName,
|
|
141
|
+
"data-fn-args": JSON.stringify(fnArgs),
|
|
142
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
143
|
+
suppressHydrationWarning: true,
|
|
144
|
+
dangerouslySetInnerHTML: {
|
|
145
|
+
__html: fnRun
|
|
146
|
+
}
|
|
147
|
+
}, fnName))
|
|
148
|
+
]
|
|
149
|
+
})
|
|
208
150
|
});
|
|
209
151
|
};
|
|
210
152
|
var DeferredDataScripts_node_default = DeferredDataScripts;
|
|
@@ -3,11 +3,13 @@ import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
|
3
3
|
import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
|
|
4
4
|
import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
|
|
5
5
|
import { PassThrough, Transform } from "stream";
|
|
6
|
-
import { createReadableStreamFromReadable } from "@modern-js/runtime-utils/node";
|
|
6
|
+
import { createReadableStreamFromReadable, storage } from "@modern-js/runtime-utils/node";
|
|
7
7
|
import checkIsBot from "isbot";
|
|
8
8
|
import { ServerStyleSheet } from "styled-components";
|
|
9
9
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common";
|
|
10
10
|
import { RenderLevel } from "../../constants";
|
|
11
|
+
import { getMonitors } from "../../context/monitors";
|
|
12
|
+
import { enqueueFromEntries } from "./deferredScript";
|
|
11
13
|
import { ShellChunkStatus, getReadableStreamFromString } from "./shared";
|
|
12
14
|
import { getTemplates } from "./template";
|
|
13
15
|
var createReadableStreamFromElement = function() {
|
|
@@ -51,6 +53,7 @@ var createReadableStreamFromElement = function() {
|
|
|
51
53
|
styledComponentsStyleTags
|
|
52
54
|
}).then(function(param) {
|
|
53
55
|
var shellAfter = param.shellAfter, shellBefore = param.shellBefore;
|
|
56
|
+
var pendingScripts = [];
|
|
54
57
|
var body = new Transform({
|
|
55
58
|
transform: function transform(chunk, _encoding, callback) {
|
|
56
59
|
try {
|
|
@@ -61,6 +64,28 @@ var createReadableStreamFromElement = function() {
|
|
|
61
64
|
concatedChunk = concatedChunk.replace(ESCAPED_SHELL_STREAM_END_MARK, "");
|
|
62
65
|
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
63
66
|
this.push("".concat(shellBefore).concat(concatedChunk).concat(shellAfter));
|
|
67
|
+
if (pendingScripts.length > 0) {
|
|
68
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
|
|
69
|
+
try {
|
|
70
|
+
for (var _iterator = pendingScripts[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
71
|
+
var s = _step.value;
|
|
72
|
+
this.push(s);
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
_didIteratorError = true;
|
|
76
|
+
_iteratorError = err;
|
|
77
|
+
} finally {
|
|
78
|
+
try {
|
|
79
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
80
|
+
_iterator.return();
|
|
81
|
+
}
|
|
82
|
+
} finally {
|
|
83
|
+
if (_didIteratorError) {
|
|
84
|
+
throw _iteratorError;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
64
89
|
}
|
|
65
90
|
} else {
|
|
66
91
|
this.push(chunk);
|
|
@@ -81,6 +106,27 @@ var createReadableStreamFromElement = function() {
|
|
|
81
106
|
var styledStream = sheet.interleaveWithNodeStream(passThrough);
|
|
82
107
|
reactStreamingPipe(passThrough);
|
|
83
108
|
styledStream.pipe(body);
|
|
109
|
+
try {
|
|
110
|
+
var _storage_useContext, _options_runtimeContext, _storageContext_activeDeferreds;
|
|
111
|
+
var storageContext = (_storage_useContext = storage.useContext) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.call(storage);
|
|
112
|
+
var routerContext = (_options_runtimeContext = options.runtimeContext) === null || _options_runtimeContext === void 0 ? void 0 : _options_runtimeContext.routerContext;
|
|
113
|
+
var entries = _instanceof(storageContext === null || storageContext === void 0 ? void 0 : storageContext.activeDeferreds, Map) && ((_storageContext_activeDeferreds = storageContext.activeDeferreds) === null || _storageContext_activeDeferreds === void 0 ? void 0 : _storageContext_activeDeferreds.size) > 0 ? Array.from(storageContext.activeDeferreds.entries()) : (routerContext === null || routerContext === void 0 ? void 0 : routerContext.activeDeferreds) ? Object.entries(routerContext.activeDeferreds) : [];
|
|
114
|
+
if (entries.length > 0) {
|
|
115
|
+
var enqueueScript = function(s) {
|
|
116
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) {
|
|
117
|
+
body.write(s);
|
|
118
|
+
} else {
|
|
119
|
+
pendingScripts.push(s);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
enqueueFromEntries(entries, config.nonce, function(s) {
|
|
123
|
+
return enqueueScript(s);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
} catch (err) {
|
|
127
|
+
var monitors = getMonitors();
|
|
128
|
+
monitors.error("cannot inject router data script", err);
|
|
129
|
+
}
|
|
84
130
|
});
|
|
85
131
|
}), _define_property(_obj, "onShellError", function onShellError(error) {
|
|
86
132
|
renderLevel = RenderLevel.CLIENT_RENDER;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
|
|
2
|
+
import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
|
|
2
3
|
import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
|
|
3
4
|
import { renderSSRStream } from "@modern-js/render/ssr";
|
|
5
|
+
import { storage } from "@modern-js/runtime-utils/node";
|
|
4
6
|
import checkIsBot from "isbot";
|
|
5
7
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common";
|
|
6
8
|
import { RenderLevel } from "../../constants";
|
|
9
|
+
import { enqueueFromEntries } from "./deferredScript";
|
|
7
10
|
import { ShellChunkStatus, encodeForWebStream, getReadableStreamFromString } from "./shared";
|
|
8
11
|
import { getTemplates } from "./template";
|
|
9
12
|
var createReadableStreamFromElement = function() {
|
|
@@ -74,12 +77,29 @@ var createReadableStreamFromElement = function() {
|
|
|
74
77
|
reader = readableOriginal.getReader();
|
|
75
78
|
stream = new ReadableStream({
|
|
76
79
|
start: function start(controller) {
|
|
80
|
+
var _storage_useContext, _options_runtimeContext, _storageContext_activeDeferreds;
|
|
81
|
+
var pendingScripts = [];
|
|
82
|
+
var enqueueScript = function(script) {
|
|
83
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) {
|
|
84
|
+
controller.enqueue(encodeForWebStream(script));
|
|
85
|
+
} else {
|
|
86
|
+
pendingScripts.push(script);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
var storageContext = (_storage_useContext = storage.useContext) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.call(storage);
|
|
90
|
+
var routerContext = (_options_runtimeContext = options.runtimeContext) === null || _options_runtimeContext === void 0 ? void 0 : _options_runtimeContext.routerContext;
|
|
91
|
+
var entries = _instanceof(storageContext === null || storageContext === void 0 ? void 0 : storageContext.activeDeferreds, Map) && ((_storageContext_activeDeferreds = storageContext.activeDeferreds) === null || _storageContext_activeDeferreds === void 0 ? void 0 : _storageContext_activeDeferreds.size) > 0 ? Array.from(storageContext.activeDeferreds.entries()) : (routerContext === null || routerContext === void 0 ? void 0 : routerContext.activeDeferreds) ? Object.entries(routerContext.activeDeferreds) : [];
|
|
92
|
+
if (entries.length > 0) {
|
|
93
|
+
enqueueFromEntries(entries, config.nonce, function(s) {
|
|
94
|
+
return enqueueScript(s);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
77
97
|
function push() {
|
|
78
98
|
return _push.apply(this, arguments);
|
|
79
99
|
}
|
|
80
100
|
function _push() {
|
|
81
101
|
_push = _async_to_generator(function() {
|
|
82
|
-
var _ref3, done, value, chunk, concatedChunk;
|
|
102
|
+
var _ref3, done, value, chunk, concatedChunk, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, s;
|
|
83
103
|
return _ts_generator(this, function(_state2) {
|
|
84
104
|
switch (_state2.label) {
|
|
85
105
|
case 0:
|
|
@@ -103,6 +123,29 @@ var createReadableStreamFromElement = function() {
|
|
|
103
123
|
concatedChunk = concatedChunk.replace(ESCAPED_SHELL_STREAM_END_MARK, "");
|
|
104
124
|
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
105
125
|
controller.enqueue(encodeForWebStream("".concat(shellBefore).concat(concatedChunk).concat(shellAfter)));
|
|
126
|
+
if (pendingScripts.length > 0) {
|
|
127
|
+
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
|
|
128
|
+
try {
|
|
129
|
+
for (_iterator = pendingScripts[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
130
|
+
s = _step.value;
|
|
131
|
+
controller.enqueue(encodeForWebStream(s));
|
|
132
|
+
}
|
|
133
|
+
} catch (err) {
|
|
134
|
+
_didIteratorError = true;
|
|
135
|
+
_iteratorError = err;
|
|
136
|
+
} finally {
|
|
137
|
+
try {
|
|
138
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
139
|
+
_iterator.return();
|
|
140
|
+
}
|
|
141
|
+
} finally {
|
|
142
|
+
if (_didIteratorError) {
|
|
143
|
+
throw _iteratorError;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
pendingScripts.length = 0;
|
|
148
|
+
}
|
|
106
149
|
}
|
|
107
150
|
} else {
|
|
108
151
|
controller.enqueue(value);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
|
|
2
|
+
import { _ as _type_of } from "@swc/helpers/_/_type_of";
|
|
3
|
+
import { runRouterDataFnStr } from "../../../router/runtime/constants";
|
|
4
|
+
var HTML_ESCAPE_MAP = {
|
|
5
|
+
"&": "&",
|
|
6
|
+
"<": "<",
|
|
7
|
+
">": ">",
|
|
8
|
+
'"': """,
|
|
9
|
+
"'": "'"
|
|
10
|
+
};
|
|
11
|
+
function escapeAttr(value) {
|
|
12
|
+
return value.replace(/[&<>"']/g, function(ch) {
|
|
13
|
+
return HTML_ESCAPE_MAP[ch];
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function isRecord(v) {
|
|
17
|
+
return (typeof v === "undefined" ? "undefined" : _type_of(v)) === "object" && v !== null;
|
|
18
|
+
}
|
|
19
|
+
function isDeferredDataLike(v) {
|
|
20
|
+
if (!isRecord(v))
|
|
21
|
+
return false;
|
|
22
|
+
var hasPending = "pendingKeys" in v && Array.isArray(v.pendingKeys);
|
|
23
|
+
var hasData = "data" in v && isRecord(v.data);
|
|
24
|
+
return hasPending && hasData;
|
|
25
|
+
}
|
|
26
|
+
function isPromiseLike(value) {
|
|
27
|
+
return !!value && typeof value.then === "function";
|
|
28
|
+
}
|
|
29
|
+
function toErrorInfo(error) {
|
|
30
|
+
if (error && (typeof error === "undefined" ? "undefined" : _type_of(error)) === "object") {
|
|
31
|
+
var maybeMsg = error.message;
|
|
32
|
+
var maybeStack = error.stack;
|
|
33
|
+
return {
|
|
34
|
+
message: typeof maybeMsg === "string" ? maybeMsg : String(maybeMsg !== null && maybeMsg !== void 0 ? maybeMsg : error),
|
|
35
|
+
stack: process.env.NODE_ENV !== "production" ? maybeStack : void 0
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
message: String(error)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function buildDeferredDataScript(nonce, args) {
|
|
43
|
+
var payload = JSON.stringify(args);
|
|
44
|
+
var escaped = escapeAttr(payload);
|
|
45
|
+
var nonceAttr = nonce ? ' nonce="'.concat(nonce, '"') : "";
|
|
46
|
+
return "<script async".concat(nonceAttr, ` data-fn-name="r" data-script-src="modern-run-router-data-fn" data-fn-args='`).concat(escaped, "' suppressHydrationWarning>").concat(runRouterDataFnStr, "</script>");
|
|
47
|
+
}
|
|
48
|
+
function enqueueFromEntries(entries, nonce, emit) {
|
|
49
|
+
entries.forEach(function(param) {
|
|
50
|
+
var _param = _sliced_to_array(param, 2), routeId = _param[0], value = _param[1];
|
|
51
|
+
if (!isDeferredDataLike(value))
|
|
52
|
+
return;
|
|
53
|
+
var _value_pendingKeys;
|
|
54
|
+
var pendingKeys = new Set((_value_pendingKeys = value.pendingKeys) !== null && _value_pendingKeys !== void 0 ? _value_pendingKeys : []);
|
|
55
|
+
pendingKeys.forEach(function(key) {
|
|
56
|
+
var _value_data;
|
|
57
|
+
var tracked = (_value_data = value.data) === null || _value_data === void 0 ? void 0 : _value_data[key];
|
|
58
|
+
if (isPromiseLike(tracked)) {
|
|
59
|
+
tracked.then(function(val) {
|
|
60
|
+
return emit(buildDeferredDataScript(nonce, [
|
|
61
|
+
routeId,
|
|
62
|
+
key,
|
|
63
|
+
val
|
|
64
|
+
]));
|
|
65
|
+
}, function(err) {
|
|
66
|
+
return emit(buildDeferredDataScript(nonce, [
|
|
67
|
+
routeId,
|
|
68
|
+
key,
|
|
69
|
+
void 0,
|
|
70
|
+
toErrorInfo(err)
|
|
71
|
+
]));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
buildDeferredDataScript,
|
|
79
|
+
enqueueFromEntries,
|
|
80
|
+
escapeAttr,
|
|
81
|
+
isDeferredDataLike,
|
|
82
|
+
isPromiseLike,
|
|
83
|
+
isRecord,
|
|
84
|
+
toErrorInfo
|
|
85
|
+
};
|
|
@@ -2,10 +2,9 @@ import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
|
|
|
2
2
|
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
|
|
3
3
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
4
4
|
import { serializeJson, storage } from "@modern-js/runtime-utils/node";
|
|
5
|
-
import {
|
|
6
|
-
import { Suspense, useEffect, useMemo, useRef } from "react";
|
|
5
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
7
6
|
import { ROUTER_DATA_JSON_ID } from "../../core/constants";
|
|
8
|
-
import { modernInline,
|
|
7
|
+
import { modernInline, runWindowFnStr } from "./constants";
|
|
9
8
|
import { serializeErrors } from "./utils";
|
|
10
9
|
var DeferredDataScripts = function(props) {
|
|
11
10
|
var staticContext = props === null || props === void 0 ? void 0 : props.context;
|
|
@@ -37,12 +36,6 @@ var DeferredDataScripts = function(props) {
|
|
|
37
36
|
var deferredKeys = deferredData.deferredKeys;
|
|
38
37
|
var deferredKeyPromiseManifests = deferredKeys.map(function(key) {
|
|
39
38
|
if (pendingKeys.has(key)) {
|
|
40
|
-
deferredDataScripts.push(/* @__PURE__ */ _jsx(DeferredDataScript, {
|
|
41
|
-
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
42
|
-
data: deferredData.data[key],
|
|
43
|
-
dataKey: key,
|
|
44
|
-
routeId
|
|
45
|
-
}, "".concat(routeId, " | ").concat(key)));
|
|
46
39
|
return {
|
|
47
40
|
key,
|
|
48
41
|
routerDataFnName: "s",
|
|
@@ -100,98 +93,43 @@ var DeferredDataScripts = function(props) {
|
|
|
100
93
|
if (!deferredScripts) {
|
|
101
94
|
return null;
|
|
102
95
|
}
|
|
103
|
-
return /* @__PURE__ */
|
|
104
|
-
children:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
96
|
+
return /* @__PURE__ */ _jsx(_Fragment, {
|
|
97
|
+
children: !hydratedRef.current && /* @__PURE__ */ _jsxs(_Fragment, {
|
|
98
|
+
children: [
|
|
99
|
+
deferredScripts[0].length !== 0 && /* @__PURE__ */ _jsx("script", {
|
|
100
|
+
type: "application/json",
|
|
101
|
+
id: ROUTER_DATA_JSON_ID,
|
|
102
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
103
|
+
suppressHydrationWarning: true,
|
|
104
|
+
dangerouslySetInnerHTML: {
|
|
105
|
+
__html: deferredScripts[0]
|
|
106
|
+
}
|
|
107
|
+
}),
|
|
108
|
+
/* @__PURE__ */ _jsx("script", {
|
|
109
|
+
async: true,
|
|
110
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
111
|
+
"data-script-src": "modern-inline",
|
|
112
|
+
suppressHydrationWarning: true,
|
|
113
|
+
dangerouslySetInnerHTML: {
|
|
114
|
+
__html: deferredScripts[1]
|
|
115
|
+
}
|
|
116
|
+
}),
|
|
117
|
+
deferredScripts[2].map(function(param) {
|
|
118
|
+
var fnName = param.fnName, fnArgs = param.fnArgs, fnRun = param.fnRun, fnScriptSrc = param.fnScriptSrc;
|
|
119
|
+
return /* @__PURE__ */ _jsx("script", {
|
|
117
120
|
async: true,
|
|
121
|
+
"data-script-src": fnScriptSrc,
|
|
122
|
+
"data-fn-name": fnName,
|
|
123
|
+
"data-fn-args": JSON.stringify(fnArgs),
|
|
118
124
|
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
119
|
-
"data-script-src": "modern-inline",
|
|
120
125
|
suppressHydrationWarning: true,
|
|
121
126
|
dangerouslySetInnerHTML: {
|
|
122
|
-
__html:
|
|
127
|
+
__html: fnRun
|
|
123
128
|
}
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
async: true,
|
|
129
|
-
"data-script-src": fnScriptSrc,
|
|
130
|
-
"data-fn-name": fnName,
|
|
131
|
-
"data-fn-args": JSON.stringify(fnArgs),
|
|
132
|
-
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
133
|
-
suppressHydrationWarning: true,
|
|
134
|
-
dangerouslySetInnerHTML: {
|
|
135
|
-
__html: fnRun
|
|
136
|
-
}
|
|
137
|
-
}, fnName);
|
|
138
|
-
})
|
|
139
|
-
]
|
|
140
|
-
}),
|
|
141
|
-
!hydratedRef.current && deferredScripts[3]
|
|
142
|
-
]
|
|
143
|
-
});
|
|
144
|
-
};
|
|
145
|
-
var DeferredDataScript = function(param) {
|
|
146
|
-
var data = param.data, routeId = param.routeId, dataKey = param.dataKey, nonce = param.nonce;
|
|
147
|
-
return /* @__PURE__ */ _jsx(Suspense, {
|
|
148
|
-
children: typeof document === "undefined" && data && dataKey && routeId ? /* @__PURE__ */ _jsx(Await, {
|
|
149
|
-
resolve: data,
|
|
150
|
-
errorElement: /* @__PURE__ */ _jsx(ErrorDeferredDataScript, {
|
|
151
|
-
routeId,
|
|
152
|
-
dataKey,
|
|
153
|
-
nonce
|
|
154
|
-
}),
|
|
155
|
-
children: function(data2) {
|
|
156
|
-
return /* @__PURE__ */ _jsx("script", {
|
|
157
|
-
async: true,
|
|
158
|
-
nonce,
|
|
159
|
-
"data-fn-name": "r",
|
|
160
|
-
"data-script-src": "modern-run-router-data-fn",
|
|
161
|
-
"data-fn-args": "".concat(JSON.stringify([
|
|
162
|
-
routeId,
|
|
163
|
-
dataKey,
|
|
164
|
-
data2
|
|
165
|
-
])),
|
|
166
|
-
suppressHydrationWarning: true,
|
|
167
|
-
dangerouslySetInnerHTML: {
|
|
168
|
-
__html: runRouterDataFnStr
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}) : null
|
|
173
|
-
});
|
|
174
|
-
};
|
|
175
|
-
var ErrorDeferredDataScript = function(param) {
|
|
176
|
-
var routeId = param.routeId, dataKey = param.dataKey, nonce = param.nonce;
|
|
177
|
-
var error = useAsyncError();
|
|
178
|
-
return /* @__PURE__ */ _jsx("script", {
|
|
179
|
-
"data-fn-name": "r",
|
|
180
|
-
"data-script-src": "modern-run-router-data-fn",
|
|
181
|
-
"data-fn-args": "".concat(JSON.stringify([
|
|
182
|
-
routeId,
|
|
183
|
-
dataKey,
|
|
184
|
-
void 0,
|
|
185
|
-
{
|
|
186
|
-
message: error.message,
|
|
187
|
-
stack: error.stack
|
|
188
|
-
}
|
|
189
|
-
])),
|
|
190
|
-
nonce,
|
|
191
|
-
suppressHydrationWarning: true,
|
|
192
|
-
dangerouslySetInnerHTML: {
|
|
193
|
-
__html: runRouterDataFnStr
|
|
194
|
-
}
|
|
129
|
+
}, fnName);
|
|
130
|
+
})
|
|
131
|
+
]
|
|
132
|
+
})
|
|
195
133
|
});
|
|
196
134
|
};
|
|
197
135
|
var DeferredDataScripts_node_default = DeferredDataScripts;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { PassThrough, Transform } from "stream";
|
|
2
|
-
import { createReadableStreamFromReadable } from "@modern-js/runtime-utils/node";
|
|
2
|
+
import { createReadableStreamFromReadable, storage } from "@modern-js/runtime-utils/node";
|
|
3
3
|
import checkIsBot from "isbot";
|
|
4
4
|
import { ServerStyleSheet } from "styled-components";
|
|
5
5
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common";
|
|
6
6
|
import { RenderLevel } from "../../constants";
|
|
7
|
+
import { getMonitors } from "../../context/monitors";
|
|
8
|
+
import { enqueueFromEntries } from "./deferredScript";
|
|
7
9
|
import { ShellChunkStatus, getReadableStreamFromString } from "./shared";
|
|
8
10
|
import { getTemplates } from "./template";
|
|
9
11
|
const createReadableStreamFromElement = async (request, rootElement, options) => {
|
|
@@ -33,6 +35,7 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
33
35
|
entryName,
|
|
34
36
|
styledComponentsStyleTags
|
|
35
37
|
}).then(({ shellAfter, shellBefore }) => {
|
|
38
|
+
const pendingScripts = [];
|
|
36
39
|
const body = new Transform({
|
|
37
40
|
transform(chunk, _encoding, callback) {
|
|
38
41
|
try {
|
|
@@ -43,6 +46,11 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
43
46
|
concatedChunk = concatedChunk.replace(ESCAPED_SHELL_STREAM_END_MARK, "");
|
|
44
47
|
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
45
48
|
this.push(`${shellBefore}${concatedChunk}${shellAfter}`);
|
|
49
|
+
if (pendingScripts.length > 0) {
|
|
50
|
+
for (const s of pendingScripts) {
|
|
51
|
+
this.push(s);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
} else {
|
|
48
56
|
this.push(chunk);
|
|
@@ -63,6 +71,25 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
63
71
|
const styledStream = sheet.interleaveWithNodeStream(passThrough);
|
|
64
72
|
reactStreamingPipe(passThrough);
|
|
65
73
|
styledStream.pipe(body);
|
|
74
|
+
try {
|
|
75
|
+
var _storage_useContext, _options_runtimeContext, _storageContext_activeDeferreds;
|
|
76
|
+
const storageContext = (_storage_useContext = storage.useContext) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.call(storage);
|
|
77
|
+
const routerContext = (_options_runtimeContext = options.runtimeContext) === null || _options_runtimeContext === void 0 ? void 0 : _options_runtimeContext.routerContext;
|
|
78
|
+
const entries = (storageContext === null || storageContext === void 0 ? void 0 : storageContext.activeDeferreds) instanceof Map && ((_storageContext_activeDeferreds = storageContext.activeDeferreds) === null || _storageContext_activeDeferreds === void 0 ? void 0 : _storageContext_activeDeferreds.size) > 0 ? Array.from(storageContext.activeDeferreds.entries()) : (routerContext === null || routerContext === void 0 ? void 0 : routerContext.activeDeferreds) ? Object.entries(routerContext.activeDeferreds) : [];
|
|
79
|
+
if (entries.length > 0) {
|
|
80
|
+
const enqueueScript = (s) => {
|
|
81
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) {
|
|
82
|
+
body.write(s);
|
|
83
|
+
} else {
|
|
84
|
+
pendingScripts.push(s);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
enqueueFromEntries(entries, config.nonce, (s) => enqueueScript(s));
|
|
88
|
+
}
|
|
89
|
+
} catch (err) {
|
|
90
|
+
const monitors = getMonitors();
|
|
91
|
+
monitors.error("cannot inject router data script", err);
|
|
92
|
+
}
|
|
66
93
|
});
|
|
67
94
|
},
|
|
68
95
|
onShellError(error) {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { renderSSRStream } from "@modern-js/render/ssr";
|
|
2
|
+
import { storage } from "@modern-js/runtime-utils/node";
|
|
2
3
|
import checkIsBot from "isbot";
|
|
3
4
|
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common";
|
|
4
5
|
import { RenderLevel } from "../../constants";
|
|
6
|
+
import { enqueueFromEntries } from "./deferredScript";
|
|
5
7
|
import { ShellChunkStatus, encodeForWebStream, getReadableStreamFromString } from "./shared";
|
|
6
8
|
import { getTemplates } from "./template";
|
|
7
9
|
const createReadableStreamFromElement = async (request, rootElement, options) => {
|
|
@@ -41,6 +43,21 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
41
43
|
const reader = readableOriginal.getReader();
|
|
42
44
|
const stream = new ReadableStream({
|
|
43
45
|
start(controller) {
|
|
46
|
+
var _storage_useContext, _options_runtimeContext, _storageContext_activeDeferreds;
|
|
47
|
+
const pendingScripts = [];
|
|
48
|
+
const enqueueScript = (script) => {
|
|
49
|
+
if (shellChunkStatus === ShellChunkStatus.FINISH) {
|
|
50
|
+
controller.enqueue(encodeForWebStream(script));
|
|
51
|
+
} else {
|
|
52
|
+
pendingScripts.push(script);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const storageContext = (_storage_useContext = storage.useContext) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.call(storage);
|
|
56
|
+
const routerContext = (_options_runtimeContext = options.runtimeContext) === null || _options_runtimeContext === void 0 ? void 0 : _options_runtimeContext.routerContext;
|
|
57
|
+
const entries = (storageContext === null || storageContext === void 0 ? void 0 : storageContext.activeDeferreds) instanceof Map && ((_storageContext_activeDeferreds = storageContext.activeDeferreds) === null || _storageContext_activeDeferreds === void 0 ? void 0 : _storageContext_activeDeferreds.size) > 0 ? Array.from(storageContext.activeDeferreds.entries()) : (routerContext === null || routerContext === void 0 ? void 0 : routerContext.activeDeferreds) ? Object.entries(routerContext.activeDeferreds) : [];
|
|
58
|
+
if (entries.length > 0) {
|
|
59
|
+
enqueueFromEntries(entries, config.nonce, (s) => enqueueScript(s));
|
|
60
|
+
}
|
|
44
61
|
async function push() {
|
|
45
62
|
const { done, value } = await reader.read();
|
|
46
63
|
if (done) {
|
|
@@ -55,6 +72,12 @@ const createReadableStreamFromElement = async (request, rootElement, options) =>
|
|
|
55
72
|
concatedChunk = concatedChunk.replace(ESCAPED_SHELL_STREAM_END_MARK, "");
|
|
56
73
|
shellChunkStatus = ShellChunkStatus.FINISH;
|
|
57
74
|
controller.enqueue(encodeForWebStream(`${shellBefore}${concatedChunk}${shellAfter}`));
|
|
75
|
+
if (pendingScripts.length > 0) {
|
|
76
|
+
for (const s of pendingScripts) {
|
|
77
|
+
controller.enqueue(encodeForWebStream(s));
|
|
78
|
+
}
|
|
79
|
+
pendingScripts.length = 0;
|
|
80
|
+
}
|
|
58
81
|
}
|
|
59
82
|
} else {
|
|
60
83
|
controller.enqueue(value);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { runRouterDataFnStr } from "../../../router/runtime/constants";
|
|
2
|
+
const HTML_ESCAPE_MAP = {
|
|
3
|
+
"&": "&",
|
|
4
|
+
"<": "<",
|
|
5
|
+
">": ">",
|
|
6
|
+
'"': """,
|
|
7
|
+
"'": "'"
|
|
8
|
+
};
|
|
9
|
+
function escapeAttr(value) {
|
|
10
|
+
return value.replace(/[&<>"']/g, (ch) => HTML_ESCAPE_MAP[ch]);
|
|
11
|
+
}
|
|
12
|
+
function isRecord(v) {
|
|
13
|
+
return typeof v === "object" && v !== null;
|
|
14
|
+
}
|
|
15
|
+
function isDeferredDataLike(v) {
|
|
16
|
+
if (!isRecord(v))
|
|
17
|
+
return false;
|
|
18
|
+
const hasPending = "pendingKeys" in v && Array.isArray(v.pendingKeys);
|
|
19
|
+
const hasData = "data" in v && isRecord(v.data);
|
|
20
|
+
return hasPending && hasData;
|
|
21
|
+
}
|
|
22
|
+
function isPromiseLike(value) {
|
|
23
|
+
return !!value && typeof value.then === "function";
|
|
24
|
+
}
|
|
25
|
+
function toErrorInfo(error) {
|
|
26
|
+
if (error && typeof error === "object") {
|
|
27
|
+
const maybeMsg = error.message;
|
|
28
|
+
const maybeStack = error.stack;
|
|
29
|
+
return {
|
|
30
|
+
message: typeof maybeMsg === "string" ? maybeMsg : String(maybeMsg !== null && maybeMsg !== void 0 ? maybeMsg : error),
|
|
31
|
+
stack: process.env.NODE_ENV !== "production" ? maybeStack : void 0
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
message: String(error)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function buildDeferredDataScript(nonce, args) {
|
|
39
|
+
const payload = JSON.stringify(args);
|
|
40
|
+
const escaped = escapeAttr(payload);
|
|
41
|
+
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
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
|
+
}
|
|
44
|
+
function enqueueFromEntries(entries, nonce, emit) {
|
|
45
|
+
entries.forEach(([routeId, value]) => {
|
|
46
|
+
if (!isDeferredDataLike(value))
|
|
47
|
+
return;
|
|
48
|
+
var _value_pendingKeys;
|
|
49
|
+
const pendingKeys = new Set((_value_pendingKeys = value.pendingKeys) !== null && _value_pendingKeys !== void 0 ? _value_pendingKeys : []);
|
|
50
|
+
pendingKeys.forEach((key) => {
|
|
51
|
+
var _value_data;
|
|
52
|
+
const tracked = (_value_data = value.data) === null || _value_data === void 0 ? void 0 : _value_data[key];
|
|
53
|
+
if (isPromiseLike(tracked)) {
|
|
54
|
+
tracked.then((val) => emit(buildDeferredDataScript(nonce, [
|
|
55
|
+
routeId,
|
|
56
|
+
key,
|
|
57
|
+
val
|
|
58
|
+
])), (err) => emit(buildDeferredDataScript(nonce, [
|
|
59
|
+
routeId,
|
|
60
|
+
key,
|
|
61
|
+
void 0,
|
|
62
|
+
toErrorInfo(err)
|
|
63
|
+
])));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
buildDeferredDataScript,
|
|
70
|
+
enqueueFromEntries,
|
|
71
|
+
escapeAttr,
|
|
72
|
+
isDeferredDataLike,
|
|
73
|
+
isPromiseLike,
|
|
74
|
+
isRecord,
|
|
75
|
+
toErrorInfo
|
|
76
|
+
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { serializeJson, storage } from "@modern-js/runtime-utils/node";
|
|
3
|
-
import {
|
|
4
|
-
import { Suspense, useEffect, useMemo, useRef } from "react";
|
|
3
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
5
4
|
import { ROUTER_DATA_JSON_ID } from "../../core/constants";
|
|
6
|
-
import { modernInline,
|
|
5
|
+
import { modernInline, runWindowFnStr } from "./constants";
|
|
7
6
|
import { serializeErrors } from "./utils";
|
|
8
7
|
const DeferredDataScripts = (props) => {
|
|
9
8
|
const staticContext = props === null || props === void 0 ? void 0 : props.context;
|
|
@@ -34,12 +33,6 @@ const DeferredDataScripts = (props) => {
|
|
|
34
33
|
const { deferredKeys } = deferredData;
|
|
35
34
|
const deferredKeyPromiseManifests = deferredKeys.map((key) => {
|
|
36
35
|
if (pendingKeys.has(key)) {
|
|
37
|
-
deferredDataScripts.push(/* @__PURE__ */ _jsx(DeferredDataScript, {
|
|
38
|
-
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
39
|
-
data: deferredData.data[key],
|
|
40
|
-
dataKey: key,
|
|
41
|
-
routeId
|
|
42
|
-
}, `${routeId} | ${key}`));
|
|
43
36
|
return {
|
|
44
37
|
key,
|
|
45
38
|
routerDataFnName: "s",
|
|
@@ -97,91 +90,40 @@ const DeferredDataScripts = (props) => {
|
|
|
97
90
|
if (!deferredScripts) {
|
|
98
91
|
return null;
|
|
99
92
|
}
|
|
100
|
-
return /* @__PURE__ */
|
|
101
|
-
children:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}),
|
|
135
|
-
!hydratedRef.current && deferredScripts[3]
|
|
136
|
-
]
|
|
137
|
-
});
|
|
138
|
-
};
|
|
139
|
-
const DeferredDataScript = ({ data, routeId, dataKey, nonce }) => {
|
|
140
|
-
return /* @__PURE__ */ _jsx(Suspense, {
|
|
141
|
-
children: typeof document === "undefined" && data && dataKey && routeId ? /* @__PURE__ */ _jsx(Await, {
|
|
142
|
-
resolve: data,
|
|
143
|
-
errorElement: /* @__PURE__ */ _jsx(ErrorDeferredDataScript, {
|
|
144
|
-
routeId,
|
|
145
|
-
dataKey,
|
|
146
|
-
nonce
|
|
147
|
-
}),
|
|
148
|
-
children: (data2) => /* @__PURE__ */ _jsx("script", {
|
|
149
|
-
async: true,
|
|
150
|
-
nonce,
|
|
151
|
-
"data-fn-name": "r",
|
|
152
|
-
"data-script-src": "modern-run-router-data-fn",
|
|
153
|
-
"data-fn-args": `${JSON.stringify([
|
|
154
|
-
routeId,
|
|
155
|
-
dataKey,
|
|
156
|
-
data2
|
|
157
|
-
])}`,
|
|
158
|
-
suppressHydrationWarning: true,
|
|
159
|
-
dangerouslySetInnerHTML: {
|
|
160
|
-
__html: runRouterDataFnStr
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
}) : null
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
const ErrorDeferredDataScript = ({ routeId, dataKey, nonce }) => {
|
|
167
|
-
const error = useAsyncError();
|
|
168
|
-
return /* @__PURE__ */ _jsx("script", {
|
|
169
|
-
"data-fn-name": "r",
|
|
170
|
-
"data-script-src": "modern-run-router-data-fn",
|
|
171
|
-
"data-fn-args": `${JSON.stringify([
|
|
172
|
-
routeId,
|
|
173
|
-
dataKey,
|
|
174
|
-
void 0,
|
|
175
|
-
{
|
|
176
|
-
message: error.message,
|
|
177
|
-
stack: error.stack
|
|
178
|
-
}
|
|
179
|
-
])}`,
|
|
180
|
-
nonce,
|
|
181
|
-
suppressHydrationWarning: true,
|
|
182
|
-
dangerouslySetInnerHTML: {
|
|
183
|
-
__html: runRouterDataFnStr
|
|
184
|
-
}
|
|
93
|
+
return /* @__PURE__ */ _jsx(_Fragment, {
|
|
94
|
+
children: !hydratedRef.current && /* @__PURE__ */ _jsxs(_Fragment, {
|
|
95
|
+
children: [
|
|
96
|
+
deferredScripts[0].length !== 0 && /* @__PURE__ */ _jsx("script", {
|
|
97
|
+
type: "application/json",
|
|
98
|
+
id: ROUTER_DATA_JSON_ID,
|
|
99
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
100
|
+
suppressHydrationWarning: true,
|
|
101
|
+
dangerouslySetInnerHTML: {
|
|
102
|
+
__html: deferredScripts[0]
|
|
103
|
+
}
|
|
104
|
+
}),
|
|
105
|
+
/* @__PURE__ */ _jsx("script", {
|
|
106
|
+
async: true,
|
|
107
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
108
|
+
"data-script-src": "modern-inline",
|
|
109
|
+
suppressHydrationWarning: true,
|
|
110
|
+
dangerouslySetInnerHTML: {
|
|
111
|
+
__html: deferredScripts[1]
|
|
112
|
+
}
|
|
113
|
+
}),
|
|
114
|
+
deferredScripts[2].map(({ fnName, fnArgs, fnRun, fnScriptSrc }) => /* @__PURE__ */ _jsx("script", {
|
|
115
|
+
async: true,
|
|
116
|
+
"data-script-src": fnScriptSrc,
|
|
117
|
+
"data-fn-name": fnName,
|
|
118
|
+
"data-fn-args": JSON.stringify(fnArgs),
|
|
119
|
+
nonce: props === null || props === void 0 ? void 0 : props.nonce,
|
|
120
|
+
suppressHydrationWarning: true,
|
|
121
|
+
dangerouslySetInnerHTML: {
|
|
122
|
+
__html: fnRun
|
|
123
|
+
}
|
|
124
|
+
}, fnName))
|
|
125
|
+
]
|
|
126
|
+
})
|
|
185
127
|
});
|
|
186
128
|
};
|
|
187
129
|
var DeferredDataScripts_node_default = DeferredDataScripts;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DeferredData } from '@modern-js/runtime-utils/browser';
|
|
2
|
+
export type DeferredDataLike = Pick<DeferredData, 'data' | 'pendingKeys'> & {
|
|
3
|
+
data?: Record<string, unknown>;
|
|
4
|
+
pendingKeys?: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function escapeAttr(value: string): string;
|
|
7
|
+
export declare function isRecord(v: unknown): v is Record<string, unknown>;
|
|
8
|
+
export declare function isDeferredDataLike(v: unknown): v is DeferredDataLike;
|
|
9
|
+
export declare function isPromiseLike(value: unknown): value is Promise<unknown>;
|
|
10
|
+
export declare function toErrorInfo(error: unknown): {
|
|
11
|
+
message: string;
|
|
12
|
+
stack?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function buildDeferredDataScript(nonce: string | undefined, args: unknown[]): string;
|
|
15
|
+
export declare function enqueueFromEntries(entries: Array<[string, unknown]>, nonce: string | undefined, emit: (script: string) => void): void;
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"modern",
|
|
16
16
|
"modern.js"
|
|
17
17
|
],
|
|
18
|
-
"version": "2.68.
|
|
18
|
+
"version": "2.68.12",
|
|
19
19
|
"engines": {
|
|
20
20
|
"node": ">=14.17.6"
|
|
21
21
|
},
|
|
@@ -219,13 +219,13 @@
|
|
|
219
219
|
"react-is": "^18",
|
|
220
220
|
"react-side-effect": "^2.1.2",
|
|
221
221
|
"styled-components": "^5.3.1",
|
|
222
|
-
"@modern-js/plugin": "2.68.
|
|
223
|
-
"@modern-js/plugin-data-loader": "2.68.
|
|
224
|
-
"@modern-js/
|
|
225
|
-
"@modern-js/
|
|
226
|
-
"@modern-js/
|
|
227
|
-
"@modern-js/utils": "2.68.
|
|
228
|
-
"@modern-js/
|
|
222
|
+
"@modern-js/plugin": "2.68.12",
|
|
223
|
+
"@modern-js/plugin-data-loader": "2.68.12",
|
|
224
|
+
"@modern-js/plugin-v2": "2.68.12",
|
|
225
|
+
"@modern-js/render": "2.68.12",
|
|
226
|
+
"@modern-js/types": "2.68.12",
|
|
227
|
+
"@modern-js/runtime-utils": "2.68.12",
|
|
228
|
+
"@modern-js/utils": "2.68.12"
|
|
229
229
|
},
|
|
230
230
|
"peerDependencies": {
|
|
231
231
|
"react": ">=17",
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
},
|
|
234
234
|
"devDependencies": {
|
|
235
235
|
"@remix-run/web-fetch": "^4.1.3",
|
|
236
|
-
"@rsbuild/core": "1.
|
|
236
|
+
"@rsbuild/core": "1.5.3",
|
|
237
237
|
"@testing-library/react": "^13.4.0",
|
|
238
238
|
"@types/cookie": "0.6.0",
|
|
239
239
|
"@types/invariant": "^2.2.30",
|
|
@@ -248,11 +248,11 @@
|
|
|
248
248
|
"ts-jest": "^29.1.0",
|
|
249
249
|
"ts-node": "^10.9.1",
|
|
250
250
|
"typescript": "^5",
|
|
251
|
-
"webpack": "^5.101.
|
|
252
|
-
"@modern-js/app-tools": "2.68.
|
|
251
|
+
"webpack": "^5.101.3",
|
|
252
|
+
"@modern-js/app-tools": "2.68.12",
|
|
253
253
|
"@scripts/build": "2.66.0",
|
|
254
254
|
"@scripts/jest-config": "2.66.0",
|
|
255
|
-
"@modern-js/core": "2.68.
|
|
255
|
+
"@modern-js/core": "2.68.12"
|
|
256
256
|
},
|
|
257
257
|
"sideEffects": false,
|
|
258
258
|
"publishConfig": {
|