@bleedingdev/modern-js-runtime 3.9.0-ultramodern.9 → 3.9.3-ultramodern.1

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.
Files changed (130) hide show
  1. package/dist/cjs/cli/code.js +2 -2
  2. package/dist/cjs/cli/index.js +0 -7
  3. package/dist/cjs/cli/ssr/loadable-bundler-plugin.js +2 -0
  4. package/dist/cjs/cli/template.server.js +1 -2
  5. package/dist/cjs/core/browser/hydrate.js +3 -9
  6. package/dist/cjs/core/browser/index.js +4 -5
  7. package/dist/cjs/core/context/index.js +8 -2
  8. package/dist/cjs/core/context/public.js +4 -4
  9. package/dist/cjs/core/context/runtime.js +3 -9
  10. package/dist/cjs/core/index.js +3 -3
  11. package/dist/cjs/core/plugin/index.js +2 -2
  12. package/dist/cjs/core/react/index.js +3 -3
  13. package/dist/cjs/core/react/wrapper.js +7 -8
  14. package/dist/cjs/core/server/requestHandler.js +253 -25
  15. package/dist/cjs/core/server/stream/beforeTemplate.js +3 -3
  16. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +2 -2
  17. package/dist/cjs/core/server/stream/createReadableStream.js +51 -19
  18. package/dist/cjs/core/server/stream/createReadableStream.worker.js +54 -27
  19. package/dist/cjs/core/server/stream/deferredScript.js +12 -6
  20. package/dist/cjs/core/server/stream/deferredScriptOutputCoordinator.js +370 -0
  21. package/dist/cjs/core/server/stream/shared.js +4 -0
  22. package/dist/cjs/core/server/string/index.js +6 -4
  23. package/dist/cjs/core/server/string/loadable.js +4 -4
  24. package/dist/cjs/document/cli/index.js +14 -5
  25. package/dist/cjs/exports/head.js +2 -2
  26. package/dist/cjs/internal.js +2 -2
  27. package/dist/cjs/router/cli/code/nestedRoutes.js +1 -2
  28. package/dist/cjs/router/cli/code/templates.js +2 -2
  29. package/dist/cjs/router/cli/code/utils.js +5 -4
  30. package/dist/cjs/router/runtime/DeferredDataScripts.node.js +13 -10
  31. package/dist/cjs/router/runtime/PrefetchLink.js +4 -4
  32. package/dist/cjs/router/runtime/hooks.js +6 -7
  33. package/dist/cjs/router/runtime/plugin.js +22 -27
  34. package/dist/cjs/router/runtime/plugin.node.js +8 -9
  35. package/dist/esm/cli/code.mjs +2 -2
  36. package/dist/esm/cli/index.mjs +0 -7
  37. package/dist/esm/cli/ssr/loadable-bundler-plugin.mjs +2 -0
  38. package/dist/esm/cli/template.server.mjs +1 -2
  39. package/dist/esm/core/browser/hydrate.mjs +3 -9
  40. package/dist/esm/core/browser/index.mjs +1 -2
  41. package/dist/esm/core/context/index.mjs +1 -1
  42. package/dist/esm/core/context/public.mjs +1 -1
  43. package/dist/esm/core/context/runtime.mjs +3 -9
  44. package/dist/esm/core/index.mjs +1 -1
  45. package/dist/esm/core/plugin/index.mjs +1 -1
  46. package/dist/esm/core/react/index.mjs +1 -1
  47. package/dist/esm/core/react/wrapper.mjs +1 -2
  48. package/dist/esm/core/server/requestHandler.mjs +223 -19
  49. package/dist/esm/core/server/stream/beforeTemplate.mjs +3 -3
  50. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +2 -2
  51. package/dist/esm/core/server/stream/createReadableStream.mjs +48 -16
  52. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +53 -26
  53. package/dist/esm/core/server/stream/deferredScript.mjs +12 -6
  54. package/dist/esm/core/server/stream/deferredScriptOutputCoordinator.mjs +332 -0
  55. package/dist/esm/core/server/stream/shared.mjs +2 -1
  56. package/dist/esm/core/server/string/index.mjs +3 -1
  57. package/dist/esm/core/server/string/loadable.mjs +4 -4
  58. package/dist/esm/document/cli/index.mjs +12 -6
  59. package/dist/esm/exports/head.mjs +1 -1
  60. package/dist/esm/internal.mjs +1 -1
  61. package/dist/esm/router/cli/code/nestedRoutes.mjs +1 -2
  62. package/dist/esm/router/cli/code/templates.mjs +2 -2
  63. package/dist/esm/router/cli/code/utils.mjs +6 -5
  64. package/dist/esm/router/runtime/DeferredDataScripts.node.mjs +13 -10
  65. package/dist/esm/router/runtime/PrefetchLink.mjs +1 -1
  66. package/dist/esm/router/runtime/hooks.mjs +6 -7
  67. package/dist/esm/router/runtime/plugin.mjs +14 -19
  68. package/dist/esm/router/runtime/plugin.node.mjs +3 -4
  69. package/dist/esm-node/cli/code.mjs +2 -2
  70. package/dist/esm-node/cli/index.mjs +1 -9
  71. package/dist/esm-node/cli/ssr/loadable-bundler-plugin.mjs +2 -0
  72. package/dist/esm-node/cli/template.server.mjs +1 -2
  73. package/dist/esm-node/core/browser/hydrate.mjs +3 -9
  74. package/dist/esm-node/core/browser/index.mjs +1 -2
  75. package/dist/esm-node/core/context/index.mjs +1 -1
  76. package/dist/esm-node/core/context/public.mjs +1 -1
  77. package/dist/esm-node/core/context/runtime.mjs +3 -9
  78. package/dist/esm-node/core/index.mjs +1 -1
  79. package/dist/esm-node/core/plugin/index.mjs +1 -1
  80. package/dist/esm-node/core/react/index.mjs +1 -1
  81. package/dist/esm-node/core/react/wrapper.mjs +1 -2
  82. package/dist/esm-node/core/server/requestHandler.mjs +223 -19
  83. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +3 -3
  84. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +2 -2
  85. package/dist/esm-node/core/server/stream/createReadableStream.mjs +48 -16
  86. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +53 -26
  87. package/dist/esm-node/core/server/stream/deferredScript.mjs +12 -6
  88. package/dist/esm-node/core/server/stream/deferredScriptOutputCoordinator.mjs +333 -0
  89. package/dist/esm-node/core/server/stream/shared.mjs +2 -1
  90. package/dist/esm-node/core/server/string/index.mjs +3 -1
  91. package/dist/esm-node/core/server/string/loadable.mjs +4 -4
  92. package/dist/esm-node/document/cli/index.mjs +12 -6
  93. package/dist/esm-node/exports/head.mjs +1 -1
  94. package/dist/esm-node/internal.mjs +1 -1
  95. package/dist/esm-node/router/cli/code/nestedRoutes.mjs +1 -2
  96. package/dist/esm-node/router/cli/code/templates.mjs +2 -2
  97. package/dist/esm-node/router/cli/code/utils.mjs +6 -5
  98. package/dist/esm-node/router/runtime/DeferredDataScripts.node.mjs +13 -10
  99. package/dist/esm-node/router/runtime/PrefetchLink.mjs +1 -1
  100. package/dist/esm-node/router/runtime/hooks.mjs +6 -7
  101. package/dist/esm-node/router/runtime/plugin.mjs +14 -19
  102. package/dist/esm-node/router/runtime/plugin.node.mjs +3 -4
  103. package/dist/types/common.d.ts +2 -8
  104. package/dist/types/core/context/index.d.ts +1 -1
  105. package/dist/types/core/context/public.d.ts +1 -1
  106. package/dist/types/core/index.d.ts +1 -1
  107. package/dist/types/core/react/wrapper.d.ts +1 -1
  108. package/dist/types/core/server/requestHandler.d.ts +30 -1
  109. package/dist/types/core/server/stream/deferredScript.d.ts +1 -1
  110. package/dist/types/core/server/stream/deferredScriptOutputCoordinator.d.ts +72 -0
  111. package/dist/types/core/server/stream/shared.d.ts +14 -0
  112. package/dist/types/document/cli/index.d.ts +1 -0
  113. package/dist/types/internal.d.ts +1 -1
  114. package/dist/types/router/cli/code/utils.d.ts +1 -1
  115. package/dist/types/router/runtime/hooks.d.ts +12 -16
  116. package/package.json +32 -26
  117. package/rslib.config.mts +3 -0
  118. package/rstest.config.mts +0 -4
  119. package/dist/cjs/core/server/requestResponse.js +0 -107
  120. package/dist/cjs/core/server/routerCleanup.js +0 -129
  121. package/dist/cjs/rsc/server.worker.js +0 -62
  122. package/dist/esm/core/server/requestResponse.mjs +0 -63
  123. package/dist/esm/core/server/routerCleanup.mjs +0 -82
  124. package/dist/esm/rsc/server.worker.mjs +0 -1
  125. package/dist/esm-node/core/server/requestResponse.mjs +0 -64
  126. package/dist/esm-node/core/server/routerCleanup.mjs +0 -83
  127. package/dist/esm-node/rsc/server.worker.mjs +0 -2
  128. package/dist/types/core/server/requestResponse.d.ts +0 -15
  129. package/dist/types/core/server/routerCleanup.d.ts +0 -31
  130. package/dist/types/rsc/server.worker.d.ts +0 -1
