@bleedingdev/modern-js-runtime 3.2.0-ultramodern.62 → 3.2.0-ultramodern.63

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 (37) hide show
  1. package/dist/cjs/boundary-debugger/index.js +99 -22
  2. package/dist/cjs/core/server/federatedCss.js +47 -0
  3. package/dist/cjs/core/server/stream/beforeTemplate.js +6 -1
  4. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +6 -1
  5. package/dist/cjs/core/server/stream/createReadableStream.js +4 -2
  6. package/dist/cjs/core/server/stream/createReadableStream.worker.js +3 -2
  7. package/dist/cjs/core/server/stream/shared.js +2 -1
  8. package/dist/cjs/core/server/string/index.js +2 -1
  9. package/dist/cjs/core/server/string/loadable.js +18 -7
  10. package/dist/cjs/router/cli/code/tanstackTypes.js +15 -0
  11. package/dist/esm/boundary-debugger/index.mjs +99 -22
  12. package/dist/esm/core/server/federatedCss.mjs +13 -0
  13. package/dist/esm/core/server/stream/beforeTemplate.mjs +6 -1
  14. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +6 -1
  15. package/dist/esm/core/server/stream/createReadableStream.mjs +4 -2
  16. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +3 -2
  17. package/dist/esm/core/server/stream/shared.mjs +2 -1
  18. package/dist/esm/core/server/string/index.mjs +2 -1
  19. package/dist/esm/core/server/string/loadable.mjs +18 -7
  20. package/dist/esm/router/cli/code/tanstackTypes.mjs +15 -0
  21. package/dist/esm-node/boundary-debugger/index.mjs +99 -22
  22. package/dist/esm-node/core/server/federatedCss.mjs +14 -0
  23. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +6 -1
  24. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +6 -1
  25. package/dist/esm-node/core/server/stream/createReadableStream.mjs +4 -2
  26. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +3 -2
  27. package/dist/esm-node/core/server/stream/shared.mjs +2 -1
  28. package/dist/esm-node/core/server/string/index.mjs +2 -1
  29. package/dist/esm-node/core/server/string/loadable.mjs +18 -7
  30. package/dist/esm-node/router/cli/code/tanstackTypes.mjs +15 -0
  31. package/dist/types/boundary-debugger/index.d.ts +3 -0
  32. package/dist/types/core/server/federatedCss.d.ts +5 -0
  33. package/dist/types/core/server/stream/beforeTemplate.d.ts +1 -0
  34. package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +1 -0
  35. package/dist/types/core/server/stream/shared.d.ts +1 -0
  36. package/dist/types/core/server/string/loadable.d.ts +1 -0
  37. package/package.json +9 -9
@@ -2,12 +2,14 @@ import "node:module";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useMemo, useState } from "react";
4
4
  const defaultStorageKey = 'modernjs:boundary-debugger:enabled';
5
+ const queryParamName = 'modern-boundaries';
6
+ const boundarySelector = '[data-modern-boundary-id]';
5
7
  const defaultLabels = {
6
8
  cs: {
7
- toggle: 'zobrazit hranice verticalů'
9
+ toggle: 'zobrazit hranice týmů'
8
10
  },
9
11
  en: {
10
- toggle: 'show vertical boundaries'
12
+ toggle: 'show team boundaries'
11
13
  }
12
14
  };
