@module-federation/bridge-react 0.0.0-next-20250407031542 → 0.0.0-next-20250408024819
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 +18 -4
- package/dist/index.cjs.js +84 -14
- package/dist/index.d.ts +20 -1
- package/dist/index.es.js +62 -14
- package/package.json +4 -4
- package/src/provider/compat.ts +156 -24
- package/src/provider/create.tsx +14 -3
- package/src/types.ts +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
# @module-federation/bridge-react
|
|
2
2
|
|
|
3
|
-
## 0.0.0-next-
|
|
3
|
+
## 0.0.0-next-20250408024819
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- @module-federation/sdk@0.0.0-next-
|
|
9
|
-
- @module-federation/bridge-shared@0.0.0-next-
|
|
7
|
+
- chore: bump next
|
|
8
|
+
- @module-federation/sdk@0.0.0-next-20250408024819
|
|
9
|
+
- @module-federation/bridge-shared@0.0.0-next-20250408024819
|
|
10
|
+
|
|
11
|
+
## 0.12.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- 8b3f9d0: feat(react-bridge): Add native support for React 19 in bridge-react with enhanced createRoot options
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 8b3f9d0: feat(bridge-react): support react v19 in react compat file.
|
|
20
|
+
- Updated dependencies [64a2bc1]
|
|
21
|
+
- Updated dependencies [c14842f]
|
|
22
|
+
- @module-federation/sdk@0.12.0
|
|
23
|
+
- @module-federation/bridge-shared@0.12.0
|
|
10
24
|
|
|
11
25
|
## 0.11.3
|
|
12
26
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var _a, _b;
|
|
3
25
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
26
|
const React = require("react");
|
|
5
27
|
const context = require("./context-C79iMWYD.cjs");
|
|
@@ -146,13 +168,13 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
|
|
|
146
168
|
providerInfoRef.current = providerReturn;
|
|
147
169
|
setInitialized(true);
|
|
148
170
|
return () => {
|
|
149
|
-
var _a2,
|
|
171
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h;
|
|
150
172
|
if ((_a2 = providerInfoRef.current) == null ? void 0 : _a2.destroy) {
|
|
151
173
|
context.LoggerInstance.debug(
|
|
152
174
|
`createRemoteComponent LazyComponent destroy >>>`,
|
|
153
175
|
{ moduleName, basename, dom: renderDom.current }
|
|
154
176
|
);
|
|
155
|
-
(_d = (_c = (
|
|
177
|
+
(_d = (_c = (_b2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _b2.lifecycle) == null ? void 0 : _c.beforeBridgeDestroy) == null ? void 0 : _d.emit({
|
|
156
178
|
moduleName,
|
|
157
179
|
dom: renderDom.current,
|
|
158
180
|
basename,
|
|
@@ -176,7 +198,7 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
|
|
|
176
198
|
};
|
|
177
199
|
}, [moduleName]);
|
|
178
200
|
React.useEffect(() => {
|
|
179
|
-
var _a2,
|
|
201
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
180
202
|
if (!initialized || !providerInfoRef.current) return;
|
|
181
203
|
let renderProps = {
|
|
182
204
|
moduleName,
|
|
@@ -187,7 +209,7 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
|
|
|
187
209
|
...resProps
|
|
188
210
|
};
|
|
189
211
|
renderDom.current = rootRef.current;
|
|
190
|
-
const beforeBridgeRenderRes = ((_c = (
|
|
212
|
+
const beforeBridgeRenderRes = ((_c = (_b2 = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b2.beforeBridgeRender) == null ? void 0 : _c.emit(renderProps)) || {};
|
|
191
213
|
renderProps = { ...renderProps, ...beforeBridgeRenderRes.extraProps };
|
|
192
214
|
providerInfoRef.current.render(renderProps);
|
|
193
215
|
(_f = (_e = (_d = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _d.lifecycle) == null ? void 0 : _e.afterBridgeRender) == null ? void 0 : _f.emit(renderProps);
|
|
@@ -322,10 +344,40 @@ function createRemoteComponent(info) {
|
|
|
322
344
|
});
|
|
323
345
|
}
|
|
324
346
|
const isReact18 = (_a = ReactDOM.version) == null ? void 0 : _a.startsWith("18");
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
347
|
+
const isReact19 = (_b = ReactDOM.version) == null ? void 0 : _b.startsWith("19");
|
|
348
|
+
let reactDOMClientPromise = null;
|
|
349
|
+
async function loadReactDOMClient() {
|
|
350
|
+
if (!isReact19) return null;
|
|
351
|
+
if (!reactDOMClientPromise) {
|
|
352
|
+
reactDOMClientPromise = import("react-dom/client");
|
|
328
353
|
}
|
|
354
|
+
return reactDOMClientPromise;
|
|
355
|
+
}
|
|
356
|
+
function createReact19Root(container, options) {
|
|
357
|
+
loadReactDOMClient();
|
|
358
|
+
return {
|
|
359
|
+
render(children) {
|
|
360
|
+
loadReactDOMClient().then((client) => {
|
|
361
|
+
if (client && client.createRoot) {
|
|
362
|
+
const root = client.createRoot(container, options);
|
|
363
|
+
root.render(children);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
},
|
|
367
|
+
unmount() {
|
|
368
|
+
loadReactDOMClient().then((client) => {
|
|
369
|
+
if (client && client.createRoot) {
|
|
370
|
+
const root = client.createRoot(container, options);
|
|
371
|
+
root.unmount();
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function createReact18Root(container, options) {
|
|
378
|
+
return ReactDOM.createRoot(container, options);
|
|
379
|
+
}
|
|
380
|
+
function createReact16Or17Root(container) {
|
|
329
381
|
return {
|
|
330
382
|
render(children) {
|
|
331
383
|
ReactDOM.render(children, container);
|
|
@@ -335,8 +387,18 @@ function createRoot(container, options) {
|
|
|
335
387
|
}
|
|
336
388
|
};
|
|
337
389
|
}
|
|
390
|
+
function createRoot(container, options) {
|
|
391
|
+
if (isReact19) {
|
|
392
|
+
return createReact19Root(container, options);
|
|
393
|
+
}
|
|
394
|
+
if (isReact18) {
|
|
395
|
+
return createReact18Root(container, options);
|
|
396
|
+
}
|
|
397
|
+
return createReact16Or17Root(container);
|
|
398
|
+
}
|
|
338
399
|
function createBridgeComponent({
|
|
339
400
|
createRoot: createRoot$1 = createRoot,
|
|
401
|
+
defaultRootOptions,
|
|
340
402
|
...bridgeInfo
|
|
341
403
|
}) {
|
|
342
404
|
return () => {
|
|
@@ -360,7 +422,7 @@ function createBridgeComponent({
|
|
|
360
422
|
};
|
|
361
423
|
return {
|
|
362
424
|
async render(info) {
|
|
363
|
-
var _a2,
|
|
425
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
364
426
|
context.LoggerInstance.debug(`createBridgeComponent render Info`, info);
|
|
365
427
|
const {
|
|
366
428
|
moduleName,
|
|
@@ -368,9 +430,14 @@ function createBridgeComponent({
|
|
|
368
430
|
basename,
|
|
369
431
|
memoryRoute,
|
|
370
432
|
fallback,
|
|
433
|
+
rootOptions,
|
|
371
434
|
...propsInfo
|
|
372
435
|
} = info;
|
|
373
|
-
const
|
|
436
|
+
const mergedRootOptions = {
|
|
437
|
+
...defaultRootOptions,
|
|
438
|
+
...rootOptions
|
|
439
|
+
};
|
|
440
|
+
const beforeBridgeRenderRes = ((_c = (_b2 = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b2.beforeBridgeRender) == null ? void 0 : _c.emit(info)) || {};
|
|
374
441
|
const rootComponentWithErrorBoundary = /* @__PURE__ */ React__namespace.createElement(ErrorBoundary, { FallbackComponent: fallback }, /* @__PURE__ */ React__namespace.createElement(
|
|
375
442
|
RawComponent,
|
|
376
443
|
{
|
|
@@ -379,7 +446,10 @@ function createBridgeComponent({
|
|
|
379
446
|
basename,
|
|
380
447
|
memoryRoute
|
|
381
448
|
},
|
|
382
|
-
propsInfo: {
|
|
449
|
+
propsInfo: {
|
|
450
|
+
...propsInfo,
|
|
451
|
+
...beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps
|
|
452
|
+
}
|
|
383
453
|
}
|
|
384
454
|
));
|
|
385
455
|
if (bridgeInfo.render) {
|
|
@@ -389,7 +459,7 @@ function createBridgeComponent({
|
|
|
389
459
|
} else {
|
|
390
460
|
let root = rootMap.get(dom);
|
|
391
461
|
if (!root) {
|
|
392
|
-
root = createRoot$1(dom);
|
|
462
|
+
root = createRoot$1(dom, mergedRootOptions);
|
|
393
463
|
rootMap.set(dom, root);
|
|
394
464
|
}
|
|
395
465
|
if ("render" in root) {
|
|
@@ -399,7 +469,7 @@ function createBridgeComponent({
|
|
|
399
469
|
((_f = (_e = (_d = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _d.lifecycle) == null ? void 0 : _e.afterBridgeRender) == null ? void 0 : _f.emit(info)) || {};
|
|
400
470
|
},
|
|
401
471
|
destroy(info) {
|
|
402
|
-
var _a2,
|
|
472
|
+
var _a2, _b2, _c;
|
|
403
473
|
const { dom } = info;
|
|
404
474
|
context.LoggerInstance.debug(`createBridgeComponent destroy Info`, info);
|
|
405
475
|
const root = rootMap.get(dom);
|
|
@@ -411,7 +481,7 @@ function createBridgeComponent({
|
|
|
411
481
|
}
|
|
412
482
|
rootMap.delete(dom);
|
|
413
483
|
}
|
|
414
|
-
(_c = (
|
|
484
|
+
(_c = (_b2 = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b2.afterBridgeDestroy) == null ? void 0 : _c.emit(info);
|
|
415
485
|
}
|
|
416
486
|
};
|
|
417
487
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { default as default_2 } from 'react';
|
|
2
2
|
import * as React_2 from 'react';
|
|
3
3
|
|
|
4
|
-
export declare function createBridgeComponent<T>({ createRoot, ...bridgeInfo }: ProviderFnParams<T>): () => {
|
|
4
|
+
export declare function createBridgeComponent<T>({ createRoot, defaultRootOptions, ...bridgeInfo }: ProviderFnParams<T>): () => {
|
|
5
5
|
render(info: RenderParams): Promise<void>;
|
|
6
6
|
destroy(info: DestroyParams): void;
|
|
7
7
|
};
|
|
@@ -34,6 +34,16 @@ declare interface ProviderFnParams<T> {
|
|
|
34
34
|
rootComponent: React_2.ComponentType<T>;
|
|
35
35
|
render?: (App: React_2.ReactElement, id?: HTMLElement | string) => RootType | Promise<RootType>;
|
|
36
36
|
createRoot?: (container: Element | DocumentFragment, options?: CreateRootOptions) => Root;
|
|
37
|
+
/**
|
|
38
|
+
* Default options to pass to createRoot for React 18 and 19
|
|
39
|
+
* These options will be used when creating a root unless overridden by rootOptions in render params
|
|
40
|
+
* @example
|
|
41
|
+
* {
|
|
42
|
+
* identifierPrefix: 'app-',
|
|
43
|
+
* onRecoverableError: (err) => console.error(err)
|
|
44
|
+
* }
|
|
45
|
+
*/
|
|
46
|
+
defaultRootOptions?: CreateRootOptions;
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
/**
|
|
@@ -97,6 +107,15 @@ export declare interface RenderParams {
|
|
|
97
107
|
initialState?: Record<string, unknown>;
|
|
98
108
|
};
|
|
99
109
|
dom: HTMLElement;
|
|
110
|
+
/**
|
|
111
|
+
* Options to pass to createRoot for React 18 and 19
|
|
112
|
+
* @example
|
|
113
|
+
* {
|
|
114
|
+
* identifierPrefix: 'app-',
|
|
115
|
+
* onRecoverableError: (err) => console.error(err)
|
|
116
|
+
* }
|
|
117
|
+
*/
|
|
118
|
+
rootOptions?: CreateRootOptions;
|
|
100
119
|
[key: string]: unknown;
|
|
101
120
|
}
|
|
102
121
|
|
package/dist/index.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var _a;
|
|
1
|
+
var _a, _b;
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import React__default, { createContext, Component, createElement, forwardRef, useRef, useState, useEffect, useContext } from "react";
|
|
4
4
|
import { L as LoggerInstance, g as getRootDomDefaultClassName, p as pathJoin, R as RouterContext } from "./context-Dbqf0szX.js";
|
|
@@ -127,13 +127,13 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
|
|
|
127
127
|
providerInfoRef.current = providerReturn;
|
|
128
128
|
setInitialized(true);
|
|
129
129
|
return () => {
|
|
130
|
-
var _a2,
|
|
130
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h;
|
|
131
131
|
if ((_a2 = providerInfoRef.current) == null ? void 0 : _a2.destroy) {
|
|
132
132
|
LoggerInstance.debug(
|
|
133
133
|
`createRemoteComponent LazyComponent destroy >>>`,
|
|
134
134
|
{ moduleName, basename, dom: renderDom.current }
|
|
135
135
|
);
|
|
136
|
-
(_d = (_c = (
|
|
136
|
+
(_d = (_c = (_b2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _b2.lifecycle) == null ? void 0 : _c.beforeBridgeDestroy) == null ? void 0 : _d.emit({
|
|
137
137
|
moduleName,
|
|
138
138
|
dom: renderDom.current,
|
|
139
139
|
basename,
|
|
@@ -157,7 +157,7 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
|
|
|
157
157
|
};
|
|
158
158
|
}, [moduleName]);
|
|
159
159
|
useEffect(() => {
|
|
160
|
-
var _a2,
|
|
160
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
161
161
|
if (!initialized || !providerInfoRef.current) return;
|
|
162
162
|
let renderProps = {
|
|
163
163
|
moduleName,
|
|
@@ -168,7 +168,7 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
|
|
|
168
168
|
...resProps
|
|
169
169
|
};
|
|
170
170
|
renderDom.current = rootRef.current;
|
|
171
|
-
const beforeBridgeRenderRes = ((_c = (
|
|
171
|
+
const beforeBridgeRenderRes = ((_c = (_b2 = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b2.beforeBridgeRender) == null ? void 0 : _c.emit(renderProps)) || {};
|
|
172
172
|
renderProps = { ...renderProps, ...beforeBridgeRenderRes.extraProps };
|
|
173
173
|
providerInfoRef.current.render(renderProps);
|
|
174
174
|
(_f = (_e = (_d = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _d.lifecycle) == null ? void 0 : _e.afterBridgeRender) == null ? void 0 : _f.emit(renderProps);
|
|
@@ -303,10 +303,40 @@ function createRemoteComponent(info) {
|
|
|
303
303
|
});
|
|
304
304
|
}
|
|
305
305
|
const isReact18 = (_a = ReactDOM.version) == null ? void 0 : _a.startsWith("18");
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
306
|
+
const isReact19 = (_b = ReactDOM.version) == null ? void 0 : _b.startsWith("19");
|
|
307
|
+
let reactDOMClientPromise = null;
|
|
308
|
+
async function loadReactDOMClient() {
|
|
309
|
+
if (!isReact19) return null;
|
|
310
|
+
if (!reactDOMClientPromise) {
|
|
311
|
+
reactDOMClientPromise = import("react-dom/client");
|
|
309
312
|
}
|
|
313
|
+
return reactDOMClientPromise;
|
|
314
|
+
}
|
|
315
|
+
function createReact19Root(container, options) {
|
|
316
|
+
loadReactDOMClient();
|
|
317
|
+
return {
|
|
318
|
+
render(children) {
|
|
319
|
+
loadReactDOMClient().then((client) => {
|
|
320
|
+
if (client && client.createRoot) {
|
|
321
|
+
const root = client.createRoot(container, options);
|
|
322
|
+
root.render(children);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
},
|
|
326
|
+
unmount() {
|
|
327
|
+
loadReactDOMClient().then((client) => {
|
|
328
|
+
if (client && client.createRoot) {
|
|
329
|
+
const root = client.createRoot(container, options);
|
|
330
|
+
root.unmount();
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function createReact18Root(container, options) {
|
|
337
|
+
return ReactDOM.createRoot(container, options);
|
|
338
|
+
}
|
|
339
|
+
function createReact16Or17Root(container) {
|
|
310
340
|
return {
|
|
311
341
|
render(children) {
|
|
312
342
|
ReactDOM.render(children, container);
|
|
@@ -316,8 +346,18 @@ function createRoot(container, options) {
|
|
|
316
346
|
}
|
|
317
347
|
};
|
|
318
348
|
}
|
|
349
|
+
function createRoot(container, options) {
|
|
350
|
+
if (isReact19) {
|
|
351
|
+
return createReact19Root(container, options);
|
|
352
|
+
}
|
|
353
|
+
if (isReact18) {
|
|
354
|
+
return createReact18Root(container, options);
|
|
355
|
+
}
|
|
356
|
+
return createReact16Or17Root(container);
|
|
357
|
+
}
|
|
319
358
|
function createBridgeComponent({
|
|
320
359
|
createRoot: createRoot$1 = createRoot,
|
|
360
|
+
defaultRootOptions,
|
|
321
361
|
...bridgeInfo
|
|
322
362
|
}) {
|
|
323
363
|
return () => {
|
|
@@ -341,7 +381,7 @@ function createBridgeComponent({
|
|
|
341
381
|
};
|
|
342
382
|
return {
|
|
343
383
|
async render(info) {
|
|
344
|
-
var _a2,
|
|
384
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
345
385
|
LoggerInstance.debug(`createBridgeComponent render Info`, info);
|
|
346
386
|
const {
|
|
347
387
|
moduleName,
|
|
@@ -349,9 +389,14 @@ function createBridgeComponent({
|
|
|
349
389
|
basename,
|
|
350
390
|
memoryRoute,
|
|
351
391
|
fallback,
|
|
392
|
+
rootOptions,
|
|
352
393
|
...propsInfo
|
|
353
394
|
} = info;
|
|
354
|
-
const
|
|
395
|
+
const mergedRootOptions = {
|
|
396
|
+
...defaultRootOptions,
|
|
397
|
+
...rootOptions
|
|
398
|
+
};
|
|
399
|
+
const beforeBridgeRenderRes = ((_c = (_b2 = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b2.beforeBridgeRender) == null ? void 0 : _c.emit(info)) || {};
|
|
355
400
|
const rootComponentWithErrorBoundary = /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: fallback }, /* @__PURE__ */ React.createElement(
|
|
356
401
|
RawComponent,
|
|
357
402
|
{
|
|
@@ -360,7 +405,10 @@ function createBridgeComponent({
|
|
|
360
405
|
basename,
|
|
361
406
|
memoryRoute
|
|
362
407
|
},
|
|
363
|
-
propsInfo: {
|
|
408
|
+
propsInfo: {
|
|
409
|
+
...propsInfo,
|
|
410
|
+
...beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps
|
|
411
|
+
}
|
|
364
412
|
}
|
|
365
413
|
));
|
|
366
414
|
if (bridgeInfo.render) {
|
|
@@ -370,7 +418,7 @@ function createBridgeComponent({
|
|
|
370
418
|
} else {
|
|
371
419
|
let root = rootMap.get(dom);
|
|
372
420
|
if (!root) {
|
|
373
|
-
root = createRoot$1(dom);
|
|
421
|
+
root = createRoot$1(dom, mergedRootOptions);
|
|
374
422
|
rootMap.set(dom, root);
|
|
375
423
|
}
|
|
376
424
|
if ("render" in root) {
|
|
@@ -380,7 +428,7 @@ function createBridgeComponent({
|
|
|
380
428
|
((_f = (_e = (_d = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _d.lifecycle) == null ? void 0 : _e.afterBridgeRender) == null ? void 0 : _f.emit(info)) || {};
|
|
381
429
|
},
|
|
382
430
|
destroy(info) {
|
|
383
|
-
var _a2,
|
|
431
|
+
var _a2, _b2, _c;
|
|
384
432
|
const { dom } = info;
|
|
385
433
|
LoggerInstance.debug(`createBridgeComponent destroy Info`, info);
|
|
386
434
|
const root = rootMap.get(dom);
|
|
@@ -392,7 +440,7 @@ function createBridgeComponent({
|
|
|
392
440
|
}
|
|
393
441
|
rootMap.delete(dom);
|
|
394
442
|
}
|
|
395
|
-
(_c = (
|
|
443
|
+
(_c = (_b2 = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b2.afterBridgeDestroy) == null ? void 0 : _c.emit(info);
|
|
396
444
|
}
|
|
397
445
|
};
|
|
398
446
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@module-federation/bridge-react",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-20250408024819",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"react-error-boundary": "^4.1.2",
|
|
48
|
-
"@module-federation/bridge-shared": "0.0.0-next-
|
|
49
|
-
"@module-federation/sdk": "0.0.0-next-
|
|
48
|
+
"@module-federation/bridge-shared": "0.0.0-next-20250408024819",
|
|
49
|
+
"@module-federation/sdk": "0.0.0-next-20250408024819"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": ">=16.9.0",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"typescript": "^5.2.2",
|
|
68
68
|
"vite": "^5.4.12",
|
|
69
69
|
"vite-plugin-dts": "^4.3.0",
|
|
70
|
-
"@module-federation/runtime": "0.0.0-next-
|
|
70
|
+
"@module-federation/runtime": "0.0.0-next-20250408024819"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"dev": "vite",
|
package/src/provider/compat.ts
CHANGED
|
@@ -1,25 +1,88 @@
|
|
|
1
1
|
import ReactDOM from 'react-dom';
|
|
2
|
-
import { CreateRootOptions, Root } from '../types';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
export interface CreateRootOptions {
|
|
4
|
+
identifierPrefix?: string;
|
|
5
|
+
onRecoverableError?: (error: unknown) => void;
|
|
6
|
+
transitionCallbacks?: unknown;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface Root {
|
|
10
|
+
render(children: React.ReactNode): void;
|
|
11
|
+
unmount(): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Check React version
|
|
5
15
|
const isReact18 = ReactDOM.version?.startsWith('18');
|
|
16
|
+
const isReact19 = ReactDOM.version?.startsWith('19');
|
|
17
|
+
|
|
18
|
+
// Store the promise for async loaded ReactDOMClient
|
|
19
|
+
let reactDOMClientPromise: Promise<any> | null = null;
|
|
6
20
|
|
|
7
21
|
/**
|
|
8
|
-
*
|
|
22
|
+
* Asynchronously load the react-dom/client module
|
|
23
|
+
* Only attempts to load in React 19 environment
|
|
9
24
|
*/
|
|
10
|
-
|
|
25
|
+
async function loadReactDOMClient() {
|
|
26
|
+
if (!isReact19) return null;
|
|
27
|
+
|
|
28
|
+
if (!reactDOMClientPromise) {
|
|
29
|
+
reactDOMClientPromise = import('react-dom/client');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return reactDOMClientPromise;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a root for React 19 using dynamic import of react-dom/client
|
|
37
|
+
*/
|
|
38
|
+
function createReact19Root(
|
|
11
39
|
container: Element | DocumentFragment,
|
|
12
40
|
options?: CreateRootOptions,
|
|
13
41
|
): Root {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// @ts-ignore - Types will be available in React 18
|
|
17
|
-
return (ReactDOM as any).createRoot(container, options);
|
|
18
|
-
}
|
|
42
|
+
// Preload react-dom/client module
|
|
43
|
+
loadReactDOMClient();
|
|
19
44
|
|
|
20
|
-
//
|
|
45
|
+
// Return a simple Root object
|
|
21
46
|
return {
|
|
22
47
|
render(children: React.ReactNode) {
|
|
48
|
+
// Try to load client again when render is called
|
|
49
|
+
loadReactDOMClient().then((client) => {
|
|
50
|
+
if (client && client.createRoot) {
|
|
51
|
+
const root = client.createRoot(container, options);
|
|
52
|
+
root.render(children);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
unmount() {
|
|
57
|
+
// Try to load client again when unmount is called
|
|
58
|
+
loadReactDOMClient().then((client) => {
|
|
59
|
+
if (client && client.createRoot) {
|
|
60
|
+
const root = client.createRoot(container, options);
|
|
61
|
+
root.unmount();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Creates a root for React 18 using ReactDOM.createRoot
|
|
70
|
+
*/
|
|
71
|
+
function createReact18Root(
|
|
72
|
+
container: Element | DocumentFragment,
|
|
73
|
+
options?: CreateRootOptions,
|
|
74
|
+
): Root {
|
|
75
|
+
// @ts-ignore - Types will be available in React 18
|
|
76
|
+
return (ReactDOM as any).createRoot(container, options);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Creates a root for React 16/17 using legacy APIs
|
|
81
|
+
*/
|
|
82
|
+
function createReact16Or17Root(container: Element | DocumentFragment): Root {
|
|
83
|
+
return {
|
|
84
|
+
render(children: React.ReactNode) {
|
|
85
|
+
// @ts-ignore - React 17's render method is deprecated but still functional
|
|
23
86
|
ReactDOM.render(children, container);
|
|
24
87
|
},
|
|
25
88
|
unmount() {
|
|
@@ -29,32 +92,101 @@ export function createRoot(
|
|
|
29
92
|
}
|
|
30
93
|
|
|
31
94
|
/**
|
|
32
|
-
*
|
|
95
|
+
* Creates a root for a container element compatible with React 16, 18, and 19
|
|
33
96
|
*/
|
|
34
|
-
export function
|
|
97
|
+
export function createRoot(
|
|
35
98
|
container: Element | DocumentFragment,
|
|
36
|
-
initialChildren: React.ReactNode,
|
|
37
99
|
options?: CreateRootOptions,
|
|
38
100
|
): Root {
|
|
101
|
+
if (isReact19) {
|
|
102
|
+
return createReact19Root(container, options);
|
|
103
|
+
}
|
|
104
|
+
|
|
39
105
|
if (isReact18) {
|
|
40
|
-
|
|
41
|
-
// @ts-ignore - Types will be available in React 18
|
|
42
|
-
return (ReactDOM as any).hydrateRoot(container, initialChildren, options);
|
|
106
|
+
return createReact18Root(container, options);
|
|
43
107
|
}
|
|
44
108
|
|
|
45
|
-
// For React 16/17
|
|
109
|
+
// For React 16/17
|
|
110
|
+
return createReact16Or17Root(container);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Creates a hydration root for React 19 using dynamic import of react-dom/client
|
|
115
|
+
*/
|
|
116
|
+
function hydrateReact19Root(
|
|
117
|
+
container: Element | DocumentFragment,
|
|
118
|
+
initialChildren: React.ReactNode,
|
|
119
|
+
options?: CreateRootOptions,
|
|
120
|
+
): Root {
|
|
121
|
+
// Preload react-dom/client module
|
|
122
|
+
loadReactDOMClient();
|
|
123
|
+
|
|
124
|
+
// Return a simple Root object
|
|
46
125
|
return {
|
|
47
126
|
render(children: React.ReactNode) {
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
127
|
+
// Try to load client again when render is called
|
|
128
|
+
loadReactDOMClient().then((client) => {
|
|
129
|
+
if (client && client.hydrateRoot) {
|
|
130
|
+
const root = client.hydrateRoot(container, initialChildren, options);
|
|
131
|
+
root.render(children);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
unmount() {
|
|
136
|
+
// Try to load client again when unmount is called
|
|
137
|
+
loadReactDOMClient().then((client) => {
|
|
138
|
+
if (client && client.hydrateRoot) {
|
|
139
|
+
const root = client.hydrateRoot(container, initialChildren, options);
|
|
140
|
+
root.unmount();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Creates a hydration root for React 18 using ReactDOM.hydrateRoot
|
|
149
|
+
*/
|
|
150
|
+
function hydrateReact18Root(
|
|
151
|
+
container: Element | DocumentFragment,
|
|
152
|
+
initialChildren: React.ReactNode,
|
|
153
|
+
options?: CreateRootOptions,
|
|
154
|
+
): Root {
|
|
155
|
+
// @ts-ignore - Types will be available in React 18
|
|
156
|
+
return (ReactDOM as any).hydrateRoot(container, initialChildren, options);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Creates a hydration root for React 16/17 using legacy APIs
|
|
161
|
+
*/
|
|
162
|
+
function hydrateReact16Or17Root(container: Element | DocumentFragment): Root {
|
|
163
|
+
return {
|
|
164
|
+
render(children: React.ReactNode) {
|
|
165
|
+
// @ts-ignore - React 17's hydrate method is deprecated but still functional
|
|
166
|
+
ReactDOM.hydrate(children, container);
|
|
55
167
|
},
|
|
56
168
|
unmount() {
|
|
57
169
|
ReactDOM.unmountComponentAtNode(container);
|
|
58
170
|
},
|
|
59
171
|
};
|
|
60
172
|
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Hydrates a container compatible with React 16, 18, and 19
|
|
176
|
+
*/
|
|
177
|
+
export function hydrateRoot(
|
|
178
|
+
container: Element | DocumentFragment,
|
|
179
|
+
initialChildren: React.ReactNode,
|
|
180
|
+
options?: CreateRootOptions,
|
|
181
|
+
): Root {
|
|
182
|
+
if (isReact19) {
|
|
183
|
+
return hydrateReact19Root(container, initialChildren, options);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (isReact18) {
|
|
187
|
+
return hydrateReact18Root(container, initialChildren, options);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// For React 16/17
|
|
191
|
+
return hydrateReact16Or17Root(container);
|
|
192
|
+
}
|
package/src/provider/create.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
RootType,
|
|
7
7
|
DestroyParams,
|
|
8
8
|
RenderParams,
|
|
9
|
+
CreateRootOptions,
|
|
9
10
|
} from '../types';
|
|
10
11
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
11
12
|
import { RouterContext } from './context';
|
|
@@ -15,6 +16,7 @@ import { createRoot as defaultCreateRoot } from './compat';
|
|
|
15
16
|
|
|
16
17
|
export function createBridgeComponent<T>({
|
|
17
18
|
createRoot = defaultCreateRoot,
|
|
19
|
+
defaultRootOptions,
|
|
18
20
|
...bridgeInfo
|
|
19
21
|
}: ProviderFnParams<T>) {
|
|
20
22
|
return () => {
|
|
@@ -48,9 +50,16 @@ export function createBridgeComponent<T>({
|
|
|
48
50
|
basename,
|
|
49
51
|
memoryRoute,
|
|
50
52
|
fallback,
|
|
53
|
+
rootOptions,
|
|
51
54
|
...propsInfo
|
|
52
55
|
} = info;
|
|
53
56
|
|
|
57
|
+
// Merge default root options with render-specific root options
|
|
58
|
+
const mergedRootOptions: CreateRootOptions | undefined = {
|
|
59
|
+
...defaultRootOptions,
|
|
60
|
+
...(rootOptions as CreateRootOptions),
|
|
61
|
+
};
|
|
62
|
+
|
|
54
63
|
const beforeBridgeRenderRes =
|
|
55
64
|
instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info) || {};
|
|
56
65
|
|
|
@@ -63,7 +72,10 @@ export function createBridgeComponent<T>({
|
|
|
63
72
|
memoryRoute,
|
|
64
73
|
}}
|
|
65
74
|
propsInfo={
|
|
66
|
-
{
|
|
75
|
+
{
|
|
76
|
+
...propsInfo,
|
|
77
|
+
...(beforeBridgeRenderRes as any)?.extraProps,
|
|
78
|
+
} as T
|
|
67
79
|
}
|
|
68
80
|
/>
|
|
69
81
|
</ErrorBoundary>
|
|
@@ -77,7 +89,7 @@ export function createBridgeComponent<T>({
|
|
|
77
89
|
let root = rootMap.get(dom);
|
|
78
90
|
// do not call createRoot multiple times
|
|
79
91
|
if (!root) {
|
|
80
|
-
root = createRoot(dom);
|
|
92
|
+
root = createRoot(dom, mergedRootOptions);
|
|
81
93
|
rootMap.set(dom, root);
|
|
82
94
|
}
|
|
83
95
|
|
|
@@ -85,7 +97,6 @@ export function createBridgeComponent<T>({
|
|
|
85
97
|
root.render(rootComponentWithErrorBoundary);
|
|
86
98
|
}
|
|
87
99
|
}
|
|
88
|
-
|
|
89
100
|
instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info) || {};
|
|
90
101
|
},
|
|
91
102
|
|
package/src/types.ts
CHANGED
|
@@ -34,6 +34,15 @@ export interface RenderParams {
|
|
|
34
34
|
initialState?: Record<string, unknown>;
|
|
35
35
|
};
|
|
36
36
|
dom: HTMLElement;
|
|
37
|
+
/**
|
|
38
|
+
* Options to pass to createRoot for React 18 and 19
|
|
39
|
+
* @example
|
|
40
|
+
* {
|
|
41
|
+
* identifierPrefix: 'app-',
|
|
42
|
+
* onRecoverableError: (err) => console.error(err)
|
|
43
|
+
* }
|
|
44
|
+
*/
|
|
45
|
+
rootOptions?: CreateRootOptions;
|
|
37
46
|
[key: string]: unknown;
|
|
38
47
|
}
|
|
39
48
|
|
|
@@ -81,6 +90,16 @@ export interface ProviderFnParams<T> {
|
|
|
81
90
|
container: Element | DocumentFragment,
|
|
82
91
|
options?: CreateRootOptions,
|
|
83
92
|
) => Root;
|
|
93
|
+
/**
|
|
94
|
+
* Default options to pass to createRoot for React 18 and 19
|
|
95
|
+
* These options will be used when creating a root unless overridden by rootOptions in render params
|
|
96
|
+
* @example
|
|
97
|
+
* {
|
|
98
|
+
* identifierPrefix: 'app-',
|
|
99
|
+
* onRecoverableError: (err) => console.error(err)
|
|
100
|
+
* }
|
|
101
|
+
*/
|
|
102
|
+
defaultRootOptions?: CreateRootOptions;
|
|
84
103
|
}
|
|
85
104
|
|
|
86
105
|
/**
|