@bleedingdev/modern-js-render 3.9.0-ultramodern.2 → 3.9.0-ultramodern.20

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.
@@ -1 +1 @@
1
- export { ElementsContext, RSCServerSlot, ResetRootContext, RscClientRoot, ServerElementsProvider, callServer, createFromFetch, createFromReadableStream, createServerReference, rscStream, setServerCallback } from "./341~0.mjs";
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 server_injectRSCPayload(rscStream, { injectClosingTags = true }) {
6
- if (injectClosingTags) return injectRSCPayload(rscStream);
4
+ function injectRSCPayload(rscStream, { injectClosingTags = true }) {
7
5
  const decoder = new TextDecoder();
8
- let resolveFlightDataPromise;
9
- const flightDataPromise = new Promise((resolve)=>resolveFlightDataPromise = resolve);
10
- let startedRSC = false;
11
- const buffered = [];
12
- let timeout = null;
13
- function flushBufferedChunks(controller) {
14
- let buf = '';
15
- for (const chunk of buffered)buf += decoder.decode(chunk, {
16
- stream: true
17
- });
18
- if (closingTagsPattern.test(buf)) buf = buf.replace(closingTagsPattern, '');
19
- if (buf) controller.enqueue(server_encoder.encode(buf));
20
- buffered.length = 0;
21
- timeout = null;
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
- return new TransformStream({
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
- buffered.push(chunk);
26
- if (timeout) return;
27
- timeout = setTimeout(async ()=>{
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 flightDataPromise;
37
- if (timeout) {
38
- clearTimeout(timeout);
39
- flushBufferedChunks(controller);
40
- }
41
- const remaining = decoder.decode();
42
- if (remaining) controller.enqueue(server_encoder.encode(remaining));
43
- if (injectClosingTags) controller.enqueue(server_encoder.encode('</body></html>'));
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(rscStream, controller) {
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
- for await (const chunk of rscStream)try {
52
- writeChunk(JSON.stringify(decoder.decode(chunk, {
53
- stream: true
54
- })), controller);
55
- } catch (err) {
56
- const base64 = JSON.stringify(btoa(String.fromCodePoint(...chunk)));
57
- writeChunk(`Uint8Array.from(atob(${base64}), m => m.codePointAt(0))`, controller);
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
- const buffered = [];
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 flushBufferedChunks(controller) {
84
- for (const chunk of buffered){
85
- let buf = decoder.decode(chunk);
86
- if (!cssInjected && buf.includes(headTrailer)) {
87
- buf = buf.replace(headTrailer, `${cssLinks}${headTrailer}`);
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
- buffered.length = 0;
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
- buffered.push(chunk);
98
- if (timeout) return;
99
- timeout = setTimeout(()=>{
100
- flushBufferedChunks(controller);
101
- }, 0);
134
+ writeHtml(decoder.decode(chunk, {
135
+ stream: true
136
+ }), controller);
102
137
  },
103
- async flush (controller) {
104
- if (timeout) {
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(server_injectRSCPayload(rscPayloadStream, {
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 rsc_worker_renderRsc = (options)=>{
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: rsc_worker_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, rsc_worker_renderRsc as renderRsc };
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 server_injectRSCPayload(rscStream, { injectClosingTags = true }) {
6
- if (injectClosingTags) return injectRSCPayload(rscStream);
4
+ function injectRSCPayload(rscStream, { injectClosingTags = true }) {
7
5
  const decoder = new TextDecoder();
8
- let resolveFlightDataPromise;
9
- const flightDataPromise = new Promise((resolve)=>resolveFlightDataPromise = resolve);
10
- let startedRSC = false;
11
- const buffered = [];
12
- let timeout = null;
13
- function flushBufferedChunks(controller) {
14
- let buf = '';
15
- for (const chunk of buffered)buf += decoder.decode(chunk, {
16
- stream: true
17
- });
18
- if (closingTagsPattern.test(buf)) buf = buf.replace(closingTagsPattern, '');
19
- if (buf) controller.enqueue(server_encoder.encode(buf));
20
- buffered.length = 0;
21
- timeout = null;
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
- return new TransformStream({
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
- buffered.push(chunk);
26
- if (timeout) return;
27
- timeout = setTimeout(async ()=>{
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 flightDataPromise;
37
- if (timeout) {
38
- clearTimeout(timeout);
39
- flushBufferedChunks(controller);
40
- }
41
- const remaining = decoder.decode();
42
- if (remaining) controller.enqueue(server_encoder.encode(remaining));
43
- if (injectClosingTags) controller.enqueue(server_encoder.encode('</body></html>'));
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(rscStream, controller) {
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
- for await (const chunk of rscStream)try {
52
- writeChunk(JSON.stringify(decoder.decode(chunk, {
53
- stream: true
54
- })), controller);
55
- } catch (err) {
56
- const base64 = JSON.stringify(btoa(String.fromCodePoint(...chunk)));
57
- writeChunk(`Uint8Array.from(atob(${base64}), m => m.codePointAt(0))`, controller);
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
- const buffered = [];
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 flushBufferedChunks(controller) {
84
- for (const chunk of buffered){
85
- let buf = decoder.decode(chunk);
86
- if (!cssInjected && buf.includes(headTrailer)) {
87
- buf = buf.replace(headTrailer, `${cssLinks}${headTrailer}`);
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
- buffered.length = 0;
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
- buffered.push(chunk);
98
- if (timeout) return;
99
- timeout = setTimeout(()=>{
100
- flushBufferedChunks(controller);
101
- }, 0);
134
+ writeHtml(decoder.decode(chunk, {
135
+ stream: true
136
+ }), controller);
102
137
  },
103
- async flush (controller) {
104
- if (timeout) {
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(server_injectRSCPayload(rscPayloadStream, {
160
+ })).pipeThrough(injectRSCPayload(rscPayloadStream, {
129
161
  injectClosingTags: true
130
162
  }));
131
163
  return new Response(stream, {
@@ -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 server_injectRSCPayload(rscStream, { injectClosingTags = true }) {
5
- if (injectClosingTags) return injectRSCPayload(rscStream);
3
+ function injectRSCPayload(rscStream, { injectClosingTags = true }) {
6
4
  const decoder = new TextDecoder();
7
- let resolveFlightDataPromise;
8
- const flightDataPromise = new Promise((resolve)=>resolveFlightDataPromise = resolve);
9
- let startedRSC = false;
10
- const buffered = [];
11
- let timeout = null;
12
- function flushBufferedChunks(controller) {
13
- let buf = '';
14
- for (const chunk of buffered)buf += decoder.decode(chunk, {
15
- stream: true
16
- });
17
- if (closingTagsPattern.test(buf)) buf = buf.replace(closingTagsPattern, '');
18
- if (buf) controller.enqueue(encoder.encode(buf));
19
- buffered.length = 0;
20
- timeout = null;
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
- return new TransformStream({
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
- buffered.push(chunk);
25
- if (timeout) return;
26
- timeout = setTimeout(async ()=>{
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 flightDataPromise;
36
- if (timeout) {
37
- clearTimeout(timeout);
38
- flushBufferedChunks(controller);
39
- }
40
- const remaining = decoder.decode();
41
- if (remaining) controller.enqueue(encoder.encode(remaining));
42
- if (injectClosingTags) controller.enqueue(encoder.encode('</body></html>'));
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(rscStream, controller) {
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
- for await (const chunk of rscStream)try {
51
- writeChunk(JSON.stringify(decoder.decode(chunk, {
52
- stream: true
53
- })), controller);
54
- } catch (err) {
55
- const base64 = JSON.stringify(btoa(String.fromCodePoint(...chunk)));
56
- writeChunk(`Uint8Array.from(atob(${base64}), m => m.codePointAt(0))`, controller);
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 { server_injectRSCPayload as injectRSCPayload };
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 "./341~0.mjs";
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
- ...options,
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
- rscRuntime,
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 htmlStream = await renderToReadableStream(/*#__PURE__*/ react.createElement(ServerElementsProvider, {
41
+ const htmlRoot = /*#__PURE__*/ react.createElement(ServerElementsProvider, {
43
42
  elements: elements
44
43
  }, /*#__PURE__*/ react.createElement(CSSLinks, {
45
44
  cssFiles: cssFiles
46
- }), children), {
47
- ...options,
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.2",
20
+ "version": "3.9.0-ultramodern.20",
21
21
  "files": [
22
22
  "dist",
23
23
  "hook.d.ts"
24
24
  ],
25
25
  "dependencies": {
26
- "@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.2",
27
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.2",
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.20",
27
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.20",
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.2",
33
- "@rslib/core": "1.0.0",
31
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.20",
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.4.1",
37
- "@types/react": "^19.2.18",
38
- "@types/react-dom": "^19.2.7",
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.2.8",
41
- "react-dom": "^19.2.8",
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 --passWithNoTests"
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