@@ -1,14 +1,16 @@
1
1
  import { renderSSRStream } from "@modern-js/render/ssr";
2
+ import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "@modern-js/runtime/context";
2
3
  import { storage } from "@modern-js/runtime-utils/node";
3
4
  import react from "react";
4
5
  import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
5
6
  import { RenderLevel } from "../../constants.mjs";
6
- import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "../../context/index.mjs";
7
+ import { getMonitors } from "../../context/monitors/index.mjs";
7
8
  import { wrapRuntimeComponentResolver } from "../../react/wrapper.mjs";
8
9
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
9
10
  import { createSSRRenderLifecycle, createSSRStreamErrorReporter, observeSSRStream, orderSSRStreamTransforms } from "../shared.mjs";
10
11
  import { enqueueFromEntries } from "./deferredScript.mjs";
11
- import { ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
12
+ import { DeferredScriptOutputCoordinator } from "./deferredScriptOutputCoordinator.mjs";
13
+ import { SHELL_PROGRESSIVE_CHUNK_SIZE, ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
12
14
  import { getTemplates } from "./template.mjs";
13
15
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
14
16
  const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, resource, rscManifest, rscRoot } = options;
@@ -21,6 +23,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
21
23
  config,
22
24
  platform: 'web',
23
25
  mode: 'stream',
26
+ monitors: getMonitors(),
24
27
  isRsc,
25
28
  terminalMarker: ESCAPED_SHELL_STREAM_END_MARK
26
29
  }) || [];
