@module-federation/bridge-react 0.0.0-next-20250920074657 → 0.0.0-next-20250923081154

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.
package/CHANGELOG.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # @module-federation/bridge-react
2
2
 
3
- ## 0.0.0-next-20250920074657
3
+ ## 0.0.0-next-20250923081154
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - @module-federation/sdk@0.0.0-next-20250920074657
8
- - @module-federation/bridge-shared@0.0.0-next-20250920074657
7
+ - @module-federation/sdk@0.0.0-next-20250923081154
8
+ - @module-federation/bridge-shared@0.0.0-next-20250923081154
9
9
 
10
10
  ## 0.19.1
11
11
 
@@ -66,12 +66,8 @@ describe('bridge', () => {
66
66
  );
67
67
  expect(getHtml(container)).toMatch('loading');
68
68
 
69
- await waitFor(
70
- () => {
71
- expect(getHtml(container)).toMatch('life cycle render');
72
- },
73
- { timeout: 1000 },
74
- );
69
+ await sleep(200);
70
+ expect(getHtml(container)).toMatch('life cycle render');
75
71
  expect(getHtml(container)).toMatch('hello world');
76
72
  });
77
73
 
@@ -101,12 +97,8 @@ describe('bridge', () => {
101
97
  );
102
98
  expect(getHtml(container)).toMatch('loading');
103
99
 
104
- await waitFor(
105
- () => {
106
- expect(getHtml(container)).toMatch('life cycle render');
107
- },
108
- { timeout: 1000 },
109
- );
100
+ await sleep(200);
101
+ expect(getHtml(container)).toMatch('life cycle render');
110
102
  expect(getHtml(container)).toMatch('hello world');
111
103
  expect(ref.current).not.toBeNull();
112
104
  });
@@ -139,11 +131,7 @@ describe('bridge', () => {
139
131
  const { container } = render(<RemoteComponent />);
140
132
  expect(getHtml(container)).toMatch('loading');
141
133
 
142
- await waitFor(
143
- () => {
144
- expect(renderMock).toHaveBeenCalledTimes(1);
145
- },
146
- { timeout: 1000 },
147
- );
134
+ await sleep(200);
135
+ expect(renderMock).toHaveBeenCalledTimes(1);
148
136
  });