13
15
  const palette = [
@@ -17,18 +19,64 @@ const palette = [
17
19
  '#7c8cff',
18
20
  '#29b6f6'
19
21
  ];
20
- const readEnabled = (storageKey, fallback)=>{
22
+ const readStoredEnabled = (storageKey, fallback)=>{
21
23
  if ("u" < typeof window) return fallback;
22
- const stored = window.localStorage.getItem(storageKey);
23
- return null === stored ? fallback : 'true' === stored;
24
+ try {
25
+ const stored = window.localStorage.getItem(storageKey);
26
+ return null === stored ? fallback : 'true' === stored;
27
+ } catch {
28
+ return fallback;
29
+ }
30
+ };
31
+ const writeStoredEnabled = (storageKey, enabled)=>{
32
+ if ("u" < typeof window) return;
33
+ try {
34
+ window.localStorage.setItem(storageKey, String(enabled));
35
+ } catch {}
36
+ };
37
+ const parseEnabledOverride = (value)=>{
38
+ if (null === value) return;
39
+ const normalized = value.toLowerCase();
40
+ if ('1' === normalized || 'true' === normalized) return true;
41
+ if ('0' === normalized || 'false' === normalized) return false;
42
+ };
43
+ const readQueryEnabledOverride = ()=>{
44
+ if ("u" < typeof window) return;
45
+ try {
46
+ return parseEnabledOverride(new URLSearchParams(window.location.search).get(queryParamName));
47
+ } catch {
48
+ return;
49
+ }
24
50
  };
25
51
  const detectLanguage = ()=>{
26
52
  if ("u" < typeof document) return 'en';
27
53
  const htmlLanguage = document.documentElement.lang;
28
54
  if (htmlLanguage) return htmlLanguage.split('-')[0] || 'en';
55
+ if ("u" < typeof window) return 'en';
29
56
  return window.location.pathname.split('/').filter(Boolean)[0] || 'en';
30
57
  };
31
- function BoundaryDebugger({ enabledByDefault = false, labels = defaultLabels, metadata, storageKey = defaultStorageKey }) {
58
+ const hashBoundaryId = (id)=>{
59
+ let hash = 0;
60
+ for(let index = 0; index < id.length; index++)hash = 31 * hash + id.charCodeAt(index) >>> 0;
61
+ return hash;
62
+ };
63
+ const formatRectKey = (rect)=>[
64
+ Math.round(100 * rect.left) / 100,
65
+ Math.round(100 * rect.top) / 100,
66
+ Math.round(100 * rect.width) / 100,
67
+ Math.round(100 * rect.height) / 100
68
+ ].join(':');
69
+ const getBoundaryId = (element)=>element.dataset.modernBoundaryId ?? element.dataset.mfRemote ?? element.getAttribute('data-mf-remote') ?? void 0;
70
+ const collectBoundaryElements = (legacySelector)=>{
71
+ const elements = new Set();
72
+ for (const element of document.querySelectorAll(boundarySelector))elements.add(element);
73
+ if (!legacySelector) return Array.from(elements);
74
+ try {
75
+ for (const element of document.querySelectorAll(legacySelector))elements.add(element);
76
+ } catch {}
77
+ return Array.from(elements);
78
+ };
79
+ function BoundaryDebugger({ controlMode = 'visible', enabledByDefault = false, labels = defaultLabels, legacySelector, metadata, storageKey = defaultStorageKey }) {
32
80
  const [mounted, setMounted] = useState(false);
33
81
  const [enabled, setEnabled] = useState(false);
34
82
  const [boxes, setBoxes] = useState([]);
@@ -43,17 +91,18 @@ function BoundaryDebugger({ enabledByDefault = false, labels = defaultLabels, me
43
91
  metadata
44
92
  ]);
45
93
  const language = mounted ? detectLanguage() : 'en';
46
- const toggleLabel = labels[language]?.toggle ?? labels.en?.toggle ?? defaultLabels.en?.toggle ?? 'show vertical boundaries';
94
+ const toggleLabel = labels[language]?.toggle ?? labels.en?.toggle ?? defaultLabels.en?.toggle ?? 'show team boundaries';
47
95
  useEffect(()=>{
48
96
  setMounted(true);
49
- setEnabled(readEnabled(storageKey, enabledByDefault));
97
+ const queryOverride = readQueryEnabledOverride();
98
+ setEnabled(queryOverride ?? readStoredEnabled(storageKey, enabledByDefault));
50
99
  }, [
51
100
  enabledByDefault,
52
101
  storageKey
53
102
  ]);
54
103
  useEffect(()=>{
55
104
  if (!mounted) return;
56
- window.localStorage.setItem(storageKey, String(enabled));
105
+ writeStoredEnabled(storageKey, enabled);
57
106
  }, [
58
107
  enabled,
59
108
  mounted,
@@ -62,28 +111,38 @@ function BoundaryDebugger({ enabledByDefault = false, labels = defaultLabels, me
62
111
  useEffect(()=>{
63
112
  if (!enabled) return void setBoxes([]);
64
113
  const readBoxes = ()=>{
65
- const nextBoxes = Array.from(document.querySelectorAll('[data-modern-boundary-id]')).map((element, index)=>{
66
- const boundaryId = element.dataset.modernBoundaryId;
114
+ const seenBoxes = new Set();
115
+ const nextBoxes = collectBoundaryElements(legacySelector).map((element)=>{
116
+ const boundaryId = getBoundaryId(element);
67
117
  if (!boundaryId) return;
68
118
  const rect = element.getBoundingClientRect();
69
119
  if (rect.width <= 0 || rect.height <= 0) return;
120
+ const rectKey = formatRectKey(rect);
121
+ const boxKey = `${boundaryId}:${rectKey}`;
122
+ if (seenBoxes.has(boxKey)) return;
123
+ seenBoxes.add(boxKey);
70
124
  const boundary = boundaries.get(boundaryId);
71
- const color = boundary?.color ?? palette[index % palette.length];
72
- return {
125
+ const color = boundary?.color ?? palette[hashBoundaryId(boundaryId) % palette.length];
126
+ const label = boundary?.label ?? boundary?.appId ?? boundaryId;
127
+ const expose = element.dataset.modernMfExpose;
128
+ const detail = expose && expose !== label && expose !== boundaryId ? expose : void 0;
129
+ const box = {
73
130
  color,
74
131
  height: rect.height,
75
- id: `${boundaryId}-${index}`,
76
- label: boundary?.label ?? boundaryId,
132
+ id: boxKey,
133
+ label,
77
134
  left: rect.left,
78
135
  top: rect.top,
79
136
  width: rect.width
80
137
  };
138
+ if (detail) box.detail = detail;
139
+ return box;
81
140
  }).filter((box)=>void 0 !== box);
82
141
  setBoxes(nextBoxes);
83
142
  };
84
143
  readBoxes();
85
144
  const resizeObserver = "u" < typeof ResizeObserver ? void 0 : new ResizeObserver(readBoxes);
86
- for (const element of document.querySelectorAll('[data-modern-boundary-id]'))resizeObserver?.observe(element);
145
+ for (const element of collectBoundaryElements(legacySelector))resizeObserver?.observe(element);
87
146
  const mutationObserver = new MutationObserver(readBoxes);
88
147
  mutationObserver.observe(document.body, {
89
148
  childList: true,
@@ -99,12 +158,14 @@ function BoundaryDebugger({ enabledByDefault = false, labels = defaultLabels, me
99
158
  };
100
159
  }, [
101
160
  boundaries,
102
- enabled
161
+ enabled,
162
+ legacySelector
103
163
  ]);
104
164
  if (!mounted) return null;
165
+ const shouldRenderToggle = 'visible' === controlMode || 'hidden-when-off' === controlMode && enabled;
105
166
  return /*#__PURE__*/ jsxs(Fragment, {
106
167
  children: [
107
- /*#__PURE__*/ jsxs("label", {
168
+ shouldRenderToggle ? /*#__PURE__*/ jsxs("label", {
108
169
  style: {
109
170
  alignItems: 'center',
110
171
  background: 'rgba(255, 255, 255, 0.96)',
@@ -131,7 +192,7 @@ function BoundaryDebugger({ enabledByDefault = false, labels = defaultLabels, me
131
192
  children: toggleLabel
132
193
  })
133
194
  ]
134
- }),
195
+ }) : null,
135
196
  enabled ? /*#__PURE__*/ jsx("div", {
136
197
  "aria-hidden": "true",
137
198
  children: boxes.map((box)=>/*#__PURE__*/ jsx("div", {
@@ -147,19 +208,35 @@ function BoundaryDebugger({ enabledByDefault = false, labels = defaultLabels, me
147
208
  width: box.width,
148
209
  zIndex: 2147482999
149
210
  },
150
- children: /*#__PURE__*/ jsx("span", {
211
+ children: /*#__PURE__*/ jsxs("span", {
151
212
  style: {
152
213
  background: box.color,
153
214
  borderRadius: 999,
154
215
  color: '#111827',
155
- font: '800 11px/1 system-ui, sans-serif',
216
+ display: 'grid',
217
+ font: '800 11px/1.1 system-ui, sans-serif',
218
+ gap: 3,
219
+ maxWidth: 'min(280px, calc(100vw - 24px))',
156
220
  padding: '5px 8px',
157
221
  position: 'absolute',
158
222
  right: 4,
159
223
  top: 4,
160
224
  whiteSpace: 'nowrap'
161
225
  },
162
- children: box.label
226
+ children: [
227
+ /*#__PURE__*/ jsx("span", {
228
+ children: box.label
229
+ }),
230
+ box.detail ? /*#__PURE__*/ jsx("span", {
231
+ style: {
232
+ font: '700 10px/1.1 system-ui, sans-serif',
233
+ opacity: 0.82,
234
+ overflow: 'hidden',
235
+ textOverflow: 'ellipsis'
236
+ },
237
+ children: box.detail
238
+ }) : null
239
+ ]
163
240
  })
164
241
  }, box.id))
165
242
  }) : null
@@ -0,0 +1,14 @@
1
+ import "node:module";
2
+ import { attributesToString } from "./utils.mjs";
3
+ const createFederatedCssLinks = (assets, options)=>{
4
+ if (!assets?.length) return '';
5
+ const seen = new Set(options.existingAssets || []);
6
+ const attributes = attributesToString(options.attributes || {});
7
+ const links = [];
8
+ for (const asset of assets)if (!(!asset || seen.has(asset) || options.template.includes(asset))) {
9
+ seen.add(asset);
10
+ links.push(`<link${attributes} href="${asset}" rel="stylesheet" />`);
11
+ }
12
+ return links.join('');
13
+ };
14
+ export { createFederatedCssLinks };
@@ -3,6 +3,7 @@ import { matchRoutes } from "@modern-js/runtime-utils/router";
3
3
  import react_helmet from "react-helmet";
4
4
  import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
5
5
  import { CHUNK_CSS_PLACEHOLDER } from "../constants.mjs";
6
+ import { createFederatedCssLinks } from "../federatedCss.mjs";
6
7
  import { createReplaceHelemt } from "../helmet.mjs";
7
8
  import { buildHtml } from "../shared.mjs";
8
9
  import { checkIsNode, safeReplace } from "../utils.mjs";
@@ -21,7 +22,7 @@ const checkIsInline = (chunk, enableInline)=>{
21
22
  return Boolean(enableInline);
22
23
  };
23
24
  async function buildShellBeforeTemplate(beforeAppTemplate, options) {
24
- const { config, runtimeContext, styledComponentsStyleTags, entryName } = options;
25
+ const { config, runtimeContext, styledComponentsStyleTags, entryName, moduleFederationCssAssets } = options;
25
26
  const helmetData = react_helmet.renderStatic();
26
27
  const callbacks = [
27
28
  createReplaceHelemt(helmetData),
@@ -31,6 +32,10 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
31
32
  async function injectCss(template, entryName, styledComponentsStyleTags) {
32
33
  let css = await getCssChunks();
33
34
  if (styledComponentsStyleTags) css += styledComponentsStyleTags;
35
+ css += createFederatedCssLinks(moduleFederationCssAssets, {
36
+ template,
37
+ existingAssets: css.match(/href="([^"]+)"/g)?.map((item)=>item.replace(/^href="/, '').replace(/"$/, ''))
38
+ });
34
39
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
35
40
  async function getCssChunks() {
36
41
  const { routeManifest, routerContext, routes } = runtimeContext;
@@ -3,6 +3,7 @@ import { matchRoutes } from "@modern-js/runtime-utils/router";
3
3
  import react_helmet from "react-helmet";
4
4
  import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
5
5
  import { CHUNK_CSS_PLACEHOLDER } from "../constants.mjs";
6
+ import { createFederatedCssLinks } from "../federatedCss.mjs";
6
7
  import { createReplaceHelemt } from "../helmet.mjs";
7
8
  import { buildHtml } from "../shared.mjs";
8
9
  import { safeReplace } from "../utils.mjs";
@@ -12,7 +13,7 @@ const checkIsInline = (chunk, enableInline)=>{
12
13
  return Boolean(enableInline);
13
14
  };
14
15
  async function buildShellBeforeTemplate(beforeAppTemplate, options) {
15
- const { config, runtimeContext, styledComponentsStyleTags, entryName } = options;
16
+ const { config, runtimeContext, styledComponentsStyleTags, entryName, moduleFederationCssAssets } = options;
16
17
  const helmetData = react_helmet.renderStatic();
17
18
  const callbacks = [
18
19
  createReplaceHelemt(helmetData),
@@ -22,6 +23,10 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
22
23
  async function injectCss(template, entryName, styledComponentsStyleTags) {
23
24
  let css = await getCssChunks();
24
25
  if (styledComponentsStyleTags) css += styledComponentsStyleTags;
26
+ css += createFederatedCssLinks(moduleFederationCssAssets, {
27
+ template,
28
+ existingAssets: css.match(/href="([^"]+)"/g)?.map((item)=>item.replace(/^href="/, '').replace(/"$/, ''))
29
+ });
25
30
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
26
31
  async function getCssChunks() {
27
32
  const { routeManifest, routerContext, routes } = runtimeContext;
@@ -16,7 +16,7 @@ const defaultExtender = {
16
16
  };
17
17
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
18
18
  const { renderToPipeableStream } = await import("react-dom/server");
19
- const { runtimeContext, htmlTemplate, config, ssrConfig, entryName } = options;
19
+ const { runtimeContext, htmlTemplate, config, ssrConfig, entryName, moduleFederationCssAssets } = options;
20
20
  let shellChunkStatus = ShellChunkStatus.START;
21
21
  let renderLevel = RenderLevel.SERVER_RENDER;
22
22
  const forceStream2String = Boolean(process.env.MODERN_JS_STREAM_TO_STRING);
@@ -53,6 +53,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
53
53
  runtimeContext,
54
54
  config,
55
55
  entryName,
56
+ moduleFederationCssAssets,
56
57
  styledComponentsStyleTags
57
58
  }).then(({ shellAfter, shellBefore })=>{
58
59
  const pendingScripts = [];
@@ -110,7 +111,8 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
110
111
  renderLevel,
111
112
  runtimeContext,
112
113
  entryName,
113
- config
114
+ config,
115
+ moduleFederationCssAssets
114
116
  }).then(({ shellAfter, shellBefore })=>{
115
117
  const fallbackHtml = `${shellBefore}${shellAfter}`;
116
118
  const readableStream = getReadableStreamFromString(fallbackHtml);
@@ -9,14 +9,15 @@ import { getTemplates } from "./template.mjs";
9
9
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
10
10
  let shellChunkStatus = ShellChunkStatus.START;
11
11
  const chunkVec = [];
12
- const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, rscManifest, rscRoot } = options;
12
+ const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, moduleFederationCssAssets, rscManifest, rscRoot } = options;
13
13
  const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
14
14
  renderLevel: RenderLevel.SERVER_RENDER,
15
15
  runtimeContext,
16
16
  ssrConfig,
17
17
  request,
18
18
  config,
19
- entryName
19
+ entryName,
20
+ moduleFederationCssAssets
20
21
  });
21
22
  try {
22
23
  const readableOriginal = await renderSSRStream(rootElement, {
@@ -64,7 +64,7 @@ function createRenderStreaming(createReadableStreamPromise) {
64
64
  const end = time();
65
65
  const { runtimeContext, config, resource } = options;
66
66
  const { onError, onTiming } = options;
67
- const { htmlTemplate, entryName } = resource;
67
+ const { htmlTemplate, entryName, moduleFederationCssAssets } = resource;
68
68
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
69
69
  const StreamServerRootWrapper = ({ children })=>/*#__PURE__*/ jsxs(Fragment, {
70
70
  children: [
@@ -84,6 +84,7 @@ function createRenderStreaming(createReadableStreamPromise) {
84
84
  runtimeContext,
85
85
  ssrConfig,
86
86
  entryName,
87
+ moduleFederationCssAssets,
87
88
  rscClientManifest: options.rscClientManifest,
88
89
  rscSSRManifest: options.rscSSRManifest,
89
90
  rscServerManifest: options.rscServerManifest,
@@ -20,7 +20,7 @@ const renderString = async (request, serverRoot, options)=>{
20
20
  onTiming
21
21
  };
22
22
  const routerContext = runtimeContext.routerContext;
23
- const { htmlTemplate, entryName, loadableStats, routeManifest } = resource;
23
+ const { htmlTemplate, entryName, loadableStats, routeManifest, moduleFederationCssAssets } = resource;
24
24
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
25
25
  const chunkSet = {
26
26
  renderLevel: RenderLevel.CLIENT_RENDER,
@@ -36,6 +36,7 @@ const renderString = async (request, serverRoot, options)=>{
36
36
  runtimeContext,
37
37
  template: htmlTemplate,
38
38
  entryName,
39
+ moduleFederationCssAssets,
39
40
  chunkSet,
40
41
  config
41
42
  }),
@@ -1,6 +1,7 @@
1
1
  import "node:module";
2
2
  import { ChunkExtractor } from "@loadable/server";
3
3
  import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
4
+ import { createFederatedCssLinks } from "../federatedCss.mjs";
4
5
  import { attributesToString, checkIsNode } from "../utils.mjs";
5
6
  import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
6
7
  import { dirname as __rspack_dirname } from "node:path";
@@ -52,20 +53,21 @@ class LoadableCollector {
52
53
  return this.extractor.collectChunks(comopnent);
53
54
  }
54
55
  async effect() {
55
- if (!this.extractor) return;
56
56
  const { extractor, options } = this;
57
57
  const { entryName, config } = options;
58
58
  const asyncChunks = [];
59
- if (config.enableAsyncEntry) try {
59
+ if (extractor && config.enableAsyncEntry) try {
60
60
  asyncChunks.push(...extractor.getChunkAssets([
61
61
  `async-${entryName}`
62
62
  ]));
63
63
  } catch (e) {}
64
- const chunks = [].concat(asyncChunks).concat(extractor.getChunkAssets(extractor.chunks)).concat(this.getMatchedRouteChunks());
64
+ const chunks = [].concat(asyncChunks).concat(extractor ? extractor.getChunkAssets(extractor.chunks) : []).concat(this.getMatchedRouteChunks());
65
65
  const scriptChunks = generateChunks(chunks, 'js');
66
66
  const styleChunks = generateChunks(chunks, 'css');
67
- this.emitLoadableScripts(extractor);
68
- await this.emitScriptAssets(scriptChunks);
67
+ if (extractor) {
68
+ this.emitLoadableScripts(extractor);
69
+ await this.emitScriptAssets(scriptChunks);
70
+ }
69
71
  await this.emitStyleAssets(styleChunks);
70
72
  }
71
73
  emitLoadableScripts(extractor) {
@@ -100,19 +102,28 @@ class LoadableCollector {
100
102
  chunkSet.jsChunk += scripts.filter((script)=>Boolean(script)).join('');
101
103
  }
102
104
  async emitStyleAssets(chunks) {
103
- const { template, chunkSet, config, entryName } = this.options;
105
+ const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
104
106
  const { inlineStyles } = config;
105
107
  const atrributes = attributesToString(this.generateAttributes());
106
108
  const linkRegExp = /<link .*?href="([^"]+)".*?>/g;
107
109
  const matchs = template.matchAll(linkRegExp);
108
110
  const existedLinks = [];
109
111
  for (const match of matchs)existedLinks.push(match[1]);
110
- const css = await Promise.all(chunks.filter((chunk)=>!existedLinks.includes(chunk.url) && !this.existsAssets?.includes(chunk.path)).map(async (chunk)=>{
112
+ const emittedChunks = chunks.filter((chunk)=>!existedLinks.includes(chunk.url) && !this.existsAssets?.includes(chunk.path));
113
+ const css = await Promise.all(emittedChunks.map(async (chunk)=>{
111
114
  const link = `<link${atrributes} href="${chunk.url}" rel="stylesheet" />`;
112
115
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
113
116
  return link;
114
117
  }));
115
118
  chunkSet.cssChunk += css.filter((css)=>Boolean(css)).join('');
119
+ chunkSet.cssChunk += createFederatedCssLinks(moduleFederationCssAssets, {
120
+ template,
121
+ attributes: this.generateAttributes(),
122
+ existingAssets: [
123
+ ...existedLinks,
124
+ ...emittedChunks.map((chunk)=>chunk.url)
125
+ ]
126
+ });
116
127
  }
117
128
  generateAttributes(extraAtr = {}) {
118
129
  const { config } = this.options;
@@ -78,10 +78,21 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
78
78
  const topLevel = rootModern ? rootModern.children || [] : routes;
79
79
  const imports = [];
80
80
  const statements = [];
81
+ const componentImportMap = new Map();
81
82
  const loaderImportMap = new Map();
82
83
  const usedRouteVarNames = new Set();
84
+ let componentIndex = 0;
83
85
  let loaderIndex = 0;
84
86
  let routeIndex = 0;
87
+ const getImportNameForComponent = (componentPath)=>{
88
+ if ('string' != typeof componentPath || 0 === componentPath.length) return null;
89
+ const existing = componentImportMap.get(componentPath);
90
+ if (existing) return existing;
91
+ const componentName = `component_${componentIndex++}`;
92
+ imports.push(`import ${componentName} from ${quote(componentPath)};`);
93
+ componentImportMap.set(componentPath, componentName);
94
+ return componentName;
95
+ };
85
96
  const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
86
97
  const key = `${inline ? 'inline' : 'default'}:${hasAction ? 'action' : 'loader'}:${aliasedNoExtPath}`;
87
98
  const existing = loaderImportMap.get(key);
@@ -138,6 +149,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
138
149
  const routeOpts = [
139
150
  `getParentRoute: () => ${parentVar},`
140
151
  ];
152
+ const componentName = getImportNameForComponent(route._component);
153
+ if (componentName) routeOpts.push(`component: ${componentName},`);
141
154
  if (isPathlessLayout(route)) {
142
155
  const id = route.id;
143
156
  routeOpts.push(`id: ${quote(id || 'pathless')},`);
@@ -175,6 +188,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
175
188
  route
176
189
  })));
177
190
  const rootOpts = [];
191
+ const rootComponentName = getImportNameForComponent(rootModern?._component);
192
+ if (rootComponentName) rootOpts.push(`component: ${rootComponentName},`);
178
193
  if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
179
194
  const routerGenTs = `/* eslint-disable */
180
195
  // This file is auto-generated by Modern.js. Do not edit manually.
@@ -13,11 +13,14 @@ export type BoundaryDebugMetadata = {
13
13
  boundaries: BoundaryDebugEntry[];
14
14
  schemaVersion: 1;
15
15
  };
16
+ export type BoundaryDebuggerControlMode = 'visible' | 'hidden-when-off' | 'hidden';
16
17
  export type BoundaryDebuggerPluginOptions = {
18
+ controlMode?: BoundaryDebuggerControlMode;
17
19
  enabledByDefault?: boolean;
18
20
  labels?: Record<string, {
19
21
  toggle: string;
20
22
  }>;
23
+ legacySelector?: string;
21
24
  metadata: BoundaryDebugMetadata;
22
25
  storageKey?: string;
23
26
  };
@@ -0,0 +1,5 @@
1
+ export declare const createFederatedCssLinks: (assets: string[] | undefined, options: {
2
+ template: string;
3
+ attributes?: Record<string, any>;
4
+ existingAssets?: Iterable<string>;
5
+ }) => string;
@@ -5,5 +5,6 @@ export interface BuildShellBeforeTemplateOptions {
5
5
  entryName: string;
6
6
  config: HandleRequestConfig;
7
7
  styledComponentsStyleTags?: string;
8
+ moduleFederationCssAssets?: string[];
8
9
  }
9
10
  export declare function buildShellBeforeTemplate(beforeAppTemplate: string, options: BuildShellBeforeTemplateOptions): Promise<string>;
@@ -5,5 +5,6 @@ export interface BuildShellBeforeTemplateOptions {
5
5
  entryName: string;
6
6
  config: HandleRequestConfig;
7
7
  styledComponentsStyleTags?: string;
8
+ moduleFederationCssAssets?: string[];
8
9
  }
9
10
  export declare function buildShellBeforeTemplate(beforeAppTemplate: string, options: BuildShellBeforeTemplateOptions): Promise<string>;
@@ -16,6 +16,7 @@ export type CreateReadableStreamFromElementOptions = {
16
16
  ssrConfig: SSRConfig;
17
17
  htmlTemplate: string;
18
18
  entryName: string;
19
+ moduleFederationCssAssets?: string[];
19
20
  rscClientManifest?: RscClientManifest;
20
21
  rscSSRManifest?: RscSSRManifest;
21
22
  rscServerManifest?: RscServerManifest;
@@ -14,6 +14,7 @@ export interface LoadableCollectorOptions {
14
14
  runtimeContext: TInternalRuntimeContext;
15
15
  template: string;
16
16
  entryName: string;
17
+ moduleFederationCssAssets?: string[];
17
18
  chunkSet: ChunkSet;
18
19
  config: LoadableCollectorConfig;
19
20
  }
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.2.0-ultramodern.62",
20
+ "version": "3.2.0-ultramodern.63",
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
@@ -234,12 +234,12 @@
234
234
  "isbot": "5.1.40",
235
235
  "react-helmet": "^6.1.0",
236
236
  "react-is": "^19.2.6",
237
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.62",
238
- "@modern-js/render": "npm:@bleedingdev/modern-js-render@3.2.0-ultramodern.62",
239
- "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.2.0-ultramodern.62",
240
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.62",
241
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.62",
242
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.62"
237
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.63",
238
+ "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.2.0-ultramodern.63",
239
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.63",
240
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.63",
241
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.63",
242
+ "@modern-js/render": "npm:@bleedingdev/modern-js-render@3.2.0-ultramodern.63"
243
243
  },
244
244
  "peerDependencies": {
245
245
  "react": "^19.2.6",
@@ -258,8 +258,8 @@
258
258
  "@typescript/native-preview": "7.0.0-dev.20260527.2",
259
259
  "react": "^19.2.6",
260
260
  "react-dom": "^19.2.6",
261
- "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.62",
262
- "@scripts/rstest-config": "2.66.0"
261
+ "@scripts/rstest-config": "2.66.0",
262
+ "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.63"
263
263
  },
264
264
  "sideEffects": false,
265
265
  "publishConfig": {