@bleedingdev/modern-js-runtime 3.2.0-ultramodern.96 → 3.2.0-ultramodern.98

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 (25) hide show
  1. package/dist/cjs/core/server/scriptOrder.js +59 -0
  2. package/dist/cjs/core/server/stream/afterTemplate.js +6 -1
  3. package/dist/cjs/core/server/string/index.js +12 -5
  4. package/dist/cjs/core/server/string/loadable.js +42 -4
  5. package/dist/cjs/router/runtime/tanstack/hydrationBoundary.js +43 -0
  6. package/dist/cjs/router/runtime/tanstack/plugin.js +4 -2
  7. package/dist/cjs/router/runtime/tanstack/plugin.node.js +3 -2
  8. package/dist/esm/core/server/scriptOrder.mjs +25 -0
  9. package/dist/esm/core/server/stream/afterTemplate.mjs +6 -1
  10. package/dist/esm/core/server/string/index.mjs +12 -5
  11. package/dist/esm/core/server/string/loadable.mjs +38 -3
  12. package/dist/esm/router/runtime/tanstack/hydrationBoundary.mjs +9 -0
  13. package/dist/esm/router/runtime/tanstack/plugin.mjs +4 -2
  14. package/dist/esm/router/runtime/tanstack/plugin.node.mjs +3 -2
  15. package/dist/esm-node/core/server/scriptOrder.mjs +26 -0
  16. package/dist/esm-node/core/server/stream/afterTemplate.mjs +6 -1
  17. package/dist/esm-node/core/server/string/index.mjs +12 -5
  18. package/dist/esm-node/core/server/string/loadable.mjs +38 -3
  19. package/dist/esm-node/router/runtime/tanstack/hydrationBoundary.mjs +10 -0
  20. package/dist/esm-node/router/runtime/tanstack/plugin.mjs +4 -2
  21. package/dist/esm-node/router/runtime/tanstack/plugin.node.mjs +3 -2
  22. package/dist/types/core/server/scriptOrder.d.ts +1 -0
  23. package/dist/types/core/server/string/loadable.d.ts +7 -0
  24. package/dist/types/router/runtime/tanstack/hydrationBoundary.d.ts +2 -0
  25. package/package.json +8 -8
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ injectBeforeHydrationEntryScript: ()=>injectBeforeHydrationEntryScript
28
+ });
29
+ function getScriptTags(template) {
30
+ const scriptRegExp = /<script\b[^>]*\bsrc=(["'])(.*?)\1[^>]*><\/script>/g;
31
+ return Array.from(template.matchAll(scriptRegExp)).map((match)=>({
32
+ index: match.index ?? 0,
33
+ tag: match[0],
34
+ src: match[2]
35
+ }));
36
+ }
37
+ function getAssetBasename(src) {
38
+ const withoutQuery = src.split(/[?#]/)[0];
39
+ return withoutQuery.split('/').pop() || withoutQuery;
40
+ }
41
+ function isEntryScript(src, entryName, asyncEntry) {
42
+ const basename = getAssetBasename(src);
43
+ const prefix = asyncEntry ? `async-${entryName}` : entryName;
44
+ return basename === `${prefix}.js` || basename.startsWith(`${prefix}.`) || basename.startsWith(`${prefix}-`);
45
+ }
46
+ function injectBeforeHydrationEntryScript(template, scripts, entryName = 'index') {
47
+ if (!scripts) return template;
48
+ const scriptTags = getScriptTags(template);
49
+ const target = scriptTags.find((match)=>isEntryScript(match.src, entryName, false)) ?? scriptTags.find((match)=>isEntryScript(match.src, entryName, true));
50
+ if (!target) return template;
51
+ return `${template.slice(0, target.index)}${scripts}${template.slice(target.index)}`;
52
+ }
53
+ exports.injectBeforeHydrationEntryScript = __webpack_exports__.injectBeforeHydrationEntryScript;
54
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
55
+ "injectBeforeHydrationEntryScript"
56
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
57
+ Object.defineProperty(exports, '__esModule', {
58
+ value: true
59
+ });
@@ -30,6 +30,7 @@ const node_namespaceObject = require("@modern-js/runtime-utils/node");
30
30
  const lifecycle_js_namespaceObject = require("../../../router/runtime/lifecycle.js");
31
31
  const external_constants_js_namespaceObject = require("../../constants.js");
32
32
  const external_constants_js_namespaceObject_1 = require("../constants.js");
33
+ const external_scriptOrder_js_namespaceObject = require("../scriptOrder.js");
33
34
  const external_shared_js_namespaceObject = require("../shared.js");
34
35
  const external_utils_js_namespaceObject = require("../utils.js");
35
36
  function buildShellAfterTemplate(afterAppTemplate, options) {
@@ -58,7 +59,11 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
58
59
  const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
59
60
  const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
60
61
  const jsChunkStr = jsAssets.filter((asset)=>!template.includes(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
61
- if (jsChunkStr) return (0, external_utils_js_namespaceObject.safeReplace)(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
62
+ if (jsChunkStr) {
63
+ const withoutPlaceholder = (0, external_utils_js_namespaceObject.safeReplace)(template, '<!--<?- chunksMap.js ?>-->', '');
64
+ const withEarlyScripts = (0, external_scriptOrder_js_namespaceObject.injectBeforeHydrationEntryScript)(withoutPlaceholder, jsChunkStr, entryName);
65
+ return withEarlyScripts !== withoutPlaceholder ? withEarlyScripts : (0, external_utils_js_namespaceObject.safeReplace)(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
66
+ }
62
67
  return template;
63
68
  }
64
69
  return (0, external_shared_js_namespaceObject.buildHtml)(afterAppTemplate, callbacks);
@@ -44,6 +44,7 @@ const index_js_namespaceObject = require("../../context/index.js");
44
44
  const wrapper_js_namespaceObject = require("../../react/wrapper.js");
45
45
  const external_constants_js_namespaceObject_1 = require("../constants.js");
46
46
  const external_helmet_js_namespaceObject = require("../helmet.js");
47
+ const external_scriptOrder_js_namespaceObject = require("../scriptOrder.js");
47
48
  const external_shared_js_namespaceObject = require("../shared.js");
48
49
  const external_tracer_js_namespaceObject = require("../tracer.js");
49
50
  const external_utils_js_namespaceObject = require("../utils.js");
@@ -96,10 +97,10 @@ const renderString = async (request, serverRoot, options)=>{
96
97
  const rootElement = (0, wrapper_js_namespaceObject.wrapRuntimeContextProvider)(serverRoot, Object.assign(runtimeContext, {
97
98
  ssr: true
98
99
  }));
99
- const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, tracer);
100
+ const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, entryName, tracer);
100
101
  return html;
101
102
  };
102
- async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, { onError, onTiming }) {
103
+ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, entryName, { onError, onTiming }) {
103
104
  let html = '';
104
105
  let helmetData;
105
106
  const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
@@ -120,7 +121,7 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
120
121
  const { ssrScripts, cssChunk, jsChunk } = chunkSet;
121
122
  const finalHtml = await (0, external_shared_js_namespaceObject.buildHtml)(htmlTemplate, [
122
123
  createReplaceHtml(html),
123
- createReplaceChunkJs(jsChunk),
124
+ createReplaceChunkJs(jsChunk, entryName),
124
125
  createReplaceChunkCss(cssChunk),
125
126
  createReplaceSSRDataScript(ssrScripts),
126
127
  (0, external_helmet_js_namespaceObject.createReplaceHelemt)(helmetData),
@@ -134,8 +135,14 @@ function createReplaceHtml(html) {
134
135
  function createReplaceSSRDataScript(data) {
135
136
  return (template)=>(0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject_1.SSR_DATA_PLACEHOLDER, data);
136
137
  }
137
- function createReplaceChunkJs(js) {
138
- return (template)=>(0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject_1.CHUNK_JS_PLACEHOLDER, js);
138
+ function createReplaceChunkJs(js, entryName) {
139
+ return (template)=>{
140
+ if (!js) return (0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject_1.CHUNK_JS_PLACEHOLDER, '');
141
+ const withoutPlaceholder = (0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject_1.CHUNK_JS_PLACEHOLDER, '');
142
+ const withEarlyScripts = (0, external_scriptOrder_js_namespaceObject.injectBeforeHydrationEntryScript)(withoutPlaceholder, js, entryName);
143
+ if (withEarlyScripts !== withoutPlaceholder) return withEarlyScripts;
144
+ return (0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject_1.CHUNK_JS_PLACEHOLDER, js);
145
+ };
139
146
  }
140
147
  function createReplaceChunkCss(css) {
141
148
  return (template)=>(0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject_1.CHUNK_CSS_PLACEHOLDER, css);
@@ -24,7 +24,8 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
- LoadableCollector: ()=>LoadableCollector
27
+ LoadableCollector: ()=>LoadableCollector,
28
+ orderHydrationScriptChunks: ()=>orderHydrationScriptChunks
28
29
  });
29
30
  const server_namespaceObject = require("@loadable/server");
30
31
  const lifecycle_js_namespaceObject = require("../../../router/runtime/lifecycle.js");
@@ -35,6 +36,33 @@ const extname = (uri)=>{
35
36
  return `.${uri?.split('.').pop()}` || '';
36
37
  };
37
38
  const generateChunks = (chunks, ext)=>chunks.filter((chunk)=>Boolean(chunk.url)).filter((chunk)=>extname(chunk.url).slice(1) === ext);
39
+ const dedupeChunksByUrl = (chunks)=>{
40
+ const seen = new Set();
41
+ return chunks.filter((chunk)=>{
42
+ if (!chunk.url || seen.has(chunk.url)) return false;
43
+ seen.add(chunk.url);
44
+ return true;
45
+ });
46
+ };
47
+ const isAsyncEntryScriptChunk = (chunk, entryName)=>{
48
+ if (!chunk.url?.endsWith('.js')) return false;
49
+ const asyncEntryName = `async-${entryName}`;
50
+ const filename = chunk.filename || chunk.url;
51
+ const basename = filename.split('/').pop() || filename;
52
+ return basename === `${asyncEntryName}.js` || basename.startsWith(`${asyncEntryName}.`) || basename.startsWith(`${asyncEntryName}-`);
53
+ };
54
+ const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
55
+ const asyncEntryScriptChunks = [];
56
+ const asyncEntryDependencyChunks = [];
57
+ for (const chunk of asyncEntryChunks)if (isAsyncEntryScriptChunk(chunk, entryName)) asyncEntryScriptChunks.push(chunk);
58
+ else asyncEntryDependencyChunks.push(chunk);
59
+ return dedupeChunksByUrl([
60
+ ...asyncEntryDependencyChunks,
61
+ ...collectedChunks,
62
+ ...matchedRouteChunks,
63
+ ...asyncEntryScriptChunks
64
+ ]);
65
+ };
38
66
  const checkIsInline = (chunk, enableInline)=>{
39
67
  if ('production' !== process.env.NODE_ENV) return false;
40
68
  if (enableInline instanceof RegExp) return enableInline.test(chunk.url);
@@ -85,8 +113,16 @@ class LoadableCollector {
85
113
  `async-${entryName}`
86
114
  ]));
87
115
  } catch (e) {}
88
- const chunks = [].concat(asyncChunks).concat(extractor ? extractor.getChunkAssets(extractor.chunks) : []).concat(this.getMatchedRouteChunks());
89
- const scriptChunks = generateChunks(chunks, 'js');
116
+ const collectedChunks = extractor ? extractor.getChunkAssets(extractor.chunks) : [];
117
+ const matchedRouteChunks = this.getMatchedRouteChunks();
118
+ const orderedScriptChunks = orderHydrationScriptChunks({
119
+ asyncEntryChunks: asyncChunks,
120
+ collectedChunks,
121
+ matchedRouteChunks,
122
+ entryName
123
+ });
124
+ const chunks = [].concat(asyncChunks).concat(collectedChunks).concat(matchedRouteChunks);
125
+ const scriptChunks = generateChunks(orderedScriptChunks, 'js');
90
126
  const styleChunks = generateChunks(chunks, 'css');
91
127
  if (extractor) {
92
128
  this.emitLoadableScripts(extractor);
@@ -164,8 +200,10 @@ class LoadableCollector {
164
200
  }
165
201
  }
166
202
  exports.LoadableCollector = __webpack_exports__.LoadableCollector;
203
+ exports.orderHydrationScriptChunks = __webpack_exports__.orderHydrationScriptChunks;
167
204
  for(var __rspack_i in __webpack_exports__)if (-1 === [
168
- "LoadableCollector"
205
+ "LoadableCollector",
206
+ "orderHydrationScriptChunks"
169
207
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
170
208
  Object.defineProperty(exports, '__esModule', {
171
209
  value: true
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ wrapTanstackSsrHydrationBoundary: ()=>wrapTanstackSsrHydrationBoundary
28
+ });
29
+ const jsx_runtime_namespaceObject = require("react/jsx-runtime");
30
+ const external_react_namespaceObject = require("react");
31
+ function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
32
+ return shouldWrap ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_namespaceObject.Suspense, {
33
+ fallback: null,
34
+ children: routerContent
35
+ }) : routerContent;
36
+ }
37
+ exports.wrapTanstackSsrHydrationBoundary = __webpack_exports__.wrapTanstackSsrHydrationBoundary;
38
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
39
+ "wrapTanstackSsrHydrationBoundary"
40
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
41
+ Object.defineProperty(exports, '__esModule', {
42
+ value: true
43
+ });
@@ -37,6 +37,7 @@ const external_hooks_js_namespaceObject = require("../hooks.js");
37
37
  const external_lifecycle_js_namespaceObject = require("../lifecycle.js");
38
38
  const external_utils_js_namespaceObject = require("../utils.js");
39
39
  const external_basepathRewrite_js_namespaceObject = require("./basepathRewrite.js");
40
+ const external_hydrationBoundary_js_namespaceObject = require("./hydrationBoundary.js");
40
41
  const external_prefetchLink_js_namespaceObject = require("./prefetchLink.js");
41
42
  const external_routeTree_js_namespaceObject = require("./routeTree.js");
42
43
  const client_js_namespaceObject = require("./rsc/client.js");
@@ -215,6 +216,7 @@ const tanstackRouterPlugin = (userConfig = {})=>({
215
216
  }) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_router_namespaceObject.RouterProvider, {
216
217
  router: router
217
218
  });
219
+ const HydratableRouterContent = (0, external_hydrationBoundary_js_namespaceObject.wrapTanstackSsrHydrationBoundary)(RouterContent, hasSSRBootstrap);
218
220
  if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
219
221
  ...lifecycleContext,
220
222
  phase: 'hydrate',
@@ -222,8 +224,8 @@ const tanstackRouterPlugin = (userConfig = {})=>({
222
224
  runtimeContext: runtimeState
223
225
  });
224
226
  return App ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(App, {
225
- children: RouterContent
226
- }) : RouterContent;
227
+ children: HydratableRouterContent
228
+ }) : HydratableRouterContent;
227
229
  };
228
230
  return RouterWrapper;
229
231
  });