149
137
  });
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const lazyUtils = require("./utils-vIpCrZmn.js");
4
- const prefetch = require("./prefetch-DfV67tNF.js");
4
+ const prefetch = require("./prefetch-BnEr_VXN.js");
5
5
  async function callDataFetch() {
6
6
  const dataFetch = globalThis[lazyUtils.DATA_FETCH_FUNCTION];
7
7
  if (dataFetch) {
@@ -1,7 +1,7 @@
1
1
  import { x as DATA_FETCH_FUNCTION } from "./utils-VSOJTX_o.mjs";
2
2
  import { C, b, e, h, c, d, r } from "./utils-VSOJTX_o.mjs";
3
- import { d as dataFetchFunction } from "./prefetch-BfuXjKtn.mjs";
4
- import { i, p } from "./prefetch-BfuXjKtn.mjs";
3
+ import { d as dataFetchFunction } from "./prefetch-DIwspSj-.mjs";
4
+ import { i, p } from "./prefetch-DIwspSj-.mjs";
5
5
  async function callDataFetch() {
6
6
  const dataFetch = globalThis[DATA_FETCH_FUNCTION];
7
7
  if (dataFetch) {
package/dist/index.cjs.js CHANGED
@@ -6,10 +6,10 @@ const React = require("react");
6
6
  const index = require("./index-eN2xRRXs.js");
7
7
  const ReactRouterDOM = require("react-router-dom");
8
8
  const plugin = require("./plugin.cjs.js");
9
- const lazyLoadComponentPlugin = require("./lazy-load-component-plugin-DFiVXILi.js");
9
+ const lazyLoadComponentPlugin = require("./lazy-load-component-plugin-Br-Tkghx.js");
10
10
  const lazyUtils = require("./utils-vIpCrZmn.js");
11
11
  const dataFetchUtils = require("./data-fetch-utils.cjs.js");
12
- const prefetch = require("./prefetch-DfV67tNF.js");
12
+ const prefetch = require("./prefetch-BnEr_VXN.js");
13
13
  function _interopNamespaceDefault(e2) {
14
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
15
15
  if (e2) {
@@ -28,37 +28,19 @@ function _interopNamespaceDefault(e2) {
28
28
  }
29
29
  const ReactRouterDOM__namespace = /* @__PURE__ */ _interopNamespaceDefault(ReactRouterDOM);
30
30
  function createReact16Or17Root(container) {
31
- const reactVersion = ReactDOM.version || "";
32
- const isReact18Plus = reactVersion.startsWith("18") || reactVersion.startsWith("19");
33
- if (isReact18Plus) {
34
- let modernRoot = null;
35
- return {
36
- render(children) {
37
- if (!modernRoot) {
38
- try {
39
- const { createRoot } = require("react-dom/client");
40
- modernRoot = createRoot(container);
41
- } catch (error) {
42
- ReactDOM.render(children, container);
43
- return;
44
- }
45
- }
46
- modernRoot.render(children);
47
- },
48
- unmount() {
49
- if (modernRoot) {
50
- modernRoot.unmount();
51
- } else {
52
- ReactDOM.unmountComponentAtNode(container);
53
- }
54
- }
55
- };
56
- }
57
31
  return {
58
32
  render(children) {
59
- if (process.env.NODE_ENV !== "test") {
33
+ const reactVersion = ReactDOM.version || "";
34
+ const isReact18 = reactVersion.startsWith("18");
35
+ const isReact19 = reactVersion.startsWith("19");
36
+ if (isReact19) {
37
+ throw new Error(
38
+ `React 19 detected in legacy mode. This is not supported. Please use the version-specific import: import { createBridgeComponent } from '@module-federation/bridge-react/v19'`
39
+ );
40
+ }
41
+ if (isReact18) {
60
42
  console.warn(
61
- `[Bridge-React] React 16/17 detected. For better compatibility, consider using version-specific imports: import { createBridgeComponent } from '@module-federation/bridge-react/v18' or v19`
43
+ `[Bridge-React] React 18 detected in legacy mode. For better compatibility, please use the version-specific import: import { createBridgeComponent } from '@module-federation/bridge-react/v18'`
62
44
  );
63
45
  }
64
46
  ReactDOM.render(children, container);
package/dist/index.d.ts CHANGED
@@ -241,7 +241,7 @@ export declare interface RenderParams {
241
241
  export declare function revalidateTag(tag: string): void;
242
242
 
243
243
  export declare interface Root {
244
- render(children: default_2.ReactNode): void;
244
+ render(children: React.ReactNode): void;
245
245
  unmount(): void;
246
246
  }
247
247
 
package/dist/index.es.js CHANGED
@@ -4,42 +4,24 @@ import React__default, { forwardRef, useContext, useState, useEffect, useRef } f
4
4
  import { p as pathJoin, L as LoggerInstance, g as getRootDomDefaultClassName } from "./index-rAO0Wr0M.mjs";
5
5
  import * as ReactRouterDOM from "react-router-dom";
6
6
  import { federationRuntime } from "./plugin.es.js";
7
- import { b, a, c, l } from "./lazy-load-component-plugin-CENdJeja.mjs";
7
+ import { b, a, c, l } from "./lazy-load-component-plugin-Cgr7vjhe.mjs";
8
8
  import { C, b as b2, E, e, h, c as c2, d, r, s } from "./utils-VSOJTX_o.mjs";
9
9
  import { callDataFetch } from "./data-fetch-utils.es.js";
10
- import { p } from "./prefetch-BfuXjKtn.mjs";
10
+ import { p } from "./prefetch-DIwspSj-.mjs";
11
11
  function createReact16Or17Root(container) {
12
- const reactVersion = ReactDOM.version || "";
13
- const isReact18Plus = reactVersion.startsWith("18") || reactVersion.startsWith("19");
14
- if (isReact18Plus) {
15
- let modernRoot = null;
16
- return {
17
- render(children) {
18
- if (!modernRoot) {
19
- try {
20
- const { createRoot } = require("react-dom/client");
21
- modernRoot = createRoot(container);
22
- } catch (error) {
23
- ReactDOM.render(children, container);
24
- return;
25
- }
26
- }
27
- modernRoot.render(children);
28
- },
29
- unmount() {
30
- if (modernRoot) {
31
- modernRoot.unmount();
32
- } else {
33
- ReactDOM.unmountComponentAtNode(container);
34
- }
35
- }
36
- };
37
- }
38
12
  return {
39
13
  render(children) {
40
- if (process.env.NODE_ENV !== "test") {
14
+ const reactVersion = ReactDOM.version || "";
15
+ const isReact18 = reactVersion.startsWith("18");
16
+ const isReact19 = reactVersion.startsWith("19");
17
+ if (isReact19) {
18
+ throw new Error(
19
+ `React 19 detected in legacy mode. This is not supported. Please use the version-specific import: import { createBridgeComponent } from '@module-federation/bridge-react/v19'`
20
+ );
21
+ }
22
+ if (isReact18) {
41
23
  console.warn(
42
- `[Bridge-React] React 16/17 detected. For better compatibility, consider using version-specific imports: import { createBridgeComponent } from '@module-federation/bridge-react/v18' or v19`
24
+ `[Bridge-React] React 18 detected in legacy mode. For better compatibility, please use the version-specific import: import { createBridgeComponent } from '@module-federation/bridge-react/v18'`
43
25
  );
44
26
  }
45
27
  ReactDOM.render(children, container);
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const prefetch = require("./prefetch-DfV67tNF.js");
2
+ const prefetch = require("./prefetch-BnEr_VXN.js");
3
3
  const lazyUtils = require("./utils-vIpCrZmn.js");
4
4
  const React = require("react");
5
5
  const autoFetchData = () => {
@@ -112,7 +112,7 @@ function AwaitDataFetch({
112
112
  params,
113
113
  delayLoading
114
114
  }) {
115
- const dataRef = React.useRef(void 0);
115
+ const dataRef = React.useRef();
116
116
  const data = dataRef.current || resolve;
117
117
  const getData = isPromise(data) ? fetchData(data, dataRef) : () => data;
118
118
  return /* @__PURE__ */ React.createElement(
@@ -1,4 +1,4 @@
1
- import { i as injectDataFetch, p as prefetch } from "./prefetch-BfuXjKtn.mjs";
1
+ import { i as injectDataFetch, p as prefetch } from "./prefetch-DIwspSj-.mjs";
2
2
  import { i as initDataFetchMap, j as isDataLoaderExpose, k as getDataFetchInfo, m as getDataFetchMapKey, l as logger, n as getDataFetchItem, o as DATA_FETCH_CLIENT_SUFFIX, p as MF_DATA_FETCH_TYPE, q as isCSROnly, a as loadDataFetchModule, M as MF_DATA_FETCH_STATUS, g as getDataFetchMap, t as isServerEnv, u as getDataFetchIdWithErrorMsgs, v as DATA_FETCH_ERROR_PREFIX, E as ERROR_TYPE, w as wrapDataFetchId, L as LOAD_REMOTE_ERROR_PREFIX, x as DATA_FETCH_FUNCTION, y as getLoadedRemoteInfos, f as fetchData$1, z as setDataFetchItemLoadedStatus, F as FS_HREF } from "./utils-VSOJTX_o.mjs";
3
3
  import React__default, { useRef, useState, Suspense, useEffect } from "react";
4
4
  const autoFetchData = () => {
@@ -111,7 +111,7 @@ function AwaitDataFetch({
111
111
  params,
112
112
  delayLoading
113
113
  }) {
114
- const dataRef = useRef(void 0);
114
+ const dataRef = useRef();
115
115
  const data = dataRef.current || resolve;
116
116
  const getData = isPromise(data) ? fetchData(data, dataRef) : () => data;
117
117
  return /* @__PURE__ */ React__default.createElement(
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- const lazyLoadComponentPlugin = require("./lazy-load-component-plugin-DFiVXILi.js");
4
- require("./prefetch-DfV67tNF.js");
3
+ const lazyLoadComponentPlugin = require("./lazy-load-component-plugin-Br-Tkghx.js");
4
+ require("./prefetch-BnEr_VXN.js");
5
5
  exports.default = lazyLoadComponentPlugin.lazyLoadComponentPlugin;
6
6
  exports.lazyLoadComponentPlugin = lazyLoadComponentPlugin.lazyLoadComponentPlugin;
@@ -1,5 +1,5 @@
1
- import { l, l as l2 } from "./lazy-load-component-plugin-CENdJeja.mjs";
2
- import "./prefetch-BfuXjKtn.mjs";
1
+ import { l, l as l2 } from "./lazy-load-component-plugin-Cgr7vjhe.mjs";
2
+ import "./prefetch-DIwspSj-.mjs";
3
3
  export {
4
4
  l as default,
5
5
  l2 as lazyLoadComponentPlugin
@@ -271,7 +271,7 @@ function getGlobalFederationConstructor() {
271
271
  function setGlobalFederationConstructor(FederationConstructor, isDebug = index_esm.isDebugMode()) {
272
272
  if (isDebug) {
273
273
  CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
274
- CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.0.0-next-20250920074657";
274
+ CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.0.0-next-20250923081154";
275
275
  }
276
276
  }
277
277
  function getInfoWithoutType(target, key) {
@@ -362,8 +362,8 @@ const registerGlobalPlugins = (plugins) => {
362
362
  const getGlobalHostPlugins = () => nativeGlobal.__FEDERATION__.__GLOBAL_PLUGIN__;
363
363
  const getPreloaded = (id) => CurrentGlobal.__FEDERATION__.__PRELOADED_MAP__.get(id);
364
364
  const setPreloaded = (id) => CurrentGlobal.__FEDERATION__.__PRELOADED_MAP__.set(id, true);
365
- const DEFAULT_REMOTE_TYPE = "global";
366
365
  const DEFAULT_SCOPE = "default";
366
+ const DEFAULT_REMOTE_TYPE = "global";
367
367
  const buildIdentifier = "[0-9A-Za-z-]+";
368
368
  const build = `(?:\\+(${buildIdentifier}(?:\\.${buildIdentifier})*))`;
369
369
  const numericIdentifier = "0|[1-9]\\d*";
@@ -1043,7 +1043,7 @@ function getRemoteEntryUniqueKey(remoteInfo) {
1043
1043
  return index_esm.composeKeyWithSeparator(name, entry);
1044
1044
  }
1045
1045
  async function getRemoteEntry(params) {
1046
- const { origin, remoteEntryExports, remoteInfo, getEntryUrl } = params;
1046
+ const { origin, remoteEntryExports, remoteInfo, getEntryUrl, _inErrorHandling = false } = params;
1047
1047
  const uniqueKey = getRemoteEntryUniqueKey(remoteInfo);
1048
1048
  if (remoteEntryExports) {
1049
1049
  return remoteEntryExports;
@@ -1069,6 +1069,28 @@ async function getRemoteEntry(params) {
1069
1069
  remoteInfo,
1070
1070
  loaderHook
1071
1071
  });
1072
+ }).catch(async (err) => {
1073
+ const uniqueKey2 = getRemoteEntryUniqueKey(remoteInfo);
1074
+ const isScriptLoadError = err instanceof Error && err.message.includes(RUNTIME_008);
1075
+ if (isScriptLoadError && !_inErrorHandling) {
1076
+ const wrappedGetRemoteEntry = (params2) => {
1077
+ return getRemoteEntry(_extends$1({}, params2, {
1078
+ _inErrorHandling: true
1079
+ }));
1080
+ };
1081
+ const RemoteEntryExports = await origin.loaderHook.lifecycle.loadEntryError.emit({
1082
+ getRemoteEntry: wrappedGetRemoteEntry,
1083
+ origin,
1084
+ remoteInfo,
1085
+ remoteEntryExports,
1086
+ globalLoading,
1087
+ uniqueKey: uniqueKey2
1088
+ });
1089
+ if (RemoteEntryExports) {
1090
+ return RemoteEntryExports;
1091
+ }
1092
+ }
1093
+ throw err;
1072
1094
  });
1073
1095
  }
1074
1096
  return globalLoading[uniqueKey];
@@ -270,7 +270,7 @@ function getGlobalFederationConstructor() {
270
270
  function setGlobalFederationConstructor(FederationConstructor, isDebug = isDebugMode()) {
271
271
  if (isDebug) {
272
272
  CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
273
- CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.0.0-next-20250920074657";
273
+ CurrentGlobal.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.0.0-next-20250923081154";
274
274
  }
275
275
  }
276
276
  function getInfoWithoutType(target, key) {
@@ -361,8 +361,8 @@ const registerGlobalPlugins = (plugins) => {
361
361
  const getGlobalHostPlugins = () => nativeGlobal.__FEDERATION__.__GLOBAL_PLUGIN__;
362
362
  const getPreloaded = (id) => CurrentGlobal.__FEDERATION__.__PRELOADED_MAP__.get(id);
363
363
  const setPreloaded = (id) => CurrentGlobal.__FEDERATION__.__PRELOADED_MAP__.set(id, true);
364
- const DEFAULT_REMOTE_TYPE = "global";
365
364
  const DEFAULT_SCOPE = "default";
365
+ const DEFAULT_REMOTE_TYPE = "global";
366
366
  const buildIdentifier = "[0-9A-Za-z-]+";
367
367
  const build = `(?:\\+(${buildIdentifier}(?:\\.${buildIdentifier})*))`;
368
368
  const numericIdentifier = "0|[1-9]\\d*";
@@ -1042,7 +1042,7 @@ function getRemoteEntryUniqueKey(remoteInfo) {
1042
1042
  return composeKeyWithSeparator(name, entry);
1043
1043
  }
1044
1044
  async function getRemoteEntry(params) {
1045
- const { origin, remoteEntryExports, remoteInfo, getEntryUrl } = params;
1045
+ const { origin, remoteEntryExports, remoteInfo, getEntryUrl, _inErrorHandling = false } = params;
1046
1046
  const uniqueKey = getRemoteEntryUniqueKey(remoteInfo);
1047
1047
  if (remoteEntryExports) {
1048
1048
  return remoteEntryExports;
@@ -1068,6 +1068,28 @@ async function getRemoteEntry(params) {
1068
1068
  remoteInfo,
1069
1069
  loaderHook
1070
1070
  });
1071
+ }).catch(async (err) => {
1072
+ const uniqueKey2 = getRemoteEntryUniqueKey(remoteInfo);
1073
+ const isScriptLoadError = err instanceof Error && err.message.includes(RUNTIME_008);
1074
+ if (isScriptLoadError && !_inErrorHandling) {
1075
+ const wrappedGetRemoteEntry = (params2) => {
1076
+ return getRemoteEntry(_extends$1({}, params2, {
1077
+ _inErrorHandling: true
1078
+ }));
1079
+ };
1080
+ const RemoteEntryExports = await origin.loaderHook.lifecycle.loadEntryError.emit({
1081
+ getRemoteEntry: wrappedGetRemoteEntry,
1082
+ origin,
1083
+ remoteInfo,
1084
+ remoteEntryExports,
1085
+ globalLoading,
1086
+ uniqueKey: uniqueKey2
1087
+ });
1088
+ if (RemoteEntryExports) {
1089
+ return RemoteEntryExports;
1090
+ }
1091
+ }
1092
+ throw err;
1071
1093
  });
1072
1094
  }
1073
1095
  return globalLoading[uniqueKey];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/bridge-react",
3
- "version": "0.0.0-next-20250920074657",
3
+ "version": "0.0.0-next-20250923081154",
4
4
  "sideEffects": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -95,8 +95,8 @@
95
95
  "dependencies": {
96
96
  "react-error-boundary": "^4.1.2",
97
97
  "lru-cache": "^10.4.3",
98
- "@module-federation/bridge-shared": "0.0.0-next-20250920074657",
99
- "@module-federation/sdk": "0.0.0-next-20250920074657"
98
+ "@module-federation/sdk": "0.0.0-next-20250923081154",
99
+ "@module-federation/bridge-shared": "0.0.0-next-20250923081154"
100
100
  },
101
101
  "peerDependencies": {
102
102
  "react": ">=16.9.0",
@@ -106,21 +106,20 @@
106
106
  "devDependencies": {
107
107
  "@testing-library/react": "15.0.7",
108
108
  "@testing-library/jest-dom": "6.6.3",
109
- "@types/react": "19.0.0",
110
- "@types/react-dom": "19.0.0",
109
+ "@types/react": "18.2.79",
110
+ "@types/react-dom": "18.3.0",
111
111
  "@vitejs/plugin-react": "^4.3.3",
112
112
  "@vitejs/plugin-vue": "^5.0.4",
113
113
  "@vitejs/plugin-vue-jsx": "^4.0.0",
114
- "jsdom": "^24.1.0",
115
- "react": "19.0.0",
116
- "react-dom": "19.0.0",
114
+ "react": "18.3.1",
115
+ "react-dom": "18.3.1",
117
116
  "react-router-dom": "6.22.3",
118
117
  "typescript": "^5.2.2",
119
118
  "vite": "^5.4.18",
120
119
  "vite-plugin-dts": "^4.3.0",
121
120
  "hono": "3.12.12",
122
- "@module-federation/runtime-core": "0.0.0-next-20250920074657",
123
- "@module-federation/runtime": "0.0.0-next-20250920074657"
121
+ "@module-federation/runtime-core": "0.0.0-next-20250923081154",
122
+ "@module-federation/runtime": "0.0.0-next-20250923081154"
124
123
  },
125
124
  "scripts": {
126
125
  "dev": "vite",
@@ -91,11 +91,9 @@ export function AwaitDataFetch<T>({
91
91
  params,
92
92
  delayLoading,
93
93
  }: AwaitProps<T>) {
94
- const dataRef = useRef<T | undefined>(undefined);
94
+ const dataRef = useRef<T>();
95
95
  const data = dataRef.current || resolve;
96
- const getData = isPromise(data)
97
- ? fetchData(data as Promise<T>, dataRef)
98
- : () => data;
96
+ const getData = isPromise(data) ? fetchData(data, dataRef) : () => data;
99
97
 
100
98
  return (
101
99
  <AwaitSuspense
@@ -308,7 +308,7 @@ export function createLazyComponent<T, E extends keyof T>(
308
308
  injectScript,
309
309
  });
310
310
 
311
- const Com = m[exportName as string] as React.FC<ComponentType>;
311
+ const Com = m[exportName] as React.FC<ComponentType>;
312
312
  if (exportName in m && typeof Com === 'function') {
313
313
  return {
314
314
  default: (props: Omit<ComponentType, 'key'> & { mfData?: unknown }) => (
@@ -350,6 +350,7 @@ export function createLazyComponent<T, E extends keyof T>(
350
350
  delayLoading={options.delayLoading}
351
351
  errorElement={options.fallback}
352
352
  >
353
+ {/* @ts-expect-error ignore */}
353
354
  {(data) => <LazyComponent {...args} mfData={data} />}
354
355
  </AwaitDataFetch>
355
356
  );
@@ -403,6 +404,7 @@ export function createLazyComponent<T, E extends keyof T>(
403
404
  </>
404
405
  );
405
406
  }
407
+ // @ts-expect-error ignore
406
408
  return <LazyComponent {...args} mfData={data} />;
407
409
  }
408
410
  };
@@ -5,7 +5,6 @@
5
5
  import type { ProviderFnParams } from '../../types';
6
6
  import { createBaseBridgeComponent } from './bridge-base';
7
7
  import ReactDOM from 'react-dom';
8
- import React from 'react';
9
8
 
10
9
  export interface CreateRootOptions {
11
10
  identifierPrefix?: string;
@@ -29,54 +28,40 @@ export interface Root {
29
28
  export function createReact16Or17Root(
30
29
  container: Element | DocumentFragment,
31
30
  ): Root {
32
- /**
33
- * Detect React version
34
- */
35
- const reactVersion = ReactDOM.version || '';
36
- const isReact18Plus =
37
- reactVersion.startsWith('18') || reactVersion.startsWith('19');
38
-
39
- if (isReact18Plus) {
40
- // For React 18+, use the modern createRoot API
41
- let modernRoot: any = null;
42
-
43
- return {
44
- render(children: React.ReactNode) {
45
- if (!modernRoot) {
46
- try {
47
- // Import createRoot dynamically to avoid issues if not available
48
- const { createRoot } = require('react-dom/client');
49
- modernRoot = createRoot(container);
50
- } catch (error) {
51
- // Fallback to legacy API if createRoot is not available
52
- // @ts-ignore - React 17's render method is deprecated but still functional
53
- ReactDOM.render(children, container);
54
- return;
55
- }
56
- }
57
- modernRoot.render(children);
58
- },
59
- unmount() {
60
- if (modernRoot) {
61
- modernRoot.unmount();
62
- } else {
63
- ReactDOM.unmountComponentAtNode(container as Element);
64
- }
65
- },
66
- };
67
- }
68
-
69
- // For React 16/17, use the legacy API
70
31
  return {
71
32
  render(children: React.ReactNode) {
72
33
  /**
73
- * Provide warning for non-test environments to suggest version-specific imports
34
+ * Detect React version
35
+ */
36
+ const reactVersion = ReactDOM.version || '';
37
+ const isReact18 = reactVersion.startsWith('18');
38
+ const isReact19 = reactVersion.startsWith('19');
39
+
40
+ /**
41
+ * Throw error for React 19
42
+ *
43
+ * Note: Due to Module Federation sharing mechanism, the actual version detected here
44
+ * might be 18 or 19, even if the application itself uses React 16/17.
45
+ * This happens because in MF environments, different remote modules may share different React versions.
46
+ * The console may throw warnings about version and API mismatches. If you need to resolve these issues,
47
+ * consider disabling the shared configuration for React.
48
+ */
49
+ if (isReact19) {
50
+ throw new Error(
51
+ `React 19 detected in legacy mode. This is not supported. ` +
52
+ `Please use the version-specific import: ` +
53
+ `import { createBridgeComponent } from '@module-federation/bridge-react/v19'`,
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Provide warning for React 18
74
59
  */
75
- if (process.env.NODE_ENV !== 'test') {
60
+ if (isReact18) {
76
61
  console.warn(
77
- `[Bridge-React] React 16/17 detected. ` +
78
- `For better compatibility, consider using version-specific imports: ` +
79
- `import { createBridgeComponent } from '@module-federation/bridge-react/v18' or v19`,
62
+ `[Bridge-React] React 18 detected in legacy mode. ` +
63
+ `For better compatibility, please use the version-specific import: ` +
64
+ `import { createBridgeComponent } from '@module-federation/bridge-react/v18'`,
80
65
  );
81
66
  }
82
67