@bleedingdev/modern-js-render 3.8.3-ultramodern.6 → 3.9.0-ultramodern.10

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.mjs";
1
+ export { ElementsContext, RSCServerSlot, ResetRootContext, RscClientRoot, ServerElementsProvider, callServer, createFromFetch, createFromReadableStream, createServerReference, rscStream, setServerCallback } from "./341~0.mjs";
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,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,15 @@ const createHandleAction = ({ decodeReply, loadServerAction, renderRsc })=>async
231
263
  });
232
264
  }
233
265
  };
234
- const rsc_worker_renderRsc = (options)=>{
266
+ const rsc_renderRsc = (options)=>{
235
267
  const readable = renderToReadableStream(options.element);
236
268
  return readable;
237
269
  };
238
- const renderCSRWithRSC = createRenderCSRWithRSC(rsc_worker_renderRsc);
239
270
  const handleAction = createHandleAction({
240
271
  decodeReply: server_edge_decodeReply,
241
272
  loadServerAction: server_edge_loadServerAction,
242
- renderRsc: rsc_worker_renderRsc
273
+ renderRsc: rsc_renderRsc
243
274
  });
275
+ const renderCSRWithRSC = createRenderCSRWithRSC(rsc_renderRsc);
244
276
  export { createFromReadableStream } from "react-server-dom-rspack/client.edge";
245
- export { handleAction, registerClientReference, registerServerReference, renderCSRWithRSC, renderToReadableStream, rsc_worker_renderRsc as renderRsc };
277
+ export { handleAction, registerClientReference, registerServerReference, renderCSRWithRSC, renderToReadableStream, rsc_renderRsc as renderRsc };
@@ -0,0 +1,100 @@
1
+ const encoder = new TextEncoder();
2
+ const closingTagsPattern = /<\/body>\s*<\/html>\s*$/i;
3
+ function injectRSCPayload(rscStream, { injectClosingTags = true }) {
4
+ const decoder = new TextDecoder();
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;
20
+ }
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 = {
53
+ transform (chunk, controller) {
54
+ return writeHtml(decoder.decode(chunk, {
55
+ stream: true
56
+ }), controller);
57
+ },
58
+ async flush (controller) {
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);
67
+ }
68
+ };
69
+ return new TransformStream(transformer);
70
+ }
71
+ async function writeRSCStream(reader, controller) {
72
+ const decoder = new TextDecoder('utf-8', {
73
+ fatal: true,
74
+ ignoreBOM: true
75
+ });
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();
92
+ }
93
+ }
94
+ function writeChunk(chunk, controller) {
95
+ controller.enqueue(encoder.encode(`<script>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}</script>`));
96
+ }
97
+ function escapeScript(script) {
98
+ return script.replace(/<!--/g, '<\\!--').replace(/<\/(script)/gi, '</\\$1');
99
+ }
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.mjs";
4
+ import { ServerElementsProvider } from "./341~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,13 +16,13 @@ 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 {
@@ -30,7 +30,7 @@ const renderSSRStream = async (children, options)=>{
30
30
  const [{ renderRsc }, { createFromReadableStream }, { injectRSCPayload }] = await Promise.all([
31
31
  rscRuntime,
32
32
  import("react-server-dom-rspack/client.edge"),
33
- import("./0~server.mjs")
33
+ import("./server~0.mjs")
34
34
  ]);
35
35
  const rscStream = await renderRsc({
36
36
  element: rscRoot || children
@@ -39,12 +39,13 @@ const renderSSRStream = async (children, options)=>{
39
39
  const elements = createFromReadableStream(rscElementStream);
40
40
  let cssFiles = [];
41
41
  if (!hasRoutes && entryCssFiles) cssFiles = Object.values(entryCssFiles).flat();
42
- const htmlStream = await renderToReadableStream(/*#__PURE__*/ react.createElement(ServerElementsProvider, {
42
+ const htmlRoot = /*#__PURE__*/ react.createElement(ServerElementsProvider, {
43
43
  elements: elements
44
44
  }, /*#__PURE__*/ react.createElement(CSSLinks, {
45
45
  cssFiles: cssFiles
46
- }), children), {
47
- ...options,
46
+ }), children);
47
+ const htmlStream = await renderToReadableStream(wrapHtmlRoot ? wrapHtmlRoot(htmlRoot) : htmlRoot, {
48
+ ...reactOptions,
48
49
  identifierPrefix: SSR_HYDRATION_ID_PREFIX
49
50
  });
50
51
  const stream = htmlStream.pipeThrough(injectRSCPayload(rscPayloadStream, {
@@ -1,7 +1,7 @@
1
1
  import React, { type ReactNode } from 'react';
2
2
  import { createFromFetch, createFromReadableStream, createServerReference, setServerCallback } from 'react-server-dom-rspack/client.browser';
3
- export { rscStream } from '../rsc-html-stream/client';
4
- export { callServer } from './callServer';
3
+ export { rscStream } from '../rsc-html-stream/client.js';
4
+ export { callServer } from './callServer.js';
5
5
  export { createFromFetch, createFromReadableStream, createServerReference };
6
6
  declare global {
7
7
  interface Window {
@@ -1 +1 @@
1
- export * from './client/index';
1
+ export * from './client/index.js';
@@ -1 +1 @@
1
- export * from './server/rsc';
1
+ export * from './server/rsc/index.js';
@@ -1 +1 @@
1
- export * from './server/rsc/rsc.worker';
1
+ export * from './server/rsc/index.js';
@@ -1,2 +1,2 @@
1
- export * from './csr';
2
- export * from './rsc';
1
+ export * from './csr.js';
2
+ export * from './rsc.js';
@@ -1 +1 @@
1
- export * from './ssr';
1
+ export * from './ssr.js';
@@ -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;
@@ -1 +1 @@
1
- export * from './server/ssr';
1
+ export * from './server/ssr/index.js';
package/package.json CHANGED
@@ -17,25 +17,24 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.8.3-ultramodern.6",
20
+ "version": "3.9.0-ultramodern.10",
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.8.3-ultramodern.6",
27
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.8.3-ultramodern.6",
28
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.8.3-ultramodern.6",
26
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.10",
27
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.10",
29
28
  "@swc/helpers": "^0.5.23"
30
29
  },
31
30
  "devDependencies": {
32
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.8.3-ultramodern.6",
33
- "@rslib/core": "0.23.2",
31
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.10",
32
+ "@rslib/core": "1.0.0",
34
33
  "@scripts/build": "2.66.0",
35
34
  "@scripts/rstest-config": "2.66.0",
36
- "@types/node": "^26.2.0",
35
+ "@types/node": "^26.4.1",
37
36
  "@types/react": "^19.2.18",
38
- "@types/react-dom": "^19.2.4",
37
+ "@types/react-dom": "^19.2.7",
39
38
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
40
39
  "react": "^19.2.8",
41
40
  "react-dom": "^19.2.8",
@@ -1,112 +0,0 @@
1
- import { injectRSCPayload } from "@modern-js/runtime-extensions/rsc-html-stream";
2
- const encoder = new TextEncoder();
3
- const closingTagsPattern = /<\/body>\s*<\/html>\s*$/i;
4
- function server_injectRSCPayload(rscStream, { injectClosingTags = true }) {
5
- if (injectClosingTags) return injectRSCPayload(rscStream);
6
- 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;
21
- }
22
- return new TransformStream({
23
- 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);
33
- },
34
- 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>'));
43
- }
44
- });
45
- }
46
- async function writeRSCStream(rscStream, controller) {
47
- const decoder = new TextDecoder('utf-8', {
48
- fatal: true
49
- });
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);
57
- }
58
- const remaining = decoder.decode();
59
- if (remaining.length) writeChunk(JSON.stringify(remaining), controller);
60
- }
61
- function writeChunk(chunk, controller) {
62
- controller.enqueue(encoder.encode(`<script>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}</script>`));
63
- }
64
- function escapeScript(script) {
65
- return script.replace(/<!--/g, '<\\!--').replace(/<\/(script)/gi, '</\\$1');
66
- }
67
- function injectCSS(cssFiles, { injectClosingTags = true } = {}) {
68
- if (0 === cssFiles.length) return new TransformStream({
69
- transform (chunk, controller) {
70
- controller.enqueue(chunk);
71
- },
72
- flush (controller) {
73
- if (injectClosingTags) controller.enqueue(encoder.encode('</body></html>'));
74
- }
75
- });
76
- const decoder = new TextDecoder();
77
- const headTrailer = '</head>';
78
- const buffered = [];
79
- let timeout = null;
80
- let cssInjected = false;
81
- const cssLinks = cssFiles.map((css)=>`<link href="${css}" rel="stylesheet" />`).join('');
82
- function flushBufferedChunks(controller) {
83
- for (const chunk of buffered){
84
- let buf = decoder.decode(chunk);
85
- if (!cssInjected && buf.includes(headTrailer)) {
86
- buf = buf.replace(headTrailer, `${cssLinks}${headTrailer}`);
87
- cssInjected = true;
88
- }
89
- controller.enqueue(encoder.encode(buf));
90
- }
91
- buffered.length = 0;
92
- timeout = null;
93
- }
94
- return new TransformStream({
95
- transform (chunk, controller) {
96
- buffered.push(chunk);
97
- if (timeout) return;
98
- timeout = setTimeout(()=>{
99
- flushBufferedChunks(controller);
100
- }, 0);
101
- },
102
- async flush (controller) {
103
- if (timeout) {
104
- clearTimeout(timeout);
105
- flushBufferedChunks(controller);
106
- }
107
- if (!cssInjected) controller.enqueue(encoder.encode(cssLinks));
108
- if (injectClosingTags) controller.enqueue(encoder.encode('</body></html>'));
109
- }
110
- });
111
- }
112
- export { injectCSS, server_injectRSCPayload as injectRSCPayload };
@@ -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