@@ -38,6 +38,7 @@ const index_js_namespaceObject = require("../../../core/context/index.js");
38
38
  const external_lifecycle_js_namespaceObject = require("../lifecycle.js");
39
39
  const external_utils_js_namespaceObject = require("../utils.js");
40
40
  const external_basepathRewrite_js_namespaceObject = require("./basepathRewrite.js");
41
+ const external_hydrationBoundary_js_namespaceObject = require("./hydrationBoundary.js");
41
42
  const external_routeTree_js_namespaceObject = require("./routeTree.js");
42
43
  function isPreloadableRouteComponent(component) {
43
44
  if (!component || 'function' != typeof component) return false;
@@ -247,9 +248,9 @@ const tanstackRouterPlugin = (userConfig = {})=>({
247
248
  if (!router) return App ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(App, {
248
249
  ...props
249
250
  }) : null;
250
- const routerWrapper = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_router_namespaceObject.RouterProvider, {
251
+ const routerWrapper = (0, external_hydrationBoundary_js_namespaceObject.wrapTanstackSsrHydrationBoundary)(/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_router_namespaceObject.RouterProvider, {
251
252
  router: router
252
- });
253
+ }), true);
253
254
  return App ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(App, {
254
255
  children: routerWrapper
255
256
  }) : routerWrapper;
@@ -0,0 +1,25 @@
1
+ function getScriptTags(template) {
2
+ const scriptRegExp = /<script\b[^>]*\bsrc=(["'])(.*?)\1[^>]*><\/script>/g;
3
+ return Array.from(template.matchAll(scriptRegExp)).map((match)=>({
4
+ index: match.index ?? 0,
5
+ tag: match[0],
6
+ src: match[2]
7
+ }));
8
+ }
9
+ function getAssetBasename(src) {
10
+ const withoutQuery = src.split(/[?#]/)[0];
11
+ return withoutQuery.split('/').pop() || withoutQuery;
12
+ }
13
+ function isEntryScript(src, entryName, asyncEntry) {
14
+ const basename = getAssetBasename(src);
15
+ const prefix = asyncEntry ? `async-${entryName}` : entryName;
16
+ return basename === `${prefix}.js` || basename.startsWith(`${prefix}.`) || basename.startsWith(`${prefix}-`);
17
+ }
18
+ function injectBeforeHydrationEntryScript(template, scripts, entryName = 'index') {
19
+ if (!scripts) return template;
20
+ const scriptTags = getScriptTags(template);
21
+ const target = scriptTags.find((match)=>isEntryScript(match.src, entryName, false)) ?? scriptTags.find((match)=>isEntryScript(match.src, entryName, true));
22
+ if (!target) return template;
23
+ return `${template.slice(0, target.index)}${scripts}${template.slice(target.index)}`;
24
+ }
25
+ export { injectBeforeHydrationEntryScript };
@@ -2,6 +2,7 @@ import { serializeJson } from "@modern-js/runtime-utils/node";
2
2
  import { getRouterHydrationScripts, getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
3
3
  import { SSR_DATA_JSON_ID } from "../../constants.mjs";
4
4
  import { SSR_DATA_PLACEHOLDER } from "../constants.mjs";
5
+ import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
5
6
  import { buildHtml } from "../shared.mjs";
6
7
  import { attributesToString, safeReplace } from "../utils.mjs";
7
8
  function buildShellAfterTemplate(afterAppTemplate, options) {
@@ -30,7 +31,11 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
30
31
  const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
31
32
  const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
32
33
  const jsChunkStr = jsAssets.filter((asset)=>!template.includes(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
33
- if (jsChunkStr) return safeReplace(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
34
+ if (jsChunkStr) {
35
+ const withoutPlaceholder = safeReplace(template, '<!--<?- chunksMap.js ?>-->', '');
36
+ const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, jsChunkStr, entryName);
37
+ return withEarlyScripts !== withoutPlaceholder ? withEarlyScripts : safeReplace(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
38
+ }
34
39
  return template;
35
40
  }
36
41
  return buildHtml(afterAppTemplate, callbacks);
@@ -6,6 +6,7 @@ import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
6
6
  import { wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
7
7
  import { CHUNK_CSS_PLACEHOLDER, CHUNK_JS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
8
8
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
9
+ import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
9
10
  import { buildHtml } from "../shared.mjs";
10
11
  import { SSRErrors, SSRTimings } from "../tracer.mjs";
11
12
  import { getSSRConfigByEntry, safeReplace } from "../utils.mjs";
@@ -58,10 +59,10 @@ const renderString = async (request, serverRoot, options)=>{
58
59
  const rootElement = wrapRuntimeContextProvider(serverRoot, Object.assign(runtimeContext, {
59
60
  ssr: true
60
61
  }));
61
- const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, tracer);
62
+ const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, entryName, tracer);
62
63
  return html;
63
64
  };
64
- async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, { onError, onTiming }) {
65
+ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, entryName, { onError, onTiming }) {
65
66
  let html = '';
66
67
  let helmetData;
67
68
  const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
@@ -82,7 +83,7 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
82
83
  const { ssrScripts, cssChunk, jsChunk } = chunkSet;
83
84
  const finalHtml = await buildHtml(htmlTemplate, [
84
85
  createReplaceHtml(html),
85
- createReplaceChunkJs(jsChunk),
86
+ createReplaceChunkJs(jsChunk, entryName),
86
87
  createReplaceChunkCss(cssChunk),
87
88
  createReplaceSSRDataScript(ssrScripts),
88
89
  createReplaceHelemt(helmetData),
@@ -96,8 +97,14 @@ function createReplaceHtml(html) {
96
97
  function createReplaceSSRDataScript(data) {
97
98
  return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, data);
98
99
  }
99
- function createReplaceChunkJs(js) {
100
- return (template)=>safeReplace(template, CHUNK_JS_PLACEHOLDER, js);
100
+ function createReplaceChunkJs(js, entryName) {
101
+ return (template)=>{
102
+ if (!js) return safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
103
+ const withoutPlaceholder = safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
104
+ const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, js, entryName);
105
+ if (withEarlyScripts !== withoutPlaceholder) return withEarlyScripts;
106
+ return safeReplace(template, CHUNK_JS_PLACEHOLDER, js);
107
+ };
101
108
  }
102
109
  function createReplaceChunkCss(css) {
103
110
  return (template)=>safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
@@ -7,6 +7,33 @@ const extname = (uri)=>{
7
7
  return `.${uri?.split('.').pop()}` || '';
8
8
  };
9
9
  const generateChunks = (chunks, ext)=>chunks.filter((chunk)=>Boolean(chunk.url)).filter((chunk)=>extname(chunk.url).slice(1) === ext);
10
+ const dedupeChunksByUrl = (chunks)=>{
11
+ const seen = new Set();
12
+ return chunks.filter((chunk)=>{
13
+ if (!chunk.url || seen.has(chunk.url)) return false;
14
+ seen.add(chunk.url);
15
+ return true;
16
+ });
17
+ };
18
+ const isAsyncEntryScriptChunk = (chunk, entryName)=>{
19
+ if (!chunk.url?.endsWith('.js')) return false;
20
+ const asyncEntryName = `async-${entryName}`;
21
+ const filename = chunk.filename || chunk.url;
22
+ const basename = filename.split('/').pop() || filename;
23
+ return basename === `${asyncEntryName}.js` || basename.startsWith(`${asyncEntryName}.`) || basename.startsWith(`${asyncEntryName}-`);
24
+ };
25
+ const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
26
+ const asyncEntryScriptChunks = [];
27
+ const asyncEntryDependencyChunks = [];
28
+ for (const chunk of asyncEntryChunks)if (isAsyncEntryScriptChunk(chunk, entryName)) asyncEntryScriptChunks.push(chunk);
29
+ else asyncEntryDependencyChunks.push(chunk);
30
+ return dedupeChunksByUrl([
31
+ ...asyncEntryDependencyChunks,
32
+ ...collectedChunks,
33
+ ...matchedRouteChunks,
34
+ ...asyncEntryScriptChunks
35
+ ]);
36
+ };
10
37
  const checkIsInline = (chunk, enableInline)=>{
11
38
  if ('production' !== process.env.NODE_ENV) return false;
12
39
  if (enableInline instanceof RegExp) return enableInline.test(chunk.url);
@@ -57,8 +84,16 @@ class LoadableCollector {
57
84
  `async-${entryName}`
58
85
  ]));
59
86
  } catch (e) {}
60
- const chunks = [].concat(asyncChunks).concat(extractor ? extractor.getChunkAssets(extractor.chunks) : []).concat(this.getMatchedRouteChunks());
61
- const scriptChunks = generateChunks(chunks, 'js');
87
+ const collectedChunks = extractor ? extractor.getChunkAssets(extractor.chunks) : [];
88
+ const matchedRouteChunks = this.getMatchedRouteChunks();
89
+ const orderedScriptChunks = orderHydrationScriptChunks({
90
+ asyncEntryChunks: asyncChunks,
91
+ collectedChunks,
92
+ matchedRouteChunks,
93
+ entryName
94
+ });
95
+ const chunks = [].concat(asyncChunks).concat(collectedChunks).concat(matchedRouteChunks);
96
+ const scriptChunks = generateChunks(orderedScriptChunks, 'js');
62
97
  const styleChunks = generateChunks(chunks, 'css');
63
98
  if (extractor) {
64
99
  this.emitLoadableScripts(extractor);
@@ -135,4 +170,4 @@ class LoadableCollector {
135
170
  this.options = options;
136
171
  }
137
172
  }
138
- export { LoadableCollector };
173
+ export { LoadableCollector, orderHydrationScriptChunks };
@@ -0,0 +1,9 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Suspense } from "react";
3
+ function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
4
+ return shouldWrap ? /*#__PURE__*/ jsx(Suspense, {
5
+ fallback: null,
6
+ children: routerContent
7
+ }) : routerContent;
8
+ }
9
+ export { wrapTanstackSsrHydrationBoundary };
@@ -9,6 +9,7 @@ import { onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBefo
9
9
  import { applyRouterRuntimeState } from "../lifecycle.mjs";
10
10
  import { createRouteObjectsFromConfig, urlJoin } from "../utils.mjs";
11
11
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
12
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
12
13
  import { Link } from "./prefetchLink.mjs";
13
14
  import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
14
15
  import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
@@ -187,6 +188,7 @@ const tanstackRouterPlugin = (userConfig = {})=>({
187
188
  }) : /*#__PURE__*/ jsx(RouterProvider, {
188
189
  router: router
189
190
  });
191
+ const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
190
192
  if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
191
193
  ...lifecycleContext,
192
194
  phase: 'hydrate',
@@ -194,8 +196,8 @@ const tanstackRouterPlugin = (userConfig = {})=>({
194
196
  runtimeContext: runtimeState
195
197
  });
196
198
  return App ? /*#__PURE__*/ jsx(App, {
197
- children: RouterContent
198
- }) : RouterContent;
199
+ children: HydratableRouterContent
200
+ }) : HydratableRouterContent;
199
201
  };
200
202
  return RouterWrapper;
201
203
  });
@@ -10,6 +10,7 @@ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlob
10
10
  import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "../lifecycle.mjs";
11
11
  import { createRouteObjectsFromConfig, urlJoin } from "../utils.mjs";
12
12
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
13
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
13
14
  import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
14
15
  function isPreloadableRouteComponent(component) {
15
16
  if (!component || 'function' != typeof component) return false;
@@ -219,9 +220,9 @@ const tanstackRouterPlugin = (userConfig = {})=>({
219
220
  if (!router) return App ? /*#__PURE__*/ jsx(App, {
220
221
  ...props
221
222
  }) : null;
222
- const routerWrapper = /*#__PURE__*/ jsx(RouterProvider, {
223
+ const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
223
224
  router: router
224
- });
225
+ }), true);
225
226
  return App ? /*#__PURE__*/ jsx(App, {
226
227
  children: routerWrapper
227
228
  }) : routerWrapper;
@@ -0,0 +1,26 @@
1
+ import "node:module";
2
+ function getScriptTags(template) {
3
+ const scriptRegExp = /<script\b[^>]*\bsrc=(["'])(.*?)\1[^>]*><\/script>/g;
4
+ return Array.from(template.matchAll(scriptRegExp)).map((match)=>({
5
+ index: match.index ?? 0,
6
+ tag: match[0],
7
+ src: match[2]
8
+ }));
9
+ }
10
+ function getAssetBasename(src) {
11
+ const withoutQuery = src.split(/[?#]/)[0];
12
+ return withoutQuery.split('/').pop() || withoutQuery;
13
+ }
14
+ function isEntryScript(src, entryName, asyncEntry) {
15
+ const basename = getAssetBasename(src);
16
+ const prefix = asyncEntry ? `async-${entryName}` : entryName;
17
+ return basename === `${prefix}.js` || basename.startsWith(`${prefix}.`) || basename.startsWith(`${prefix}-`);
18
+ }
19
+ function injectBeforeHydrationEntryScript(template, scripts, entryName = 'index') {
20
+ if (!scripts) return template;
21
+ const scriptTags = getScriptTags(template);
22
+ const target = scriptTags.find((match)=>isEntryScript(match.src, entryName, false)) ?? scriptTags.find((match)=>isEntryScript(match.src, entryName, true));
23
+ if (!target) return template;
24
+ return `${template.slice(0, target.index)}${scripts}${template.slice(target.index)}`;
25
+ }
26
+ export { injectBeforeHydrationEntryScript };
@@ -3,6 +3,7 @@ import { serializeJson } from "@modern-js/runtime-utils/node";
3
3
  import { getRouterHydrationScripts, getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
4
4
  import { SSR_DATA_JSON_ID } from "../../constants.mjs";
5
5
  import { SSR_DATA_PLACEHOLDER } from "../constants.mjs";
6
+ import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
6
7
  import { buildHtml } from "../shared.mjs";
7
8
  import { attributesToString, safeReplace } from "../utils.mjs";
8
9
  function buildShellAfterTemplate(afterAppTemplate, options) {
@@ -31,7 +32,11 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
31
32
  const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
32
33
  const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
33
34
  const jsChunkStr = jsAssets.filter((asset)=>!template.includes(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
34
- if (jsChunkStr) return safeReplace(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
35
+ if (jsChunkStr) {
36
+ const withoutPlaceholder = safeReplace(template, '<!--<?- chunksMap.js ?>-->', '');
37
+ const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, jsChunkStr, entryName);
38
+ return withEarlyScripts !== withoutPlaceholder ? withEarlyScripts : safeReplace(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
39
+ }
35
40
  return template;
36
41
  }
37
42
  return buildHtml(afterAppTemplate, callbacks);
@@ -7,6 +7,7 @@ import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
7
7
  import { wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
8
8
  import { CHUNK_CSS_PLACEHOLDER, CHUNK_JS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
9
9
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
10
+ import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
10
11
  import { buildHtml } from "../shared.mjs";
11
12
  import { SSRErrors, SSRTimings } from "../tracer.mjs";
12
13
  import { getSSRConfigByEntry, safeReplace } from "../utils.mjs";
@@ -59,10 +60,10 @@ const renderString = async (request, serverRoot, options)=>{
59
60
  const rootElement = wrapRuntimeContextProvider(serverRoot, Object.assign(runtimeContext, {
60
61
  ssr: true
61
62
  }));
62
- const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, tracer);
63
+ const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, entryName, tracer);
63
64
  return html;
64
65
  };
65
- async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, { onError, onTiming }) {
66
+ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, entryName, { onError, onTiming }) {
66
67
  let html = '';
67
68
  let helmetData;
68
69
  const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
@@ -83,7 +84,7 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
83
84
  const { ssrScripts, cssChunk, jsChunk } = chunkSet;
84
85
  const finalHtml = await buildHtml(htmlTemplate, [
85
86
  createReplaceHtml(html),
86
- createReplaceChunkJs(jsChunk),
87
+ createReplaceChunkJs(jsChunk, entryName),
87
88
  createReplaceChunkCss(cssChunk),
88
89
  createReplaceSSRDataScript(ssrScripts),
89
90
  createReplaceHelemt(helmetData),
@@ -97,8 +98,14 @@ function createReplaceHtml(html) {
97
98
  function createReplaceSSRDataScript(data) {
98
99
  return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, data);
99
100
  }
100
- function createReplaceChunkJs(js) {
101
- return (template)=>safeReplace(template, CHUNK_JS_PLACEHOLDER, js);
101
+ function createReplaceChunkJs(js, entryName) {
102
+ return (template)=>{
103
+ if (!js) return safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
104
+ const withoutPlaceholder = safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
105
+ const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, js, entryName);
106
+ if (withEarlyScripts !== withoutPlaceholder) return withEarlyScripts;
107
+ return safeReplace(template, CHUNK_JS_PLACEHOLDER, js);
108
+ };
102
109
  }
103
110
  function createReplaceChunkCss(css) {
104
111
  return (template)=>safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
@@ -11,6 +11,33 @@ const extname = (uri)=>{
11
11
  return `.${uri?.split('.').pop()}` || '';
12
12
  };
13
13
  const generateChunks = (chunks, ext)=>chunks.filter((chunk)=>Boolean(chunk.url)).filter((chunk)=>extname(chunk.url).slice(1) === ext);
14
+ const dedupeChunksByUrl = (chunks)=>{
15
+ const seen = new Set();
16
+ return chunks.filter((chunk)=>{
17
+ if (!chunk.url || seen.has(chunk.url)) return false;
18
+ seen.add(chunk.url);
19
+ return true;
20
+ });
21
+ };
22
+ const isAsyncEntryScriptChunk = (chunk, entryName)=>{
23
+ if (!chunk.url?.endsWith('.js')) return false;
24
+ const asyncEntryName = `async-${entryName}`;
25
+ const filename = chunk.filename || chunk.url;
26
+ const basename = filename.split('/').pop() || filename;
27
+ return basename === `${asyncEntryName}.js` || basename.startsWith(`${asyncEntryName}.`) || basename.startsWith(`${asyncEntryName}-`);
28
+ };
29
+ const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
30
+ const asyncEntryScriptChunks = [];
31
+ const asyncEntryDependencyChunks = [];
32
+ for (const chunk of asyncEntryChunks)if (isAsyncEntryScriptChunk(chunk, entryName)) asyncEntryScriptChunks.push(chunk);
33
+ else asyncEntryDependencyChunks.push(chunk);
34
+ return dedupeChunksByUrl([
35
+ ...asyncEntryDependencyChunks,
36
+ ...collectedChunks,
37
+ ...matchedRouteChunks,
38
+ ...asyncEntryScriptChunks
39
+ ]);
40
+ };
14
41
  const checkIsInline = (chunk, enableInline)=>{
15
42
  if ('production' !== process.env.NODE_ENV) return false;
16
43
  if (enableInline instanceof RegExp) return enableInline.test(chunk.url);
@@ -61,8 +88,16 @@ class LoadableCollector {
61
88
  `async-${entryName}`
62
89
  ]));
63
90
  } catch (e) {}
64
- const chunks = [].concat(asyncChunks).concat(extractor ? extractor.getChunkAssets(extractor.chunks) : []).concat(this.getMatchedRouteChunks());
65
- const scriptChunks = generateChunks(chunks, 'js');
91
+ const collectedChunks = extractor ? extractor.getChunkAssets(extractor.chunks) : [];
92
+ const matchedRouteChunks = this.getMatchedRouteChunks();
93
+ const orderedScriptChunks = orderHydrationScriptChunks({
94
+ asyncEntryChunks: asyncChunks,
95
+ collectedChunks,
96
+ matchedRouteChunks,
97
+ entryName
98
+ });
99
+ const chunks = [].concat(asyncChunks).concat(collectedChunks).concat(matchedRouteChunks);
100
+ const scriptChunks = generateChunks(orderedScriptChunks, 'js');
66
101
  const styleChunks = generateChunks(chunks, 'css');
67
102
  if (extractor) {
68
103
  this.emitLoadableScripts(extractor);
@@ -139,4 +174,4 @@ class LoadableCollector {
139
174
  this.options = options;
140
175
  }
141
176
  }
142
- export { LoadableCollector };
177
+ export { LoadableCollector, orderHydrationScriptChunks };
@@ -0,0 +1,10 @@
1
+ import "node:module";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Suspense } from "react";
4
+ function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
5
+ return shouldWrap ? /*#__PURE__*/ jsx(Suspense, {
6
+ fallback: null,
7
+ children: routerContent
8
+ }) : routerContent;
9
+ }
10
+ export { wrapTanstackSsrHydrationBoundary };
@@ -10,6 +10,7 @@ import { onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBefo
10
10
  import { applyRouterRuntimeState } from "../lifecycle.mjs";
11
11
  import { createRouteObjectsFromConfig, urlJoin } from "../utils.mjs";
12
12
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
13
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
13
14
  import { Link } from "./prefetchLink.mjs";
14
15
  import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
15
16
  import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
@@ -188,6 +189,7 @@ const tanstackRouterPlugin = (userConfig = {})=>({
188
189
  }) : /*#__PURE__*/ jsx(RouterProvider, {
189
190
  router: router
190
191
  });
192
+ const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
191
193
  if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
192
194
  ...lifecycleContext,
193
195
  phase: 'hydrate',
@@ -195,8 +197,8 @@ const tanstackRouterPlugin = (userConfig = {})=>({
195
197
  runtimeContext: runtimeState
196
198
  });
197
199
  return App ? /*#__PURE__*/ jsx(App, {
198
- children: RouterContent
199
- }) : RouterContent;
200
+ children: HydratableRouterContent
201
+ }) : HydratableRouterContent;
200
202
  };
201
203
  return RouterWrapper;
202
204
  });
@@ -11,6 +11,7 @@ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlob
11
11
  import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "../lifecycle.mjs";
12
12
  import { createRouteObjectsFromConfig, urlJoin } from "../utils.mjs";
13
13
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
14
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
14
15
  import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
15
16
  function isPreloadableRouteComponent(component) {
16
17
  if (!component || 'function' != typeof component) return false;
@@ -220,9 +221,9 @@ const tanstackRouterPlugin = (userConfig = {})=>({
220
221
  if (!router) return App ? /*#__PURE__*/ jsx(App, {
221
222
  ...props
222
223
  }) : null;
223
- const routerWrapper = /*#__PURE__*/ jsx(RouterProvider, {
224
+ const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
224
225
  router: router
225
- });
226
+ }), true);
226
227
  return App ? /*#__PURE__*/ jsx(App, {
227
228
  children: routerWrapper
228
229
  }) : routerWrapper;
@@ -0,0 +1 @@
1
+ export declare function injectBeforeHydrationEntryScript(template: string, scripts: string, entryName?: string): string;
@@ -1,3 +1,4 @@
1
+ import { type Chunk } from '@loadable/server';
1
2
  import type { ReactElement } from 'react';
2
3
  import type { TInternalRuntimeContext } from '../../context';
3
4
  import type { ChunkSet, Collector } from './types';
@@ -7,6 +8,12 @@ declare module '@loadable/server' {
7
8
  getChunkAssets: (chunks: string[]) => Chunk[];
8
9
  }
9
10
  }
11
+ export declare const orderHydrationScriptChunks: ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName, }: {
12
+ asyncEntryChunks: Chunk[];
13
+ collectedChunks: Chunk[];
14
+ matchedRouteChunks: Chunk[];
15
+ entryName: string;
16
+ }) => Chunk[];
10
17
  export interface LoadableCollectorOptions {
11
18
  nonce?: string;
12
19
  stats?: Record<string, any>;
@@ -0,0 +1,2 @@
1
+ import { type ReactElement } from 'react';
2
+ export declare function wrapTanstackSsrHydrationBoundary(routerContent: ReactElement, shouldWrap: boolean): import("react").JSX.Element;
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.2.0-ultramodern.96",
20
+ "version": "3.2.0-ultramodern.98",
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
@@ -233,12 +233,12 @@
233
233
  "isbot": "5.1.40",
234
234
  "react-helmet-async": "3.0.0",
235
235
  "react-is": "^19.2.6",
236
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.96",
237
- "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.2.0-ultramodern.96",
238
- "@modern-js/render": "npm:@bleedingdev/modern-js-render@3.2.0-ultramodern.96",
239
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.96",
240
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.96",
241
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.96"
236
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.98",
237
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.98",
238
+ "@modern-js/render": "npm:@bleedingdev/modern-js-render@3.2.0-ultramodern.98",
239
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.98",
240
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.98",
241
+ "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.2.0-ultramodern.98"
242
242
  },
243
243
  "peerDependencies": {
244
244
  "react": "^19.2.6",
@@ -258,7 +258,7 @@
258
258
  "react": "^19.2.6",
259
259
  "react-dom": "^19.2.6",
260
260
  "@scripts/rstest-config": "2.66.0",
261
- "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.96"
261
+ "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.98"
262
262
  },
263
263
  "sideEffects": false,
264
264
  "publishConfig": {