@@ -33,6 +36,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
33
36
  let pendingSource;
34
37
  let bodyOpen = true;
35
38
  let bodyPipe;
39
+ let coordinator;
36
40
  const templateOptions = {
37
41
  runtimeContext,
38
42
  ssrConfig,
@@ -51,6 +55,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
51
55
  request,
52
56
  signal: request.signal,
53
57
  nonce: config.nonce,
58
+ progressiveChunkSize: SHELL_PROGRESSIVE_CHUNK_SIZE,
54
59
  rscManifest,
55
60
  rscRoot: rscRoot,
56
61
  routes: runtimeContext.routes,
@@ -79,66 +84,87 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
79
84
  const decoder = new TextDecoder();
80
85
  const encoder = new TextEncoder();
81
86
  const pendingScripts = [];
82
- let buffered = '';
87
+ const buffered = [];
88
+ let bufferedLength = 0;
89
+ let markerTail = '';
83
90
  let shellChunkStatus = ShellChunkStatus.START;
84
91
  let bodyController;
85
- const emit = (chunk, controller)=>{
92
+ let deferredResolversComplete = Promise.resolve();
93
+ coordinator = new DeferredScriptOutputCoordinator((content)=>{
94
+ if (!bodyOpen) return;
95
+ try {
96
+ bodyController.enqueue(encoder.encode(content));
97
+ } catch {
98
+ bodyOpen = false;
99
+ }
100
+ });
101
+ const emit = (chunk)=>{
86
102
  if (shellChunkStatus === ShellChunkStatus.FINISH) {
87
- if (chunk.length > 0) controller.enqueue(encoder.encode(chunk));
103
+ if (chunk.length > 0) coordinator?.writeReact(chunk);
104
+ return;
105
+ }
106
+ const window = markerTail + chunk;
107
+ const windowIndex = window.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
108
+ const markerIndex = bufferedLength - markerTail.length + windowIndex;
109
+ buffered.push(chunk);
110
+ bufferedLength += chunk.length;
111
+ if (-1 === windowIndex) {
112
+ markerTail = window.slice(Math.max(0, window.length - ESCAPED_SHELL_STREAM_END_MARK.length + 1));
88
113
  return;
89
114
  }
90
- buffered += chunk;
91
- const markerIndex = buffered.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
92
- if (-1 === markerIndex) return;
93
- const beforeMark = lifecycle.completedBody(buffered.slice(0, markerIndex), 'shell');
94
- const afterMark = buffered.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
115
+ const shell = buffered.join('');
116
+ const beforeMark = lifecycle.completedBody(shell.slice(0, markerIndex), 'shell');
117
+ const afterMark = shell.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
95
118
  const completedShellBefore = createReplaceHelemt(getHelmetData(extenders))(shellBefore);
96
119
  shellChunkStatus = ShellChunkStatus.FINISH;
97
- buffered = '';
98
- controller.enqueue(encoder.encode(`${completedShellBefore}${beforeMark}${shellAfter}`));
99
- if (afterMark.length > 0) controller.enqueue(encoder.encode(afterMark));
100
- for (const script of pendingScripts)controller.enqueue(encoder.encode(script));
120
+ buffered.length = 0;
121
+ coordinator?.writeReact(`${completedShellBefore}${beforeMark}${shellAfter}`);
122
+ if (afterMark.length > 0) coordinator?.writeReact(afterMark);
123
+ coordinator?.markShellFinished();
124
+ for (const script of pendingScripts)coordinator?.enqueueResolver(script);
101
125
  pendingScripts.length = 0;
102
126
  };
103
127
  const body = new TransformStream({
104
128
  start (controller) {
105
129
  bodyController = controller;
106
130
  },
107
- transform (chunk, controller) {
131
+ transform (chunk) {
108
132
  emit(decoder.decode(chunk, {
109
133
  stream: true
110
- }), controller);
134
+ }));
111
135
  },
112
- flush (controller) {
113
- bodyOpen = false;
114
- emit(decoder.decode(), controller);
136
+ async flush () {
137
+ emit(decoder.decode());
115
138
  if (shellChunkStatus !== ShellChunkStatus.FINISH) throw new Error('React SSR stream ended before the shell marker');
139
+ await deferredResolversComplete;
140
+ coordinator?.finish();
141
+ bodyOpen = false;
116
142
  }
117
143
  });
118
144
  bodyPipe = pendingSource.pipeTo(body.writable);
119
145
  bodyPipe.catch(()=>{});
120
146
  pendingSource = body.readable;
121
- const activeDeferreds = storage.useContext?.()?.activeDeferreds;
147
+ const storageContext = storage.useContext?.();
148
+ const activeDeferreds = storageContext?.activeDeferreds;
149
+ const deferredScriptKeys = storageContext?.deferredScriptKeys;
122
150
  const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
123
- enqueueFromEntries(entries, config.nonce, (script)=>{
151
+ if (entries.length > 0) deferredResolversComplete = enqueueFromEntries(entries, deferredScriptKeys, config.nonce, (script)=>{
124
152
  if (!bodyOpen) return;
125
- if (shellChunkStatus === ShellChunkStatus.FINISH) try {
126
- bodyController.enqueue(encoder.encode(script));
127
- } catch {
128
- bodyOpen = false;
129
- }
153
+ if (shellChunkStatus === ShellChunkStatus.FINISH) coordinator?.enqueueResolver(script);
130
154
  else pendingScripts.push(script);
131
155
  });
132
156
  return observeSSRStream(pendingSource, {
133
157
  lifecycle,
134
158
  async onError (error) {
135
159
  bodyOpen = false;
160
+ coordinator?.abort();
136
161
  await bodyPipe?.catch(()=>{});
137
162
  reportError(error);
138
163
  },
139
164
  signal: request.signal,
140
165
  async onCancel (reason) {
141
166
  bodyOpen = false;
167
+ coordinator?.abort();
142
168
  await bodyPipe?.catch((error)=>{
143
169
  if (error !== reason) throw error;
144
170
  });
@@ -147,6 +173,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
147
173
  });
148
174
  } catch (error) {
149
175
  bodyOpen = false;
176
+ coordinator?.abort();
150
177
  if (void 0 !== pendingSource) try {
151
178
  await pendingSource.cancel(error);
152
179
  await bodyPipe?.catch(()=>{});
@@ -44,23 +44,29 @@ function buildDeferredDataScript(nonce, args) {
44
44
  const nonceAttr = void 0 !== nonce && '' !== nonce ? ` nonce="${nonce}"` : '';
45
45
  return `<script async${nonceAttr} data-fn-name="r" data-script-src="modern-run-router-data-fn" data-fn-args='${escaped}' suppressHydrationWarning>${runRouterDataFnStr}</script>`;
46
46
  }
47
- function enqueueFromEntries(entries, nonce, emit) {
47
+ function enqueueFromEntries(entries, deferredScriptKeys, nonce, emit) {
48
+ const pendingResolvers = [];
48
49
  entries.forEach(([routeId, value])=>{
49
50
  if (!isDeferredDataLike(value)) return;
50
- const pendingKeys = new Set(value.pendingKeys ?? []);
51
- pendingKeys.forEach((key)=>{
51
+ const serializedKeys = void 0 !== deferredScriptKeys ? deferredScriptKeys.get(routeId) ?? [] : value.pendingKeys ?? [];
52
+ serializedKeys.forEach((key)=>{
52
53
  const tracked = value.data?.[key];
53
- if (isPromiseLike(tracked)) tracked.then((val)=>emit(buildDeferredDataScript(nonce, [
54
+ if (isPromiseLike(tracked)) pendingResolvers.push(Promise.resolve(tracked).then((val)=>{
55
+ emit(buildDeferredDataScript(nonce, [
54
56
  routeId,
55
57
  key,
56
58
  val
57
- ])), (err)=>emit(buildDeferredDataScript(nonce, [
59
+ ]));
60
+ }, (err)=>{
61
+ emit(buildDeferredDataScript(nonce, [
58
62
  routeId,
59
63
  key,
60
64
  void 0,
61
65
  toErrorInfo(err)
62
- ])));
66
+ ]));
67
+ }));
63
68
  });
64
69
  });
70
+ return Promise.all(pendingResolvers).then(()=>void 0);
65
71
  }
66
72
  export { buildDeferredDataScript, enqueueFromEntries, escapeAttr, isDeferredDataLike, isPromiseLike, isRecord, toErrorInfo };
@@ -0,0 +1,332 @@
1
+ import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
2
+ const VOID_ELEMENTS = new Set([
3
+ 'area',
4
+ 'base',
5
+ 'br',
6
+ 'col',
7
+ 'embed',
8
+ 'hr',
9
+ 'img',
10
+ 'input',
11
+ 'link',
12
+ 'meta',
13
+ 'param',
14
+ 'source',
15
+ 'track',
16
+ 'wbr'
17
+ ]);
18
+ const RAW_TEXT_ELEMENTS = new Set([
19
+ 'iframe',
20
+ 'noembed',
21
+ 'noframes',
22
+ "script",
23
+ 'style',
24
+ 'textarea',
25
+ 'title',
26
+ 'xmp'
27
+ ]);
28
+ const REACT_SEGMENT_ID_PATTERN = new RegExp(`^${SSR_HYDRATION_ID_PREFIX}S:[0-9a-f]+$`);
29
+ const TABLE_SEGMENT_CHILDREN = new Set([
30
+ 'tbody',
31
+ 'tr',
32
+ 'colgroup'
33
+ ]);
34
+ function isAsciiAlpha(char) {
35
+ return /[A-Za-z]/.test(char);
36
+ }
37
+ function isWhitespace(char) {
38
+ return /[\t\n\f\r ]/.test(char);
39
+ }
40
+ function getSuffix(value, pattern) {
41
+ const start = Math.max(0, value.length - pattern.length);
42
+ for(let index = start; index < value.length; index++){
43
+ const suffix = value.slice(index);
44
+ if (pattern.startsWith(suffix)) return suffix;
45
+ }
46
+ return '';
47
+ }
48
+ class DeferredScriptOutputCoordinator {
49
+ enqueueResolver(script) {
50
+ if (this.closed) return;
51
+ this.pendingResolvers.push(script);
52
+ this.flushResolvers();
53
+ }
54
+ markShellFinished() {
55
+ if (this.closed) return;
56
+ this.shellFinished = true;
57
+ this.flushResolvers();
58
+ }
59
+ writeReact(chunk) {
60
+ if (this.closed || '' === chunk) return;
61
+ this.flushResolvers();
62
+ let emittedUntil = 0;
63
+ for(let index = 0; index < chunk.length; index++){
64
+ const wasSafe = this.isSafeBoundary();
65
+ this.consume(chunk[index]);
66
+ if (!wasSafe && this.isSafeBoundary() && this.pendingResolvers.length > 0) {
67
+ this.emit(chunk.slice(emittedUntil, index + 1));
68
+ emittedUntil = index + 1;
69
+ this.flushResolvers();
70
+ }
71
+ }
72
+ if (emittedUntil < chunk.length) this.emit(chunk.slice(emittedUntil));
73
+ }
74
+ finish() {
75
+ if (this.closed) return;
76
+ this.flushResolvers();
77
+ this.closed = true;
78
+ if (this.pendingResolvers.length > 0) throw new Error("Cannot emit deferred resolver scripts because the React stream ended outside a safe HTML boundary.");
79
+ }
80
+ abort() {
81
+ this.closed = true;
82
+ this.pendingResolvers.length = 0;
83
+ }
84
+ isSafeBoundary() {
85
+ return this.shellFinished && 'data' === this.state && 0 === this.openElements.length && !this.awaitingContinuationProtocol;
86
+ }
87
+ flushResolvers() {
88
+ if (!this.isSafeBoundary() || 0 === this.pendingResolvers.length) return;
89
+ while(this.pendingResolvers.length > 0){
90
+ const resolver = this.pendingResolvers.shift();
91
+ if (void 0 !== resolver) this.emit(resolver);
92
+ }
93
+ }
94
+ consume(char) {
95
+ switch(this.state){
96
+ case 'data':
97
+ if ('<' === char) this.state = 'tag-open';
98
+ return;
99
+ case 'tag-open':
100
+ if ('/' === char) {
101
+ this.currentTagName = '';
102
+ this.state = 'end-tag-name';
103
+ } else if ('!' === char) {
104
+ this.declarationPrefix = '';
105
+ this.state = 'markup-declaration';
106
+ } else if ('?' === char) this.state = 'bogus-comment';
107
+ else if (isAsciiAlpha(char)) {
108
+ this.startTag(char);
109
+ this.state = 'start-tag-name';
110
+ } else this.state = 'data';
111
+ return;
112
+ case 'start-tag-name':
113
+ if (isWhitespace(char)) this.state = 'before-attribute-name';
114
+ else if ('/' === char) this.state = 'self-closing-start-tag';
115
+ else if ('>' === char) this.completeStartTag(false);
116
+ else this.currentTagName += char.toLowerCase();
117
+ return;
118
+ case 'before-attribute-name':
119
+ if (isWhitespace(char)) return;
120
+ if ('/' === char) this.state = 'self-closing-start-tag';
121
+ else if ('>' === char) this.completeStartTag(false);
122
+ else {
123
+ this.startAttribute(char);
124
+ this.state = 'attribute-name';
125
+ }
126
+ return;
127
+ case 'attribute-name':
128
+ if (isWhitespace(char)) this.state = 'after-attribute-name';
129
+ else if ('=' === char) {
130
+ this.currentAttributeHasValue = true;
131
+ this.state = 'before-attribute-value';
132
+ } else if ('/' === char) {
133
+ this.completeAttribute();
134
+ this.state = 'self-closing-start-tag';
135
+ } else if ('>' === char) this.completeStartTag(false);
136
+ else this.currentAttributeName += char.toLowerCase();
137
+ return;
138
+ case 'after-attribute-name':
139
+ if (isWhitespace(char)) return;
140
+ if ('=' === char) {
141
+ this.currentAttributeHasValue = true;
142
+ this.state = 'before-attribute-value';
143
+ } else if ('/' === char) {
144
+ this.completeAttribute();
145
+ this.state = 'self-closing-start-tag';
146
+ } else if ('>' === char) this.completeStartTag(false);
147
+ else {
148
+ this.completeAttribute();
149
+ this.startAttribute(char);
150
+ this.state = 'attribute-name';
151
+ }
152
+ return;
153
+ case 'before-attribute-value':
154
+ if (isWhitespace(char)) return;
155
+ if ('"' === char) this.state = 'attribute-value-double-quoted';
156
+ else if ("'" === char) this.state = 'attribute-value-single-quoted';
157
+ else if ('>' === char) this.completeStartTag(false);
158
+ else {
159
+ this.currentAttributeValue += char;
160
+ this.state = 'attribute-value-unquoted';
161
+ }
162
+ return;
163
+ case 'attribute-value-double-quoted':
164
+ if ('"' === char) {
165
+ this.completeAttribute();
166
+ this.state = 'before-attribute-name';
167
+ } else this.currentAttributeValue += char;
168
+ return;
169
+ case 'attribute-value-single-quoted':
170
+ if ("'" === char) {
171
+ this.completeAttribute();
172
+ this.state = 'before-attribute-name';
173
+ } else this.currentAttributeValue += char;
174
+ return;
175
+ case 'attribute-value-unquoted':
176
+ if (isWhitespace(char)) {
177
+ this.completeAttribute();
178
+ this.state = 'before-attribute-name';
179
+ } else if ('>' === char) this.completeStartTag(false);
180
+ else this.currentAttributeValue += char;
181
+ return;
182
+ case 'self-closing-start-tag':
183
+ if ('>' === char) this.completeStartTag(true);
184
+ else if (!isWhitespace(char)) {
185
+ this.startAttribute(char);
186
+ this.state = 'attribute-name';
187
+ }
188
+ return;
189
+ case 'end-tag-name':
190
+ if (isWhitespace(char)) this.state = 'after-end-tag-name';
191
+ else if ('>' === char) this.completeEndTag();
192
+ else this.currentTagName += char.toLowerCase();
193
+ return;
194
+ case 'after-end-tag-name':
195
+ if ('>' === char) this.completeEndTag();
196
+ return;
197
+ case 'markup-declaration':
198
+ if (this.declarationPrefix.length < 2 && '-' === char) {
199
+ this.declarationPrefix += char;
200
+ if ('--' === this.declarationPrefix) {
201
+ this.commentTail = '';
202
+ this.state = 'comment';
203
+ }
204
+ } else this.state = '>' === char ? 'data' : 'declaration';
205
+ return;
206
+ case 'declaration':
207
+ if ('>' === char) this.state = 'data';
208
+ return;
209
+ case 'comment':
210
+ this.commentTail = `${this.commentTail}${char}`.slice(-3);
211
+ if ('-->' === this.commentTail) this.state = 'data';
212
+ return;
213
+ case 'bogus-comment':
214
+ if ('>' === char) this.state = 'data';
215
+ return;
216
+ case 'raw-text':
217
+ this.consumeRawText(char);
218
+ return;
219
+ case 'raw-end-tag':
220
+ if ('>' === char) this.completeRawTextEndTag();
221
+ else if (!isWhitespace(char)) {
222
+ this.state = 'raw-text';
223
+ this.rawTextSearch = getSuffix(`${this.rawTextSearch}${char.toLowerCase()}`, `</${this.rawTextElement}`);
224
+ }
225
+ }
226
+ }
227
+ startTag(char) {
228
+ this.currentTagName = char.toLowerCase();
229
+ this.currentAttributes = new Map();
230
+ this.currentAttributeName = '';
231
+ this.currentAttributeValue = '';
232
+ this.currentAttributeHasValue = false;
233
+ }
234
+ startAttribute(char) {
235
+ this.currentAttributeName = char.toLowerCase();
236
+ this.currentAttributeValue = '';
237
+ this.currentAttributeHasValue = false;
238
+ }
239
+ completeAttribute() {
240
+ if ('' === this.currentAttributeName) return;
241
+ this.currentAttributes.set(this.currentAttributeName, this.currentAttributeHasValue ? this.currentAttributeValue : true);
242
+ this.currentAttributeName = '';
243
+ this.currentAttributeValue = '';
244
+ this.currentAttributeHasValue = false;
245
+ }
246
+ completeStartTag(selfClosing) {
247
+ this.completeAttribute();
248
+ const tagName = this.currentTagName;
249
+ const id = this.currentAttributes.get('id');
250
+ const hasReactSegmentId = 'string' == typeof id && REACT_SEGMENT_ID_PATTERN.test(id);
251
+ const hasHiddenAttribute = this.currentAttributes.has('hidden');
252
+ const isHiddenSegmentTable = 'table' === tagName && hasHiddenAttribute && !hasReactSegmentId;
253
+ const isTableSegmentChild = hasReactSegmentId && TABLE_SEGMENT_CHILDREN.has(tagName) && this.openElements[this.openElements.length - 1]?.isSegmentTableWrapper === true;
254
+ const isContinuationContainer = hasReactSegmentId && ('div' === tagName && hasHiddenAttribute || ('svg' === tagName || 'math' === tagName) && void 0 !== id && 'true' === this.currentAttributes.get('aria-hidden') && 'display:none' === this.currentAttributes.get('style') || 'table' === tagName && hasHiddenAttribute || isTableSegmentChild);
255
+ this.continuationProtocolScript = "script" === tagName && this.awaitingContinuationProtocol;
256
+ this.continuationProtocolTail = '';
257
+ this.hasContinuationProtocolCall = false;
258
+ if (!selfClosing && !VOID_ELEMENTS.has(tagName)) this.openElements.push({
259
+ tagName,
260
+ isContinuationContainer,
261
+ isSegmentTableWrapper: isHiddenSegmentTable
262
+ });
263
+ this.currentTagName = '';
264
+ this.currentAttributes = new Map();
265
+ this.currentAttributeName = '';
266
+ this.currentAttributeValue = '';
267
+ this.currentAttributeHasValue = false;
268
+ if (!selfClosing && RAW_TEXT_ELEMENTS.has(tagName)) {
269
+ this.rawTextElement = tagName;
270
+ this.rawTextSearch = '';
271
+ this.state = 'raw-text';
272
+ } else this.state = 'data';
273
+ }
274
+ completeEndTag() {
275
+ this.closeOpenElement(this.currentTagName);
276
+ this.currentTagName = '';
277
+ this.state = 'data';
278
+ }
279
+ consumeRawText(char) {
280
+ const rawTextElement = this.rawTextElement;
281
+ if (void 0 === rawTextElement) {
282
+ this.state = 'data';
283
+ return;
284
+ }
285
+ const endTagPrefix = `</${rawTextElement}`;
286
+ if (this.continuationProtocolScript) {
287
+ this.continuationProtocolTail = `${this.continuationProtocolTail}${char}`.slice(-4);
288
+ if (/\$(?:RC|RS|RX|RB|RR)\b/.test(this.continuationProtocolTail)) this.hasContinuationProtocolCall = true;
289
+ }
290
+ this.rawTextSearch = getSuffix(`${this.rawTextSearch}${char.toLowerCase()}`, endTagPrefix);
291
+ if (this.rawTextSearch === endTagPrefix) this.state = 'raw-end-tag';
292
+ }
293
+ completeRawTextEndTag() {
294
+ const rawTextElement = this.rawTextElement;
295
+ if (void 0 !== rawTextElement) this.closeOpenElement(rawTextElement);
296
+ if ("script" === rawTextElement && this.continuationProtocolScript && this.hasContinuationProtocolCall) this.awaitingContinuationProtocol = false;
297
+ this.rawTextElement = void 0;
298
+ this.rawTextSearch = '';
299
+ this.continuationProtocolScript = false;
300
+ this.continuationProtocolTail = '';
301
+ this.hasContinuationProtocolCall = false;
302
+ this.state = 'data';
303
+ }
304
+ closeOpenElement(tagName) {
305
+ const matchingIndex = this.openElements.map((element)=>element.tagName).lastIndexOf(tagName);
306
+ if (-1 === matchingIndex) return;
307
+ const closedElements = this.openElements.splice(matchingIndex);
308
+ const closedContinuation = closedElements.some((element)=>element.isContinuationContainer);
309
+ if (closedContinuation) this.awaitingContinuationProtocol = true;
310
+ }
311
+ constructor(emit){
312
+ this.emit = emit;
313
+ this.pendingResolvers = [];
314
+ this.openElements = [];
315
+ this.shellFinished = false;
316
+ this.closed = false;
317
+ this.state = 'data';
318
+ this.currentTagName = '';
319
+ this.currentAttributes = new Map();
320
+ this.currentAttributeName = '';
321
+ this.currentAttributeValue = '';
322
+ this.currentAttributeHasValue = false;
323
+ this.declarationPrefix = '';
324
+ this.commentTail = '';
325
+ this.rawTextSearch = '';
326
+ this.continuationProtocolScript = false;
327
+ this.continuationProtocolTail = '';
328
+ this.hasContinuationProtocolCall = false;
329
+ this.awaitingContinuationProtocol = false;
330
+ }
331
+ }
332
+ export { DeferredScriptOutputCoordinator };
@@ -10,6 +10,7 @@ var shared_ShellChunkStatus = /*#__PURE__*/ function(ShellChunkStatus) {
10
10
  ShellChunkStatus[ShellChunkStatus["FINISH"] = 1] = "FINISH";
11
11
  return ShellChunkStatus;
12
12
  }({});
13
+ const SHELL_PROGRESSIVE_CHUNK_SIZE = Number.MAX_SAFE_INTEGER;
13
14
  const SHOULD_STREAM_ALL_HEADER = 'x-should-stream-all';
14
15
  function parseShouldStreamAllFlag(value) {
15
16
  if (!value) return;
@@ -107,4 +108,4 @@ function createRenderStreaming(createReadableStreamPromise) {
107
108
  return stream;
108
109
  };
109
110
  }
110
- export { createRenderStreaming, encodeForWebStream, getReadableStreamFromString, resolveStreamingMode, shared_ShellChunkStatus as ShellChunkStatus };
111
+ export { SHELL_PROGRESSIVE_CHUNK_SIZE, createRenderStreaming, encodeForWebStream, getReadableStreamFromString, resolveStreamingMode, shared_ShellChunkStatus as ShellChunkStatus };
@@ -1,8 +1,9 @@
1
+ import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "@modern-js/runtime/context";
1
2
  import { time } from "@modern-js/runtime-utils/time";
2
3
  import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
3
4
  import server from "react-dom/server";
4
5
  import { RenderLevel } from "../../constants.mjs";
5
- import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "../../context/index.mjs";
6
+ import { getMonitors } from "../../context/monitors/index.mjs";
6
7
  import { wrapRuntimeComponentResolver, wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
7
8
  import { CHUNK_CSS_PLACEHOLDER, CHUNK_JS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
8
9
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
@@ -60,6 +61,7 @@ const renderString = async (request, serverRoot, options)=>{
60
61
  config,
61
62
  platform: 'node',
62
63
  mode: 'string',
64
+ monitors: getMonitors(),
63
65
  isRsc: true === getGlobalEnableRsc()
64
66
  }
65
67
  });
@@ -16,8 +16,8 @@ const assetToChunk = (asset)=>({
16
16
  });
17
17
  const checkIsInline = (chunk, enableInline)=>{
18
18
  if ('production' !== process.env.NODE_ENV) return false;
19
- if (enableInline instanceof RegExp) return enableInline.test(chunk.url);
20
- return Boolean(enableInline);
19
+ else if (enableInline instanceof RegExp) return enableInline.test(chunk.url);
20
+ else return Boolean(enableInline);
21
21
  };
22
22
  const readAsset = async (chunk)=>{
23
23
  const fs = await import("fs/promises");
@@ -110,7 +110,7 @@ class LoadableCollector {
110
110
  const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url) && !this.existsAssets?.includes(chunk.path)).map(async (chunk)=>{
111
111
  const script = `<script${attributes} src="${chunk.url}"></script>`;
112
112
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<script>${content}</script>`).catch((_)=>script);
113
- return script;
113
+ else return script;
114
114
  }));
115
115
  chunkSet.jsChunk += scripts.filter((script)=>Boolean(script)).join('');
116
116
  }
@@ -127,7 +127,7 @@ class LoadableCollector {
127
127
  const css = await Promise.all(emittedChunks.map(async (chunk)=>{
128
128
  const link = `<link${atrributes} href="${chunk.url}" rel="stylesheet" />`;
129
129
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
130
- return link;
130
+ else return link;
131
131
  }));
132
132
  chunkSet.cssChunk += css.filter((css)=>Boolean(css)).join('');
133
133
  this.stylesheetInfo.emittedAssets = emittedChunks.map((chunk)=>chunk.url);
@@ -124,6 +124,7 @@ g.__MODERN_DOC_RENDERERS__[${JSON.stringify(_entryName)}] = render;
124
124
 
125
125
  export default { render: render };`;
126
126
  };
127
+ const getDocumentTempEntry = (internalDirectory, compilerName, entryName)=>path.join(internalDirectory, CONSTANTS.DOCUMENT_OUTPUT_DIR, compilerName ?? '', `${CONSTANTS.TEMP_ENTRY_PREFIX}${entryName}.js`);
127
128
  const processChildCompilation = async (entryName, docPath, compilation, compiler, appDirectory, internalDirectory)=>new Promise((resolve, reject)=>{
128
129
  const outFile = path.posix.join(CONSTANTS.DOCUMENT_OUTPUT_DIR, `${CONSTANTS.HTML_OUTPUT_PREFIX}${entryName}${CONSTANTS.HTML_OUTPUT_SUFFIX}`);
129
130
  const child = compilation.createChildCompiler(`${CONSTANTS.CHILD_COMPILER_PREFIX}${entryName}`, {
@@ -134,8 +135,7 @@ const processChildCompilation = async (entryName, docPath, compilation, compiler
134
135
  }, []);
135
136
  configureChildCompiler(child, compiler, appDirectory);
136
137
  applyExternalsPlugin(child, compiler);
137
- const entryDir = path.join(internalDirectory, CONSTANTS.DOCUMENT_OUTPUT_DIR);
138
- const tempEntry = path.join(entryDir, `${CONSTANTS.TEMP_ENTRY_PREFIX}${entryName}.js`);
138
+ const tempEntry = getDocumentTempEntry(internalDirectory, compiler.name, entryName);
139
139
  const finalize = ()=>{
140
140
  try {
141
141
  const EntryPlugin = compiler.rspack?.EntryPlugin;
@@ -202,6 +202,7 @@ const documentPlugin = ()=>({
202
202
  const tasks = [];
203
203
  for (const ep of entrypoints || []){
204
204
  const entryName = ep.entryName;
205
+ if (!this.htmlEntryNames.has(entryName)) continue;
205
206
  const docPath = getDocumentByEntryName(entrypoints, entryName, appDirectory);
206
207
  if (docPath) {
207
208
  compilation.fileDependencies?.add?.(docPath);
@@ -218,14 +219,19 @@ const documentPlugin = ()=>({
218
219
  }
219
220
  });
220
221
  }
221
- constructor(){
222
+ constructor(htmlEntryNames){
223
+ this.htmlEntryNames = htmlEntryNames;
222
224
  this.name = 'ModernJsDocumentChildCompilerPlugin';
223
225
  }
224
226
  }
225
227
  api.config(()=>({
226
228
  tools: {
227
- bundlerChain: (chain)=>{
228
- chain.plugin('modernjs-document-child-compiler').use(ModernJsDocumentChildCompilerPlugin, []);
229
+ bundlerChain: (chain, { environment })=>{
230
+ const htmlEntryNames = new Set(Object.keys(environment.htmlPaths));
231
+ if (0 === htmlEntryNames.size) return;
232
+ chain.plugin('modernjs-document-child-compiler').use(ModernJsDocumentChildCompilerPlugin, [
233
+ htmlEntryNames
234
+ ]);
229
235
  }
230
236
  }
231
237
  }));
@@ -346,4 +352,4 @@ const documentPlugin = ()=>({
346
352
  });
347
353
  const cli = documentPlugin;
348
354
  export default cli;
349
- export { documentPlugin, getDocumentByEntryName, processScriptPlaceholders };
355
+ export { documentPlugin, getDocumentByEntryName, getDocumentTempEntry, processScriptPlaceholders };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
+ import { RuntimeComponentResolverContext } from "@modern-js/runtime/context";
2
3
  import react from "react";
3
4
  import { Helmet, HelmetData, HelmetProvider } from "react-helmet-async";
4
- import { RuntimeComponentResolverContext } from "../core/context/runtime.mjs";
5
5
  const head_Helmet = (props)=>{
6
6
  const resolveComponent = react.useContext(RuntimeComponentResolverContext);
7
7
  const Component = resolveComponent?.(Helmet, {
@@ -1 +1 @@
1
- export { InternalRuntimeContext } from "./core/context/runtime.mjs";
1
+ export { InternalRuntimeContext } from "@modern-js/runtime/context";