@bleedingdev/modern-js-render 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21
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/esm/client.mjs +1 -1
- package/dist/esm/{rscWorker.mjs → rsc.edge.mjs} +104 -75
- package/dist/esm/rsc.mjs +100 -68
- package/dist/esm/server~0.mjs +81 -48
- package/dist/esm/ssr.mjs +9 -9
- package/dist/types/rsc.edge.d.ts +1 -0
- package/dist/types/server/rsc/rsc.edge.d.ts +11 -0
- package/dist/types/server/ssr/ssr.d.ts +3 -1
- package/package.json +14 -19
- package/dist/types/rsc.worker.d.ts +0 -1
- package/dist/types/server/rsc/rsc.worker.d.ts +0 -12
- /package/dist/esm/{341~0.mjs → m~0.mjs} +0 -0
package/dist/esm/client.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ElementsContext, RSCServerSlot, ResetRootContext, RscClientRoot, ServerElementsProvider, callServer, createFromFetch, createFromReadableStream, createServerReference, rscStream, setServerCallback } from "./
|
|
1
|
+
export { ElementsContext, RSCServerSlot, ResetRootContext, RscClientRoot, ServerElementsProvider, callServer, createFromFetch, createFromReadableStream, createServerReference, rscStream, setServerCallback } from "./m~0.mjs";
|
|
@@ -1,63 +1,96 @@
|
|
|
1
1
|
import { decodeReply as server_edge_decodeReply, loadServerAction as server_edge_loadServerAction, registerClientReference, registerServerReference, renderToReadableStream } from "react-server-dom-rspack/server.edge";
|
|
2
|
-
import { injectRSCPayload } from "@modern-js/runtime-extensions/rsc-html-stream";
|
|
3
2
|
const server_encoder = new TextEncoder();
|
|
4
3
|
const closingTagsPattern = /<\/body>\s*<\/html>\s*$/i;
|
|
5
|
-
function
|
|
6
|
-
if (injectClosingTags) return injectRSCPayload(rscStream);
|
|
4
|
+
function injectRSCPayload(rscStream, { injectClosingTags = true }) {
|
|
7
5
|
const decoder = new TextDecoder();
|
|
8
|
-
let
|
|
9
|
-
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
let
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
let pendingHtml = '';
|
|
7
|
+
let closingBody = false;
|
|
8
|
+
let closingHtml = false;
|
|
9
|
+
let closingProbe = '';
|
|
10
|
+
let flightReader;
|
|
11
|
+
let flightPromise;
|
|
12
|
+
function startFlight(controller) {
|
|
13
|
+
if (!flightPromise) {
|
|
14
|
+
flightReader = rscStream.getReader();
|
|
15
|
+
flightPromise = writeRSCStream(flightReader, controller).finally(()=>{
|
|
16
|
+
flightReader = void 0;
|
|
17
|
+
});
|
|
18
|
+
flightPromise.catch((error)=>controller.error(error));
|
|
19
|
+
}
|
|
20
|
+
return flightPromise;
|
|
22
21
|
}
|
|
23
|
-
|
|
22
|
+
async function writeHtml(value, controller) {
|
|
23
|
+
let html = pendingHtml + value;
|
|
24
|
+
pendingHtml = '';
|
|
25
|
+
if (!closingBody) {
|
|
26
|
+
const bodyIndex = html.search(/<\/body>\s*(?:<\/html>\s*|<\/h(?:t(?:m(?:l>?)?)?)?|<\/?|<)?$/i);
|
|
27
|
+
if (-1 !== bodyIndex) {
|
|
28
|
+
controller.enqueue(server_encoder.encode(html.slice(0, bodyIndex)));
|
|
29
|
+
await startFlight(controller);
|
|
30
|
+
closingBody = true;
|
|
31
|
+
html = html.slice(bodyIndex);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (closingBody) {
|
|
35
|
+
if (!injectClosingTags) {
|
|
36
|
+
pendingHtml = html;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
closingHtml ||= /<\/html>/i.test(closingProbe + html);
|
|
40
|
+
closingProbe = (closingProbe + html).slice(-6);
|
|
41
|
+
} else {
|
|
42
|
+
const tagIndex = html.lastIndexOf('<');
|
|
43
|
+
if (tagIndex > html.lastIndexOf('>')) {
|
|
44
|
+
pendingHtml = html.slice(tagIndex);
|
|
45
|
+
html = html.slice(0, tagIndex);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (html) {
|
|
49
|
+
controller.enqueue(server_encoder.encode(html));
|
|
50
|
+
startFlight(controller);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const transformer = {
|
|
24
54
|
transform (chunk, controller) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
flushBufferedChunks(controller);
|
|
29
|
-
if (!startedRSC) {
|
|
30
|
-
startedRSC = true;
|
|
31
|
-
writeRSCStream(rscStream, controller).catch((err)=>controller.error(err)).then(()=>resolveFlightDataPromise());
|
|
32
|
-
}
|
|
33
|
-
}, 0);
|
|
55
|
+
return writeHtml(decoder.decode(chunk, {
|
|
56
|
+
stream: true
|
|
57
|
+
}), controller);
|
|
34
58
|
},
|
|
35
59
|
async flush (controller) {
|
|
36
|
-
await
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
await writeHtml(decoder.decode(), controller);
|
|
61
|
+
await startFlight(controller);
|
|
62
|
+
const tail = injectClosingTags ? pendingHtml : pendingHtml.replace(closingTagsPattern, '');
|
|
63
|
+
if (tail) controller.enqueue(server_encoder.encode(tail));
|
|
64
|
+
if (injectClosingTags && !closingHtml) controller.enqueue(server_encoder.encode(closingBody ? '</html>' : '</body></html>'));
|
|
65
|
+
},
|
|
66
|
+
cancel (reason) {
|
|
67
|
+
return flightReader ? flightReader.cancel(reason) : rscStream.cancel(reason);
|
|
44
68
|
}
|
|
45
|
-
}
|
|
69
|
+
};
|
|
70
|
+
return new TransformStream(transformer);
|
|
46
71
|
}
|
|
47
|
-
async function writeRSCStream(
|
|
72
|
+
async function writeRSCStream(reader, controller) {
|
|
48
73
|
const decoder = new TextDecoder('utf-8', {
|
|
49
|
-
fatal: true
|
|
74
|
+
fatal: true,
|
|
75
|
+
ignoreBOM: true
|
|
50
76
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
77
|
+
try {
|
|
78
|
+
while(true){
|
|
79
|
+
const { done, value } = await reader.read();
|
|
80
|
+
if (done) return;
|
|
81
|
+
let chunk;
|
|
82
|
+
try {
|
|
83
|
+
chunk = JSON.stringify(decoder.decode(value));
|
|
84
|
+
} catch {
|
|
85
|
+
let binary = '';
|
|
86
|
+
for (const byte of value)binary += String.fromCharCode(byte);
|
|
87
|
+
chunk = `Uint8Array.from(atob(${JSON.stringify(btoa(binary))}), m => m.codePointAt(0))`;
|
|
88
|
+
}
|
|
89
|
+
writeChunk(chunk, controller);
|
|
90
|
+
}
|
|
91
|
+
} finally{
|
|
92
|
+
reader.releaseLock();
|
|
58
93
|
}
|
|
59
|
-
const remaining = decoder.decode();
|
|
60
|
-
if (remaining.length) writeChunk(JSON.stringify(remaining), controller);
|
|
61
94
|
}
|
|
62
95
|
function writeChunk(chunk, controller) {
|
|
63
96
|
controller.enqueue(server_encoder.encode(`<script>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}</script>`));
|
|
@@ -76,35 +109,34 @@ function injectCSS(cssFiles, { injectClosingTags = true } = {}) {
|
|
|
76
109
|
});
|
|
77
110
|
const decoder = new TextDecoder();
|
|
78
111
|
const headTrailer = '</head>';
|
|
79
|
-
|
|
80
|
-
let timeout = null;
|
|
112
|
+
let pendingHtml = '';
|
|
81
113
|
let cssInjected = false;
|
|
82
114
|
const cssLinks = cssFiles.map((css)=>`<link href="${css}" rel="stylesheet" />`).join('');
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
function writeHtml(value, controller, final = false) {
|
|
116
|
+
let html = pendingHtml + value;
|
|
117
|
+
pendingHtml = '';
|
|
118
|
+
if (!cssInjected) {
|
|
119
|
+
const headIndex = html.toLowerCase().indexOf(headTrailer);
|
|
120
|
+
if (-1 !== headIndex) {
|
|
121
|
+
html = html.slice(0, headIndex) + cssLinks + html.slice(headIndex);
|
|
88
122
|
cssInjected = true;
|
|
123
|
+
} else if (!final) {
|
|
124
|
+
let retain = Math.min(headTrailer.length - 1, html.length);
|
|
125
|
+
while(retain && !html.toLowerCase().endsWith(headTrailer.slice(0, retain)))retain--;
|
|
126
|
+
pendingHtml = html.slice(html.length - retain);
|
|
127
|
+
html = html.slice(0, html.length - retain);
|
|
89
128
|
}
|
|
90
|
-
controller.enqueue(server_encoder.encode(buf));
|
|
91
129
|
}
|
|
92
|
-
|
|
93
|
-
timeout = null;
|
|
130
|
+
if (html) controller.enqueue(server_encoder.encode(html));
|
|
94
131
|
}
|
|
95
132
|
return new TransformStream({
|
|
96
133
|
transform (chunk, controller) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
flushBufferedChunks(controller);
|
|
101
|
-
}, 0);
|
|
134
|
+
writeHtml(decoder.decode(chunk, {
|
|
135
|
+
stream: true
|
|
136
|
+
}), controller);
|
|
102
137
|
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
clearTimeout(timeout);
|
|
106
|
-
flushBufferedChunks(controller);
|
|
107
|
-
}
|
|
138
|
+
flush (controller) {
|
|
139
|
+
writeHtml(decoder.decode(), controller, true);
|
|
108
140
|
if (!cssInjected) controller.enqueue(server_encoder.encode(cssLinks));
|
|
109
141
|
if (injectClosingTags) controller.enqueue(server_encoder.encode('</body></html>'));
|
|
110
142
|
}
|
|
@@ -125,7 +157,7 @@ const createRenderCSRWithRSC = (renderRsc)=>async (options)=>{
|
|
|
125
157
|
});
|
|
126
158
|
const stream = htmlStream.pipeThrough(injectCSS(cssFiles, {
|
|
127
159
|
injectClosingTags: false
|
|
128
|
-
})).pipeThrough(
|
|
160
|
+
})).pipeThrough(injectRSCPayload(rscPayloadStream, {
|
|
129
161
|
injectClosingTags: true
|
|
130
162
|
}));
|
|
131
163
|
return new Response(stream, {
|
|
@@ -231,15 +263,12 @@ const createHandleAction = ({ decodeReply, loadServerAction, renderRsc })=>async
|
|
|
231
263
|
});
|
|
232
264
|
}
|
|
233
265
|
};
|
|
234
|
-
const
|
|
235
|
-
const readable = renderToReadableStream(options.element);
|
|
236
|
-
return readable;
|
|
237
|
-
};
|
|
238
|
-
const renderCSRWithRSC = createRenderCSRWithRSC(rsc_worker_renderRsc);
|
|
266
|
+
const rsc_edge_renderRsc = (options)=>renderToReadableStream(options.element);
|
|
239
267
|
const handleAction = createHandleAction({
|
|
240
268
|
decodeReply: server_edge_decodeReply,
|
|
241
269
|
loadServerAction: server_edge_loadServerAction,
|
|
242
|
-
renderRsc:
|
|
270
|
+
renderRsc: rsc_edge_renderRsc
|
|
243
271
|
});
|
|
272
|
+
const renderCSRWithRSC = createRenderCSRWithRSC(rsc_edge_renderRsc);
|
|
244
273
|
export { createFromReadableStream } from "react-server-dom-rspack/client.edge";
|
|
245
|
-
export { handleAction, registerClientReference, registerServerReference, renderCSRWithRSC, renderToReadableStream,
|
|
274
|
+
export { handleAction, registerClientReference, registerServerReference, renderCSRWithRSC, renderToReadableStream, rsc_edge_renderRsc as renderRsc };
|
package/dist/esm/rsc.mjs
CHANGED
|
@@ -1,63 +1,96 @@
|
|
|
1
|
-
import { injectRSCPayload } from "@modern-js/runtime-extensions/rsc-html-stream";
|
|
2
1
|
import { decodeReply as server_node_decodeReply, loadServerAction as server_node_loadServerAction, registerClientReference, registerServerReference, renderToReadableStream } from "react-server-dom-rspack/server.node";
|
|
3
2
|
const server_encoder = new TextEncoder();
|
|
4
3
|
const closingTagsPattern = /<\/body>\s*<\/html>\s*$/i;
|
|
5
|
-
function
|
|
6
|
-
if (injectClosingTags) return injectRSCPayload(rscStream);
|
|
4
|
+
function injectRSCPayload(rscStream, { injectClosingTags = true }) {
|
|
7
5
|
const decoder = new TextDecoder();
|
|
8
|
-
let
|
|
9
|
-
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
let
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
let pendingHtml = '';
|
|
7
|
+
let closingBody = false;
|
|
8
|
+
let closingHtml = false;
|
|
9
|
+
let closingProbe = '';
|
|
10
|
+
let flightReader;
|
|
11
|
+
let flightPromise;
|
|
12
|
+
function startFlight(controller) {
|
|
13
|
+
if (!flightPromise) {
|
|
14
|
+
flightReader = rscStream.getReader();
|
|
15
|
+
flightPromise = writeRSCStream(flightReader, controller).finally(()=>{
|
|
16
|
+
flightReader = void 0;
|
|
17
|
+
});
|
|
18
|
+
flightPromise.catch((error)=>controller.error(error));
|
|
19
|
+
}
|
|
20
|
+
return flightPromise;
|
|
22
21
|
}
|
|
23
|
-
|
|
22
|
+
async function writeHtml(value, controller) {
|
|
23
|
+
let html = pendingHtml + value;
|
|
24
|
+
pendingHtml = '';
|
|
25
|
+
if (!closingBody) {
|
|
26
|
+
const bodyIndex = html.search(/<\/body>\s*(?:<\/html>\s*|<\/h(?:t(?:m(?:l>?)?)?)?|<\/?|<)?$/i);
|
|
27
|
+
if (-1 !== bodyIndex) {
|
|
28
|
+
controller.enqueue(server_encoder.encode(html.slice(0, bodyIndex)));
|
|
29
|
+
await startFlight(controller);
|
|
30
|
+
closingBody = true;
|
|
31
|
+
html = html.slice(bodyIndex);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (closingBody) {
|
|
35
|
+
if (!injectClosingTags) {
|
|
36
|
+
pendingHtml = html;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
closingHtml ||= /<\/html>/i.test(closingProbe + html);
|
|
40
|
+
closingProbe = (closingProbe + html).slice(-6);
|
|
41
|
+
} else {
|
|
42
|
+
const tagIndex = html.lastIndexOf('<');
|
|
43
|
+
if (tagIndex > html.lastIndexOf('>')) {
|
|
44
|
+
pendingHtml = html.slice(tagIndex);
|
|
45
|
+
html = html.slice(0, tagIndex);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (html) {
|
|
49
|
+
controller.enqueue(server_encoder.encode(html));
|
|
50
|
+
startFlight(controller);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const transformer = {
|
|
24
54
|
transform (chunk, controller) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
flushBufferedChunks(controller);
|
|
29
|
-
if (!startedRSC) {
|
|
30
|
-
startedRSC = true;
|
|
31
|
-
writeRSCStream(rscStream, controller).catch((err)=>controller.error(err)).then(()=>resolveFlightDataPromise());
|
|
32
|
-
}
|
|
33
|
-
}, 0);
|
|
55
|
+
return writeHtml(decoder.decode(chunk, {
|
|
56
|
+
stream: true
|
|
57
|
+
}), controller);
|
|
34
58
|
},
|
|
35
59
|
async flush (controller) {
|
|
36
|
-
await
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
await writeHtml(decoder.decode(), controller);
|
|
61
|
+
await startFlight(controller);
|
|
62
|
+
const tail = injectClosingTags ? pendingHtml : pendingHtml.replace(closingTagsPattern, '');
|
|
63
|
+
if (tail) controller.enqueue(server_encoder.encode(tail));
|
|
64
|
+
if (injectClosingTags && !closingHtml) controller.enqueue(server_encoder.encode(closingBody ? '</html>' : '</body></html>'));
|
|
65
|
+
},
|
|
66
|
+
cancel (reason) {
|
|
67
|
+
return flightReader ? flightReader.cancel(reason) : rscStream.cancel(reason);
|
|
44
68
|
}
|
|
45
|
-
}
|
|
69
|
+
};
|
|
70
|
+
return new TransformStream(transformer);
|
|
46
71
|
}
|
|
47
|
-
async function writeRSCStream(
|
|
72
|
+
async function writeRSCStream(reader, controller) {
|
|
48
73
|
const decoder = new TextDecoder('utf-8', {
|
|
49
|
-
fatal: true
|
|
74
|
+
fatal: true,
|
|
75
|
+
ignoreBOM: true
|
|
50
76
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
77
|
+
try {
|
|
78
|
+
while(true){
|
|
79
|
+
const { done, value } = await reader.read();
|
|
80
|
+
if (done) return;
|
|
81
|
+
let chunk;
|
|
82
|
+
try {
|
|
83
|
+
chunk = JSON.stringify(decoder.decode(value));
|
|
84
|
+
} catch {
|
|
85
|
+
let binary = '';
|
|
86
|
+
for (const byte of value)binary += String.fromCharCode(byte);
|
|
87
|
+
chunk = `Uint8Array.from(atob(${JSON.stringify(btoa(binary))}), m => m.codePointAt(0))`;
|
|
88
|
+
}
|
|
89
|
+
writeChunk(chunk, controller);
|
|
90
|
+
}
|
|
91
|
+
} finally{
|
|
92
|
+
reader.releaseLock();
|
|
58
93
|
}
|
|
59
|
-
const remaining = decoder.decode();
|
|
60
|
-
if (remaining.length) writeChunk(JSON.stringify(remaining), controller);
|
|
61
94
|
}
|
|
62
95
|
function writeChunk(chunk, controller) {
|
|
63
96
|
controller.enqueue(server_encoder.encode(`<script>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}</script>`));
|
|
@@ -76,35 +109,34 @@ function injectCSS(cssFiles, { injectClosingTags = true } = {}) {
|
|
|
76
109
|
});
|
|
77
110
|
const decoder = new TextDecoder();
|
|
78
111
|
const headTrailer = '</head>';
|
|
79
|
-
|
|
80
|
-
let timeout = null;
|
|
112
|
+
let pendingHtml = '';
|
|
81
113
|
let cssInjected = false;
|
|
82
114
|
const cssLinks = cssFiles.map((css)=>`<link href="${css}" rel="stylesheet" />`).join('');
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
function writeHtml(value, controller, final = false) {
|
|
116
|
+
let html = pendingHtml + value;
|
|
117
|
+
pendingHtml = '';
|
|
118
|
+
if (!cssInjected) {
|
|
119
|
+
const headIndex = html.toLowerCase().indexOf(headTrailer);
|
|
120
|
+
if (-1 !== headIndex) {
|
|
121
|
+
html = html.slice(0, headIndex) + cssLinks + html.slice(headIndex);
|
|
88
122
|
cssInjected = true;
|
|
123
|
+
} else if (!final) {
|
|
124
|
+
let retain = Math.min(headTrailer.length - 1, html.length);
|
|
125
|
+
while(retain && !html.toLowerCase().endsWith(headTrailer.slice(0, retain)))retain--;
|
|
126
|
+
pendingHtml = html.slice(html.length - retain);
|
|
127
|
+
html = html.slice(0, html.length - retain);
|
|
89
128
|
}
|
|
90
|
-
controller.enqueue(server_encoder.encode(buf));
|
|
91
129
|
}
|
|
92
|
-
|
|
93
|
-
timeout = null;
|
|
130
|
+
if (html) controller.enqueue(server_encoder.encode(html));
|
|
94
131
|
}
|
|
95
132
|
return new TransformStream({
|
|
96
133
|
transform (chunk, controller) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
flushBufferedChunks(controller);
|
|
101
|
-
}, 0);
|
|
134
|
+
writeHtml(decoder.decode(chunk, {
|
|
135
|
+
stream: true
|
|
136
|
+
}), controller);
|
|
102
137
|
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
clearTimeout(timeout);
|
|
106
|
-
flushBufferedChunks(controller);
|
|
107
|
-
}
|
|
138
|
+
flush (controller) {
|
|
139
|
+
writeHtml(decoder.decode(), controller, true);
|
|
108
140
|
if (!cssInjected) controller.enqueue(server_encoder.encode(cssLinks));
|
|
109
141
|
if (injectClosingTags) controller.enqueue(server_encoder.encode('</body></html>'));
|
|
110
142
|
}
|
|
@@ -125,7 +157,7 @@ const createRenderCSRWithRSC = (renderRsc)=>async (options)=>{
|
|
|
125
157
|
});
|
|
126
158
|
const stream = htmlStream.pipeThrough(injectCSS(cssFiles, {
|
|
127
159
|
injectClosingTags: false
|
|
128
|
-
})).pipeThrough(
|
|
160
|
+
})).pipeThrough(injectRSCPayload(rscPayloadStream, {
|
|
129
161
|
injectClosingTags: true
|
|
130
162
|
}));
|
|
131
163
|
return new Response(stream, {
|
package/dist/esm/server~0.mjs
CHANGED
|
@@ -1,62 +1,95 @@
|
|
|
1
|
-
import { injectRSCPayload } from "@modern-js/runtime-extensions/rsc-html-stream";
|
|
2
1
|
const encoder = new TextEncoder();
|
|
3
2
|
const closingTagsPattern = /<\/body>\s*<\/html>\s*$/i;
|
|
4
|
-
function
|
|
5
|
-
if (injectClosingTags) return injectRSCPayload(rscStream);
|
|
3
|
+
function injectRSCPayload(rscStream, { injectClosingTags = true }) {
|
|
6
4
|
const decoder = new TextDecoder();
|
|
7
|
-
let
|
|
8
|
-
|
|
9
|
-
let
|
|
10
|
-
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
let pendingHtml = '';
|
|
6
|
+
let closingBody = false;
|
|
7
|
+
let closingHtml = false;
|
|
8
|
+
let closingProbe = '';
|
|
9
|
+
let flightReader;
|
|
10
|
+
let flightPromise;
|
|
11
|
+
function startFlight(controller) {
|
|
12
|
+
if (!flightPromise) {
|
|
13
|
+
flightReader = rscStream.getReader();
|
|
14
|
+
flightPromise = writeRSCStream(flightReader, controller).finally(()=>{
|
|
15
|
+
flightReader = void 0;
|
|
16
|
+
});
|
|
17
|
+
flightPromise.catch((error)=>controller.error(error));
|
|
18
|
+
}
|
|
19
|
+
return flightPromise;
|
|
21
20
|
}
|
|
22
|
-
|
|
21
|
+
async function writeHtml(value, controller) {
|
|
22
|
+
let html = pendingHtml + value;
|
|
23
|
+
pendingHtml = '';
|
|
24
|
+
if (!closingBody) {
|
|
25
|
+
const bodyIndex = html.search(/<\/body>\s*(?:<\/html>\s*|<\/h(?:t(?:m(?:l>?)?)?)?|<\/?|<)?$/i);
|
|
26
|
+
if (-1 !== bodyIndex) {
|
|
27
|
+
controller.enqueue(encoder.encode(html.slice(0, bodyIndex)));
|
|
28
|
+
await startFlight(controller);
|
|
29
|
+
closingBody = true;
|
|
30
|
+
html = html.slice(bodyIndex);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (closingBody) {
|
|
34
|
+
if (!injectClosingTags) {
|
|
35
|
+
pendingHtml = html;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
closingHtml ||= /<\/html>/i.test(closingProbe + html);
|
|
39
|
+
closingProbe = (closingProbe + html).slice(-6);
|
|
40
|
+
} else {
|
|
41
|
+
const tagIndex = html.lastIndexOf('<');
|
|
42
|
+
if (tagIndex > html.lastIndexOf('>')) {
|
|
43
|
+
pendingHtml = html.slice(tagIndex);
|
|
44
|
+
html = html.slice(0, tagIndex);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (html) {
|
|
48
|
+
controller.enqueue(encoder.encode(html));
|
|
49
|
+
startFlight(controller);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const transformer = {
|
|
23
53
|
transform (chunk, controller) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
flushBufferedChunks(controller);
|
|
28
|
-
if (!startedRSC) {
|
|
29
|
-
startedRSC = true;
|
|
30
|
-
writeRSCStream(rscStream, controller).catch((err)=>controller.error(err)).then(()=>resolveFlightDataPromise());
|
|
31
|
-
}
|
|
32
|
-
}, 0);
|
|
54
|
+
return writeHtml(decoder.decode(chunk, {
|
|
55
|
+
stream: true
|
|
56
|
+
}), controller);
|
|
33
57
|
},
|
|
34
58
|
async flush (controller) {
|
|
35
|
-
await
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
await writeHtml(decoder.decode(), controller);
|
|
60
|
+
await startFlight(controller);
|
|
61
|
+
const tail = injectClosingTags ? pendingHtml : pendingHtml.replace(closingTagsPattern, '');
|
|
62
|
+
if (tail) controller.enqueue(encoder.encode(tail));
|
|
63
|
+
if (injectClosingTags && !closingHtml) controller.enqueue(encoder.encode(closingBody ? '</html>' : '</body></html>'));
|
|
64
|
+
},
|
|
65
|
+
cancel (reason) {
|
|
66
|
+
return flightReader ? flightReader.cancel(reason) : rscStream.cancel(reason);
|
|
43
67
|
}
|
|
44
|
-
}
|
|
68
|
+
};
|
|
69
|
+
return new TransformStream(transformer);
|
|
45
70
|
}
|
|
46
|
-
async function writeRSCStream(
|
|
71
|
+
async function writeRSCStream(reader, controller) {
|
|
47
72
|
const decoder = new TextDecoder('utf-8', {
|
|
48
|
-
fatal: true
|
|
73
|
+
fatal: true,
|
|
74
|
+
ignoreBOM: true
|
|
49
75
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
76
|
+
try {
|
|
77
|
+
while(true){
|
|
78
|
+
const { done, value } = await reader.read();
|
|
79
|
+
if (done) return;
|
|
80
|
+
let chunk;
|
|
81
|
+
try {
|
|
82
|
+
chunk = JSON.stringify(decoder.decode(value));
|
|
83
|
+
} catch {
|
|
84
|
+
let binary = '';
|
|
85
|
+
for (const byte of value)binary += String.fromCharCode(byte);
|
|
86
|
+
chunk = `Uint8Array.from(atob(${JSON.stringify(btoa(binary))}), m => m.codePointAt(0))`;
|
|
87
|
+
}
|
|
88
|
+
writeChunk(chunk, controller);
|
|
89
|
+
}
|
|
90
|
+
} finally{
|
|
91
|
+
reader.releaseLock();
|
|
57
92
|
}
|
|
58
|
-
const remaining = decoder.decode();
|
|
59
|
-
if (remaining.length) writeChunk(JSON.stringify(remaining), controller);
|
|
60
93
|
}
|
|
61
94
|
function writeChunk(chunk, controller) {
|
|
62
95
|
controller.enqueue(encoder.encode(`<script>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}</script>`));
|
|
@@ -64,4 +97,4 @@ function writeChunk(chunk, controller) {
|
|
|
64
97
|
function escapeScript(script) {
|
|
65
98
|
return script.replace(/<!--/g, '<\\!--').replace(/<\/(script)/gi, '</\\$1');
|
|
66
99
|
}
|
|
67
|
-
export {
|
|
100
|
+
export { injectRSCPayload };
|
package/dist/esm/ssr.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
|
|
2
2
|
import react from "react";
|
|
3
3
|
import { renderToReadableStream } from "react-dom/server.edge";
|
|
4
|
-
import { ServerElementsProvider } from "./
|
|
4
|
+
import { ServerElementsProvider } from "./m~0.mjs";
|
|
5
5
|
function CSSLinks({ cssFiles }) {
|
|
6
6
|
if (0 === cssFiles.length) return null;
|
|
7
7
|
return /*#__PURE__*/ react.createElement(react.Fragment, null, cssFiles.map((css)=>/*#__PURE__*/ react.createElement("link", {
|
|
@@ -16,19 +16,18 @@ function wrapStream(stream, originalStream) {
|
|
|
16
16
|
return wrappedStream;
|
|
17
17
|
}
|
|
18
18
|
const renderSSRStream = async (children, options)=>{
|
|
19
|
-
const { rscManifest, rscRoot, routes } = options;
|
|
19
|
+
const { rscManifest, rscRoot, routes, wrapHtmlRoot, ...reactOptions } = options;
|
|
20
20
|
const clientManifest = rscManifest?.clientManifest;
|
|
21
21
|
const serverConsumerModuleMap = rscManifest?.serverConsumerModuleMap;
|
|
22
22
|
const entryCssFiles = rscManifest?.entryCssFiles;
|
|
23
23
|
const hasRoutes = Boolean(routes && routes.length > 0);
|
|
24
|
-
if (!clientManifest || !serverConsumerModuleMap) return renderToReadableStream(children, {
|
|
25
|
-
...
|
|
24
|
+
if (!clientManifest || !serverConsumerModuleMap) return renderToReadableStream(wrapHtmlRoot ? wrapHtmlRoot(children) : children, {
|
|
25
|
+
...reactOptions,
|
|
26
26
|
identifierPrefix: SSR_HYDRATION_ID_PREFIX
|
|
27
27
|
});
|
|
28
28
|
try {
|
|
29
|
-
const rscRuntime = 'edge' === process.env.MODERN_SSR_ENV ? import("@modern-js/render/rsc-worker") : import("@modern-js/render/rsc");
|
|
30
29
|
const [{ renderRsc }, { createFromReadableStream }, { injectRSCPayload }] = await Promise.all([
|
|
31
|
-
|
|
30
|
+
import("@modern-js/render/rsc"),
|
|
32
31
|
import("react-server-dom-rspack/client.edge"),
|
|
33
32
|
import("./server~0.mjs")
|
|
34
33
|
]);
|
|
@@ -39,12 +38,13 @@ const renderSSRStream = async (children, options)=>{
|
|
|
39
38
|
const elements = createFromReadableStream(rscElementStream);
|
|
40
39
|
let cssFiles = [];
|
|
41
40
|
if (!hasRoutes && entryCssFiles) cssFiles = Object.values(entryCssFiles).flat();
|
|
42
|
-
const
|
|
41
|
+
const htmlRoot = /*#__PURE__*/ react.createElement(ServerElementsProvider, {
|
|
43
42
|
elements: elements
|
|
44
43
|
}, /*#__PURE__*/ react.createElement(CSSLinks, {
|
|
45
44
|
cssFiles: cssFiles
|
|
46
|
-
}), children)
|
|
47
|
-
|
|
45
|
+
}), children);
|
|
46
|
+
const htmlStream = await renderToReadableStream(wrapHtmlRoot ? wrapHtmlRoot(htmlRoot) : htmlRoot, {
|
|
47
|
+
...reactOptions,
|
|
48
48
|
identifierPrefix: SSR_HYDRATION_ID_PREFIX
|
|
49
49
|
});
|
|
50
50
|
const stream = htmlStream.pipeThrough(injectRSCPayload(rscPayloadStream, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './server/rsc/rsc.edge.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
export { createFromReadableStream } from 'react-server-dom-rspack/client.edge';
|
|
3
|
+
export { registerClientReference, registerServerReference, renderToReadableStream, } from 'react-server-dom-rspack/server.edge';
|
|
4
|
+
export declare const renderRsc: (options: {
|
|
5
|
+
element: ReactElement;
|
|
6
|
+
}) => ReadableStream<Uint8Array<ArrayBufferLike>>;
|
|
7
|
+
export declare const handleAction: (req: Request) => Promise<Response>;
|
|
8
|
+
export declare const renderCSRWithRSC: (options: {
|
|
9
|
+
html: string;
|
|
10
|
+
rscRoot: ReactElement;
|
|
11
|
+
}) => Promise<Response>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { ClientManifest } from '@modern-js/types/server';
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { type ReactNode } from 'react';
|
|
3
3
|
import { renderToReadableStream } from 'react-dom/server.edge';
|
|
4
4
|
type Options = {
|
|
5
5
|
request: Request;
|
|
6
6
|
routes?: unknown[];
|
|
7
|
+
/** Wrap only the HTML render tree, never the input serialized by Flight. */
|
|
8
|
+
wrapHtmlRoot?: (root: ReactNode) => ReactNode;
|
|
7
9
|
rscManifest?: {
|
|
8
10
|
clientManifest?: ClientManifest;
|
|
9
11
|
serverConsumerModuleMap?: unknown;
|
package/package.json
CHANGED
|
@@ -17,28 +17,27 @@
|
|
|
17
17
|
"modern",
|
|
18
18
|
"modern.js"
|
|
19
19
|
],
|
|
20
|
-
"version": "3.9.0-ultramodern.
|
|
20
|
+
"version": "3.9.0-ultramodern.21",
|
|
21
21
|
"files": [
|
|
22
22
|
"dist",
|
|
23
23
|
"hook.d.ts"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@modern-js/
|
|
27
|
-
"@modern-js/
|
|
28
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.2",
|
|
26
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.21",
|
|
27
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.21",
|
|
29
28
|
"@swc/helpers": "^0.5.23"
|
|
30
29
|
},
|
|
31
30
|
"devDependencies": {
|
|
32
|
-
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.
|
|
33
|
-
"@rslib/core": "1.0.
|
|
31
|
+
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.21",
|
|
32
|
+
"@rslib/core": "1.0.2",
|
|
34
33
|
"@scripts/build": "2.66.0",
|
|
35
34
|
"@scripts/rstest-config": "2.66.0",
|
|
36
|
-
"@types/node": "^26.
|
|
37
|
-
"@types/react": "^19.
|
|
38
|
-
"@types/react-dom": "^19.
|
|
35
|
+
"@types/node": "^26.6.2",
|
|
36
|
+
"@types/react": "^19.3.0",
|
|
37
|
+
"@types/react-dom": "^19.3.0",
|
|
39
38
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
40
|
-
"react": "^19.
|
|
41
|
-
"react-dom": "^19.
|
|
39
|
+
"react": "^19.3.0",
|
|
40
|
+
"react-dom": "^19.3.0",
|
|
42
41
|
"react-server-dom-rspack": "0.1.0",
|
|
43
42
|
"typescript": "^7.0.2"
|
|
44
43
|
},
|
|
@@ -59,12 +58,11 @@
|
|
|
59
58
|
},
|
|
60
59
|
"./rsc": {
|
|
61
60
|
"types": "./dist/types/server/rsc/index.d.ts",
|
|
61
|
+
"workerd": "./dist/esm/rsc.edge.mjs",
|
|
62
|
+
"worker": "./dist/esm/rsc.edge.mjs",
|
|
63
|
+
"edge-light": "./dist/esm/rsc.edge.mjs",
|
|
62
64
|
"default": "./dist/esm/rsc.mjs"
|
|
63
65
|
},
|
|
64
|
-
"./rsc-worker": {
|
|
65
|
-
"types": "./dist/types/rsc.worker.d.ts",
|
|
66
|
-
"default": "./dist/esm/rscWorker.mjs"
|
|
67
|
-
},
|
|
68
66
|
"./client": {
|
|
69
67
|
"types": "./dist/types/client/index.d.ts",
|
|
70
68
|
"default": "./dist/esm/client.mjs"
|
|
@@ -78,9 +76,6 @@
|
|
|
78
76
|
"rsc": [
|
|
79
77
|
"./dist/types/server/rsc/index.d.ts"
|
|
80
78
|
],
|
|
81
|
-
"rsc-worker": [
|
|
82
|
-
"./dist/types/rsc.worker.d.ts"
|
|
83
|
-
],
|
|
84
79
|
"client": [
|
|
85
80
|
"./dist/types/client/index.d.ts"
|
|
86
81
|
]
|
|
@@ -93,6 +88,6 @@
|
|
|
93
88
|
"scripts": {
|
|
94
89
|
"dev": "rslib build --watch",
|
|
95
90
|
"build": "rslib build",
|
|
96
|
-
"test": "tsgo --noEmit -p tsconfig.json && rstest
|
|
91
|
+
"test": "tsgo --noEmit -p tsconfig.json && rstest"
|
|
97
92
|
}
|
|
98
93
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './server/rsc/rsc.worker.js';
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export { renderToReadableStream } from 'react-server-dom-rspack/server.edge';
|
|
2
|
-
export { createFromReadableStream } from 'react-server-dom-rspack/client.edge';
|
|
3
|
-
export { registerClientReference, registerServerReference, } from 'react-server-dom-rspack/server.edge';
|
|
4
|
-
type RenderRscOptions = {
|
|
5
|
-
element: React.ReactElement;
|
|
6
|
-
};
|
|
7
|
-
export declare const renderRsc: (options: RenderRscOptions) => ReadableStream<Uint8Array<ArrayBufferLike>>;
|
|
8
|
-
export declare const renderCSRWithRSC: (options: {
|
|
9
|
-
html: string;
|
|
10
|
-
rscRoot: import("react").ReactElement;
|
|
11
|
-
}) => Promise<Response>;
|
|
12
|
-
export declare const handleAction: (req: Request) => Promise<Response>;
|
|
File without changes
|