@module-federation/bridge-react 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @module-federation/bridge-react
2
2
 
3
+ ## 0.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 790bdea: fix(bridge-react): export DestroyParams and RenderParams types
8
+ - @module-federation/sdk@0.11.1
9
+ - @module-federation/bridge-shared@0.11.1
10
+
11
+ ## 0.11.0
12
+
13
+ ### Patch Changes
14
+
15
+ - 4d67b8f: feat(bridge-react): enable custom createRoot in bridge-react
16
+ - 2d086fc: Fix react-bridge version check for React versions earlier than 16.13.0
17
+ - 4d67b8f: refactor(bridge-react): centralize type definitions into a single file for better maintainability and consistency
18
+ - Updated dependencies [fce107e]
19
+ - @module-federation/sdk@0.11.0
20
+ - @module-federation/bridge-shared@0.11.0
21
+
3
22
  ## 0.10.0
4
23
 
5
24
  ### Minor Changes
@@ -102,4 +102,36 @@ describe('bridge', () => {
102
102
  expect(getHtml(container)).toMatch('hello world');
103
103
  expect(ref.current).not.toBeNull();
104
104
  });
105
+
106
+ it('createRemoteComponent with custom createRoot prop', async () => {
107
+ const renderMock = vi.fn();
108
+
109
+ function Component({ props }: { props?: Record<string, any> }) {
110
+ return <div>life cycle render {props?.msg}</div>;
111
+ }
112
+ const BridgeComponent = createBridgeComponent({
113
+ rootComponent: Component,
114
+ createRoot: () => {
115
+ return {
116
+ render: renderMock,
117
+ unmount: vi.fn(),
118
+ };
119
+ },
120
+ });
121
+ const RemoteComponent = createRemoteComponent({
122
+ loader: async () => {
123
+ return {
124
+ default: BridgeComponent,
125
+ };
126
+ },
127
+ fallback: () => <div></div>,
128
+ loading: <div>loading</div>,
129
+ });
130
+
131
+ const { container } = render(<RemoteComponent />);
132
+ expect(getHtml(container)).toMatch('loading');
133
+
134
+ await sleep(200);
135
+ expect(renderMock).toHaveBeenCalledTimes(1);
136
+ });
105
137
  });
package/dist/index.cjs.js CHANGED
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ var _a;
2
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
4
  const React = require("react");
4
5
  const context = require("./context-yPtLY2cD.cjs");
@@ -140,14 +141,13 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
140
141
  const [initialized, setInitialized] = React.useState(false);
141
142
  context.LoggerInstance.debug(`RemoteAppWrapper instance from props >>>`, instance);
142
143
  React.useEffect(() => {
143
- if (initialized)
144
- return;
144
+ if (initialized) return;
145
145
  const providerReturn = providerInfo();
146
146
  providerInfoRef.current = providerReturn;
147
147
  setInitialized(true);
148
148
  return () => {
149
- var _a, _b, _c, _d, _e, _f, _g, _h;
150
- if ((_a = providerInfoRef.current) == null ? void 0 : _a.destroy) {
149
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
150
+ if ((_a2 = providerInfoRef.current) == null ? void 0 : _a2.destroy) {
151
151
  context.LoggerInstance.debug(
152
152
  `createRemoteComponent LazyComponent destroy >>>`,
153
153
  { moduleName, basename, dom: renderDom.current }
@@ -176,9 +176,8 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
176
176
  };
177
177
  }, [moduleName]);
178
178
  React.useEffect(() => {
179
- var _a, _b, _c, _d, _e, _f;
180
- if (!initialized || !providerInfoRef.current)
181
- return;
179
+ var _a2, _b, _c, _d, _e, _f;
180
+ if (!initialized || !providerInfoRef.current) return;
182
181
  let renderProps = {
183
182
  moduleName,
184
183
  dom: rootRef.current,
@@ -188,7 +187,7 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
188
187
  ...resProps
189
188
  };
190
189
  renderDom.current = rootRef.current;
191
- const beforeBridgeRenderRes = ((_c = (_b = (_a = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(renderProps)) || {};
190
+ const beforeBridgeRenderRes = ((_c = (_b = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(renderProps)) || {};
192
191
  renderProps = { ...renderProps, ...beforeBridgeRenderRes.extraProps };
193
192
  providerInfoRef.current.render(renderProps);
194
193
  (_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);
@@ -198,7 +197,7 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
198
197
  });
199
198
  function withRouterData(WrappedComponent) {
200
199
  const Component = React.forwardRef(function(props, ref) {
201
- var _a;
200
+ var _a2;
202
201
  if (props == null ? void 0 : props.basename) {
203
202
  return /* @__PURE__ */ React.createElement(WrappedComponent, { ...props, basename: props.basename, ref });
204
203
  }
@@ -231,7 +230,7 @@ function withRouterData(WrappedComponent) {
231
230
  const match = useRouteMatch == null ? void 0 : useRouteMatch();
232
231
  if (useHistory) {
233
232
  const history = useHistory == null ? void 0 : useHistory();
234
- basename = (_a = history == null ? void 0 : history.createHref) == null ? void 0 : _a.call(history, { pathname: "/" });
233
+ basename = (_a2 = history == null ? void 0 : history.createHref) == null ? void 0 : _a2.call(history, { pathname: "/" });
235
234
  }
236
235
  if (match) {
237
236
  basename = context.pathJoin(basename, (match == null ? void 0 : match.path) || "/");
@@ -318,13 +317,11 @@ function createLazyRemoteComponent(info) {
318
317
  }
319
318
  function createRemoteComponent(info) {
320
319
  const LazyComponent = createLazyRemoteComponent(info);
321
- return React.forwardRef(
322
- (props, ref) => {
323
- return /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React.createElement(React.Suspense, { fallback: info.loading }, /* @__PURE__ */ React.createElement(LazyComponent, { ...props, ref })));
324
- }
325
- );
320
+ return React.forwardRef((props, ref) => {
321
+ return /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React.createElement(React.Suspense, { fallback: info.loading }, /* @__PURE__ */ React.createElement(LazyComponent, { ...props, ref })));
322
+ });
326
323
  }
327
- const isReact18 = ReactDOM.version.startsWith("18");
324
+ const isReact18 = (_a = ReactDOM.version) == null ? void 0 : _a.startsWith("18");
328
325
  function createRoot(container, options) {
329
326
  if (isReact18) {
330
327
  return ReactDOM.createRoot(container, options);
@@ -338,7 +335,10 @@ function createRoot(container, options) {
338
335
  }
339
336
  };
340
337
  }
341
- function createBridgeComponent(bridgeInfo) {
338
+ function createBridgeComponent({
339
+ createRoot: createRoot$1 = createRoot,
340
+ ...bridgeInfo
341
+ }) {
342
342
  return () => {
343
343
  const rootMap = /* @__PURE__ */ new Map();
344
344
  const instance = plugin.federationRuntime.instance;
@@ -360,7 +360,7 @@ function createBridgeComponent(bridgeInfo) {
360
360
  };
361
361
  return {
362
362
  async render(info) {
363
- var _a, _b, _c, _d, _e, _f;
363
+ var _a2, _b, _c, _d, _e, _f;
364
364
  context.LoggerInstance.debug(`createBridgeComponent render Info`, info);
365
365
  const {
366
366
  moduleName,
@@ -370,7 +370,7 @@ function createBridgeComponent(bridgeInfo) {
370
370
  fallback,
371
371
  ...propsInfo
372
372
  } = info;
373
- const beforeBridgeRenderRes = ((_c = (_b = (_a = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(info)) || {};
373
+ const beforeBridgeRenderRes = ((_c = (_b = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(info)) || {};
374
374
  const rootComponentWithErrorBoundary = /* @__PURE__ */ React__namespace.createElement(ErrorBoundary, { FallbackComponent: fallback }, /* @__PURE__ */ React__namespace.createElement(
375
375
  RawComponent,
376
376
  {
@@ -382,33 +382,36 @@ function createBridgeComponent(bridgeInfo) {
382
382
  propsInfo: { ...propsInfo, ...beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps }
383
383
  }
384
384
  ));
385
- if (bridgeInfo == null ? void 0 : bridgeInfo.render) {
386
- Promise.resolve(
387
- bridgeInfo == null ? void 0 : bridgeInfo.render(rootComponentWithErrorBoundary, dom)
388
- ).then((root) => rootMap.set(info.dom, root));
385
+ if (bridgeInfo.render) {
386
+ await Promise.resolve(
387
+ bridgeInfo.render(rootComponentWithErrorBoundary, dom)
388
+ ).then((root) => rootMap.set(dom, root));
389
389
  } else {
390
- let root = rootMap.get(info.dom);
390
+ let root = rootMap.get(dom);
391
391
  if (!root) {
392
- root = createRoot(info.dom);
393
- rootMap.set(info.dom, root);
392
+ root = createRoot$1(dom);
393
+ rootMap.set(dom, root);
394
+ }
395
+ if ("render" in root) {
396
+ root.render(rootComponentWithErrorBoundary);
394
397
  }
395
- root.render(rootComponentWithErrorBoundary);
396
398
  }
397
399
  ((_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)) || {};
398
400
  },
399
401
  destroy(info) {
400
- var _a, _b, _c;
402
+ var _a2, _b, _c;
403
+ const { dom } = info;
401
404
  context.LoggerInstance.debug(`createBridgeComponent destroy Info`, info);
402
- const root = rootMap.get(info.dom);
405
+ const root = rootMap.get(dom);
403
406
  if (root) {
404
407
  if ("unmount" in root) {
405
408
  root.unmount();
406
409
  } else {
407
410
  ReactDOM.unmountComponentAtNode(root);
408
411
  }
409
- rootMap.delete(info.dom);
412
+ rootMap.delete(dom);
410
413
  }
411
- (_c = (_b = (_a = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.afterBridgeDestroy) == null ? void 0 : _c.emit(info);
414
+ (_c = (_b = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b.afterBridgeDestroy) == null ? void 0 : _c.emit(info);
412
415
  }
413
416
  };
414
417
  };
package/dist/index.d.ts CHANGED
@@ -1,91 +1,116 @@
1
- import { ComponentType } from 'react';
2
1
  import { default as default_2 } from 'react';
3
- import { ErrorInfo } from 'react';
4
- import { PropsWithChildren } from 'react';
5
2
  import * as React_2 from 'react';
6
3
 
7
- export declare function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>): () => {
4
+ export declare function createBridgeComponent<T>({ createRoot, ...bridgeInfo }: ProviderFnParams<T>): () => {
8
5
  render(info: RenderParams): Promise<void>;
9
6
  destroy(info: DestroyParams): void;
10
7
  };
11
8
 
12
- export declare function createRemoteComponent<T, E extends keyof T>(info: LazyRemoteComponentInfo<T, E>): default_2.ForwardRefExoticComponent<default_2.PropsWithoutRef<ProviderParams & ("__BRIDGE_FN__" extends keyof (T[E] extends (...args: any) => any ? ReturnType<T[E]> : never) ? (T[E] extends (...args: any) => any ? ReturnType<T[E]> : never)["__BRIDGE_FN__"] extends (...args: any) => any ? Parameters<(T[E] extends (...args: any) => any ? ReturnType<T[E]> : never)["__BRIDGE_FN__"]>[0] : {} : {})> & default_2.RefAttributes<HTMLDivElement>>;
9
+ export declare function createRemoteComponent<T = Record<string, unknown>, E extends keyof T = keyof T>(info: LazyRemoteComponentInfo<T, E>): default_2.ForwardRefExoticComponent<Omit<RemoteComponentProps<Record<string, unknown>>, "ref"> & default_2.RefAttributes<HTMLDivElement>>;
13
10
 
14
11
  /**
15
- * Creates a root for a container element compatible with both React 16 and 18
12
+ * Options for creating a React root
16
13
  */
17
- declare function createRoot(container: Element | DocumentFragment, options?: CreateRootOptions): Root;
18
-
19
14
  declare interface CreateRootOptions {
20
15
  identifierPrefix?: string;
21
16
  onRecoverableError?: (error: unknown) => void;
22
17
  transitionCallbacks?: unknown;
23
18
  }
24
19
 
25
- declare type DestroyParams = {
20
+ /**
21
+ * Parameters for the destroy function
22
+ */
23
+ export declare interface DestroyParams {
26
24
  moduleName: string;
27
25
  dom: HTMLElement;
28
- };
29
-
30
- declare type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
31
- fallback?: never;
32
- FallbackComponent: ComponentType<FallbackProps>;
33
- fallbackRender?: never;
34
- };
35
-
36
- declare type ErrorBoundarySharedProps = PropsWithChildren<{
37
- onError?: (error: Error, info: ErrorInfo) => void;
38
- onReset?: (details: {
39
- reason: "imperative-api";
40
- args: any[];
41
- } | {
42
- reason: "keys";
43
- prev: any[] | undefined;
44
- next: any[] | undefined;
45
- }) => void;
46
- resetKeys?: any[];
47
- }>;
48
-
49
- declare type FallbackProps = {
50
- error: any;
51
- resetErrorBoundary: (...args: any[]) => void;
52
- };
26
+ }
53
27
 
54
- declare type LazyRemoteComponentInfo<T, E extends keyof T> = {
55
- loader: () => Promise<T>;
56
- loading: default_2.ReactNode;
57
- fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
58
- export?: E;
59
- };
28
+ declare type LazyRemoteComponentInfo<T, E extends keyof T> = RemoteComponentParams<T>;
60
29
 
61
- declare type ProviderFnParams<T> = {
30
+ /**
31
+ * Parameters for the provider function
32
+ */
33
+ declare interface ProviderFnParams<T> {
62
34
  rootComponent: React_2.ComponentType<T>;
63
35
  render?: (App: React_2.ReactElement, id?: HTMLElement | string) => RootType | Promise<RootType>;
64
- };
36
+ createRoot?: (container: Element | DocumentFragment, options?: CreateRootOptions) => Root;
37
+ }
65
38
 
39
+ /**
40
+ * Parameters for the provider function
41
+ */
66
42
  export declare interface ProviderParams {
67
43
  moduleName?: string;
68
44
  basename?: string;
69
45
  memoryRoute?: {
70
46
  entryPath: string;
47
+ initialState?: Record<string, unknown>;
71
48
  };
72
- style?: React.CSSProperties;
49
+ style?: React_2.CSSProperties;
73
50
  className?: string;
74
51
  }
75
52
 
53
+ /**
54
+ * Parameters for the remote component loader
55
+ */
56
+ declare interface RemoteComponentParams<T = Record<string, unknown>, E extends keyof T = keyof T> {
57
+ loader: () => Promise<T>;
58
+ loading: React_2.ReactNode;
59
+ fallback: React_2.ComponentType<{
60
+ error: Error;
61
+ }>;
62
+ export?: E;
63
+ props?: T;
64
+ }
65
+
66
+ /**
67
+ * Parameters for the remote component
68
+ */
69
+ declare interface RemoteComponentProps<T = Record<string, unknown>> {
70
+ props?: T;
71
+ fallback?: React_2.ComponentType<{
72
+ error: Error;
73
+ }>;
74
+ loading?: React_2.ReactNode;
75
+ [key: string]: unknown;
76
+ }
77
+
78
+ /**
79
+ * Parameters for the render function, extending ProviderParams
80
+ */
76
81
  export declare interface RenderFnParams extends ProviderParams {
77
82
  dom: HTMLElement;
83
+ fallback?: React_2.ComponentType<{
84
+ error: Error;
85
+ }>;
86
+ [key: string]: unknown;
78
87
  }
79
88
 
80
- declare type RenderParams = RenderFnParams & {
89
+ /**
90
+ * Parameters for the render function
91
+ */
92
+ export declare interface RenderParams {
93
+ moduleName?: string;
94
+ basename?: string;
95
+ memoryRoute?: {
96
+ entryPath: string;
97
+ initialState?: Record<string, unknown>;
98
+ };
99
+ dom: HTMLElement;
81
100
  [key: string]: unknown;
82
- };
101
+ }
83
102
 
103
+ /**
104
+ * Interface for a React root object
105
+ */
84
106
  declare interface Root {
85
- render(children: React.ReactNode): void;
107
+ render(children: React_2.ReactNode): void;
86
108
  unmount(): void;
87
109
  }
88
110
 
89
- declare type RootType = HTMLElement | ReturnType<typeof createRoot>;
111
+ /**
112
+ * Type for a root element, which can be either an HTMLElement or a React root
113
+ */
114
+ declare type RootType = HTMLElement | Root;
90
115
 
91
116
  export { }
package/dist/index.es.js CHANGED
@@ -1,3 +1,4 @@
1
+ var _a;
1
2
  import * as React from "react";
2
3
  import React__default, { createContext, Component, createElement, forwardRef, useRef, useState, useEffect, useContext } from "react";
3
4
  import { L as LoggerInstance, g as getRootDomDefaultClassName, p as pathJoin, R as RouterContext } from "./context-YcJWgOAv.js";
@@ -121,14 +122,13 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
121
122
  const [initialized, setInitialized] = useState(false);
122
123
  LoggerInstance.debug(`RemoteAppWrapper instance from props >>>`, instance);
123
124
  useEffect(() => {
124
- if (initialized)
125
- return;
125
+ if (initialized) return;
126
126
  const providerReturn = providerInfo();
127
127
  providerInfoRef.current = providerReturn;
128
128
  setInitialized(true);
129
129
  return () => {
130
- var _a, _b, _c, _d, _e, _f, _g, _h;
131
- if ((_a = providerInfoRef.current) == null ? void 0 : _a.destroy) {
130
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
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 }
@@ -157,9 +157,8 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
157
157
  };
158
158
  }, [moduleName]);
159
159
  useEffect(() => {
160
- var _a, _b, _c, _d, _e, _f;
161
- if (!initialized || !providerInfoRef.current)
162
- return;
160
+ var _a2, _b, _c, _d, _e, _f;
161
+ if (!initialized || !providerInfoRef.current) return;
163
162
  let renderProps = {
164
163
  moduleName,
165
164
  dom: rootRef.current,
@@ -169,7 +168,7 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
169
168
  ...resProps
170
169
  };
171
170
  renderDom.current = rootRef.current;
172
- const beforeBridgeRenderRes = ((_c = (_b = (_a = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(renderProps)) || {};
171
+ const beforeBridgeRenderRes = ((_c = (_b = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(renderProps)) || {};
173
172
  renderProps = { ...renderProps, ...beforeBridgeRenderRes.extraProps };
174
173
  providerInfoRef.current.render(renderProps);
175
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);
@@ -179,7 +178,7 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
179
178
  });
180
179
  function withRouterData(WrappedComponent) {
181
180
  const Component2 = forwardRef(function(props, ref) {
182
- var _a;
181
+ var _a2;
183
182
  if (props == null ? void 0 : props.basename) {
184
183
  return /* @__PURE__ */ React__default.createElement(WrappedComponent, { ...props, basename: props.basename, ref });
185
184
  }
@@ -212,7 +211,7 @@ function withRouterData(WrappedComponent) {
212
211
  const match = useRouteMatch == null ? void 0 : useRouteMatch();
213
212
  if (useHistory) {
214
213
  const history = useHistory == null ? void 0 : useHistory();
215
- basename = (_a = history == null ? void 0 : history.createHref) == null ? void 0 : _a.call(history, { pathname: "/" });
214
+ basename = (_a2 = history == null ? void 0 : history.createHref) == null ? void 0 : _a2.call(history, { pathname: "/" });
216
215
  }
217
216
  if (match) {
218
217
  basename = pathJoin(basename, (match == null ? void 0 : match.path) || "/");
@@ -299,13 +298,11 @@ function createLazyRemoteComponent(info) {
299
298
  }
300
299
  function createRemoteComponent(info) {
301
300
  const LazyComponent = createLazyRemoteComponent(info);
302
- return forwardRef(
303
- (props, ref) => {
304
- return /* @__PURE__ */ React__default.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React__default.createElement(React__default.Suspense, { fallback: info.loading }, /* @__PURE__ */ React__default.createElement(LazyComponent, { ...props, ref })));
305
- }
306
- );
301
+ return forwardRef((props, ref) => {
302
+ return /* @__PURE__ */ React__default.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React__default.createElement(React__default.Suspense, { fallback: info.loading }, /* @__PURE__ */ React__default.createElement(LazyComponent, { ...props, ref })));
303
+ });
307
304
  }
308
- const isReact18 = ReactDOM.version.startsWith("18");
305
+ const isReact18 = (_a = ReactDOM.version) == null ? void 0 : _a.startsWith("18");
309
306
  function createRoot(container, options) {
310
307
  if (isReact18) {
311
308
  return ReactDOM.createRoot(container, options);
@@ -319,7 +316,10 @@ function createRoot(container, options) {
319
316
  }
320
317
  };
321
318
  }
322
- function createBridgeComponent(bridgeInfo) {
319
+ function createBridgeComponent({
320
+ createRoot: createRoot$1 = createRoot,
321
+ ...bridgeInfo
322
+ }) {
323
323
  return () => {
324
324
  const rootMap = /* @__PURE__ */ new Map();
325
325
  const instance = federationRuntime.instance;
@@ -341,7 +341,7 @@ function createBridgeComponent(bridgeInfo) {
341
341
  };
342
342
  return {
343
343
  async render(info) {
344
- var _a, _b, _c, _d, _e, _f;
344
+ var _a2, _b, _c, _d, _e, _f;
345
345
  LoggerInstance.debug(`createBridgeComponent render Info`, info);
346
346
  const {
347
347
  moduleName,
@@ -351,7 +351,7 @@ function createBridgeComponent(bridgeInfo) {
351
351
  fallback,
352
352
  ...propsInfo
353
353
  } = info;
354
- const beforeBridgeRenderRes = ((_c = (_b = (_a = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(info)) || {};
354
+ const beforeBridgeRenderRes = ((_c = (_b = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b.beforeBridgeRender) == null ? void 0 : _c.emit(info)) || {};
355
355
  const rootComponentWithErrorBoundary = /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: fallback }, /* @__PURE__ */ React.createElement(
356
356
  RawComponent,
357
357
  {
@@ -363,33 +363,36 @@ function createBridgeComponent(bridgeInfo) {
363
363
  propsInfo: { ...propsInfo, ...beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps }
364
364
  }
365
365
  ));
366
- if (bridgeInfo == null ? void 0 : bridgeInfo.render) {
367
- Promise.resolve(
368
- bridgeInfo == null ? void 0 : bridgeInfo.render(rootComponentWithErrorBoundary, dom)
369
- ).then((root) => rootMap.set(info.dom, root));
366
+ if (bridgeInfo.render) {
367
+ await Promise.resolve(
368
+ bridgeInfo.render(rootComponentWithErrorBoundary, dom)
369
+ ).then((root) => rootMap.set(dom, root));
370
370
  } else {
371
- let root = rootMap.get(info.dom);
371
+ let root = rootMap.get(dom);
372
372
  if (!root) {
373
- root = createRoot(info.dom);
374
- rootMap.set(info.dom, root);
373
+ root = createRoot$1(dom);
374
+ rootMap.set(dom, root);
375
+ }
376
+ if ("render" in root) {
377
+ root.render(rootComponentWithErrorBoundary);
375
378
  }
376
- root.render(rootComponentWithErrorBoundary);
377
379
  }
378
380
  ((_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)) || {};
379
381
  },
380
382
  destroy(info) {
381
- var _a, _b, _c;
383
+ var _a2, _b, _c;
384
+ const { dom } = info;
382
385
  LoggerInstance.debug(`createBridgeComponent destroy Info`, info);
383
- const root = rootMap.get(info.dom);
386
+ const root = rootMap.get(dom);
384
387
  if (root) {
385
388
  if ("unmount" in root) {
386
389
  root.unmount();
387
390
  } else {
388
391
  ReactDOM.unmountComponentAtNode(root);
389
392
  }
390
- rootMap.delete(info.dom);
393
+ rootMap.delete(dom);
391
394
  }
392
- (_c = (_b = (_a = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.afterBridgeDestroy) == null ? void 0 : _c.emit(info);
395
+ (_c = (_b = (_a2 = instance == null ? void 0 : instance.bridgeHook) == null ? void 0 : _a2.lifecycle) == null ? void 0 : _b.afterBridgeDestroy) == null ? void 0 : _c.emit(info);
393
396
  }
394
397
  };
395
398
  };
@@ -48,9 +48,8 @@ function WraperRouter(props) {
48
48
  }
49
49
  exports.BrowserRouter = WraperRouter;
50
50
  Object.keys(ReactRouterDom).forEach((k) => {
51
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k))
52
- Object.defineProperty(exports, k, {
53
- enumerable: true,
54
- get: () => ReactRouterDom[k]
55
- });
51
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
52
+ enumerable: true,
53
+ get: () => ReactRouterDom[k]
54
+ });
56
55
  });
@@ -77,9 +77,8 @@ function WraperRouterProvider(props) {
77
77
  exports.BrowserRouter = WraperRouter;
78
78
  exports.RouterProvider = WraperRouterProvider;
79
79
  Object.keys(ReactRouterDom).forEach((k) => {
80
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k))
81
- Object.defineProperty(exports, k, {
82
- enumerable: true,
83
- get: () => ReactRouterDom[k]
84
- });
80
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
81
+ enumerable: true,
82
+ get: () => ReactRouterDom[k]
83
+ });
85
84
  });
@@ -75,9 +75,8 @@ function WrapperRouterProvider(props) {
75
75
  exports.BrowserRouter = WrapperRouter;
76
76
  exports.RouterProvider = WrapperRouterProvider;
77
77
  Object.keys(ReactRouterDom).forEach((k) => {
78
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k))
79
- Object.defineProperty(exports, k, {
80
- enumerable: true,
81
- get: () => ReactRouterDom[k]
82
- });
78
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
79
+ enumerable: true,
80
+ get: () => ReactRouterDom[k]
81
+ });
83
82
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/bridge-react",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -46,8 +46,8 @@
46
46
  "dependencies": {
47
47
  "@loadable/component": "^5.16.4",
48
48
  "react-error-boundary": "^4.1.2",
49
- "@module-federation/bridge-shared": "0.10.0",
50
- "@module-federation/sdk": "0.10.0"
49
+ "@module-federation/bridge-shared": "0.11.1",
50
+ "@module-federation/sdk": "0.11.1"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "react": ">=16.9.0",
@@ -66,9 +66,9 @@
66
66
  "react-dom": "18.3.1",
67
67
  "react-router-dom": "6.22.3",
68
68
  "typescript": "^5.2.2",
69
- "vite": "^5.2.14",
69
+ "vite": "^5.4.12",
70
70
  "vite-plugin-dts": "^4.3.0",
71
- "@module-federation/runtime": "0.10.0"
71
+ "@module-federation/runtime": "0.11.1"
72
72
  },
73
73
  "scripts": {
74
74
  "dev": "vite",
package/src/index.ts CHANGED
@@ -3,4 +3,6 @@ export { createBridgeComponent } from './provider/create';
3
3
  export type {
4
4
  ProviderParams,
5
5
  RenderFnParams,
6
- } from '@module-federation/bridge-shared';
6
+ DestroyParams,
7
+ RenderParams,
8
+ } from './types';
@@ -1,17 +1,8 @@
1
1
  import ReactDOM from 'react-dom';
2
+ import { CreateRootOptions, Root } from '../types';
2
3
 
3
- 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
- const isReact18 = ReactDOM.version.startsWith('18');
4
+ // ReactDOM.version is only available in React 16.13.0 and later
5
+ const isReact18 = ReactDOM.version?.startsWith('18');
15
6
 
16
7
  /**
17
8
  * Creates a root for a container element compatible with both React 16 and 18
@@ -29,7 +20,6 @@ export function createRoot(
29
20
  // For React 16/17, simulate the new root API using render/unmountComponentAtNode
30
21
  return {
31
22
  render(children: React.ReactNode) {
32
- // @ts-ignore - React 17's render method is deprecated but still functional
33
23
  ReactDOM.render(children, container);
34
24
  },
35
25
  unmount() {
@@ -52,11 +42,16 @@ export function hydrateRoot(
52
42
  return (ReactDOM as any).hydrateRoot(container, initialChildren, options);
53
43
  }
54
44
 
55
- // For React 16/17, simulate the new root API using hydrate
45
+ // For React 16/17, simulate the new root API using hydrate/unmountComponentAtNode
56
46
  return {
57
47
  render(children: React.ReactNode) {
58
- // @ts-ignore - React 17's hydrate method is deprecated but still functional
59
- ReactDOM.hydrate(children, container);
48
+ // For the initial render, use hydrate
49
+ if (children === initialChildren) {
50
+ ReactDOM.hydrate(children, container);
51
+ } else {
52
+ // For subsequent renders, use regular render
53
+ ReactDOM.render(children, container);
54
+ }
60
55
  },
61
56
  unmount() {
62
57
  ReactDOM.unmountComponentAtNode(container);
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
- import { ProviderParams } from '@module-federation/bridge-shared';
2
+ import { ProviderParams } from '../types';
3
3
 
4
4
  export const RouterContext = React.createContext<ProviderParams | null>(null);
@@ -2,32 +2,21 @@ import * as React from 'react';
2
2
  import ReactDOM from 'react-dom';
3
3
  import type {
4
4
  ProviderParams,
5
- RenderFnParams,
6
- } from '@module-federation/bridge-shared';
5
+ ProviderFnParams,
6
+ RootType,
7
+ DestroyParams,
8
+ RenderParams,
9
+ } from '../types';
7
10
  import { ErrorBoundary } from 'react-error-boundary';
8
11
  import { RouterContext } from './context';
9
12
  import { LoggerInstance } from '../utils';
10
13
  import { federationRuntime } from './plugin';
11
- import { createRoot } from './compat';
14
+ import { createRoot as defaultCreateRoot } from './compat';
12
15
 
13
- type RenderParams = RenderFnParams & {
14
- [key: string]: unknown;
15
- };
16
- type DestroyParams = {
17
- moduleName: string;
18
- dom: HTMLElement;
19
- };
20
- type RootType = HTMLElement | ReturnType<typeof createRoot>;
21
-
22
- export type ProviderFnParams<T> = {
23
- rootComponent: React.ComponentType<T>;
24
- render?: (
25
- App: React.ReactElement,
26
- id?: HTMLElement | string,
27
- ) => RootType | Promise<RootType>;
28
- };
29
-
30
- export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
16
+ export function createBridgeComponent<T>({
17
+ createRoot = defaultCreateRoot,
18
+ ...bridgeInfo
19
+ }: ProviderFnParams<T>) {
31
20
  return () => {
32
21
  const rootMap = new Map<any, RootType>();
33
22
  const instance = federationRuntime.instance;
@@ -80,34 +69,37 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
80
69
  </ErrorBoundary>
81
70
  );
82
71
 
83
- if (bridgeInfo?.render) {
84
- // in case bridgeInfo?.render is an async function, resolve this to promise
85
- Promise.resolve(
86
- bridgeInfo?.render(rootComponentWithErrorBoundary, dom),
87
- ).then((root: RootType) => rootMap.set(info.dom, root));
72
+ if (bridgeInfo.render) {
73
+ await Promise.resolve(
74
+ bridgeInfo.render(rootComponentWithErrorBoundary, dom),
75
+ ).then((root: RootType) => rootMap.set(dom, root));
88
76
  } else {
89
- let root = rootMap.get(info.dom);
77
+ let root = rootMap.get(dom);
90
78
  // do not call createRoot multiple times
91
79
  if (!root) {
92
- root = createRoot(info.dom);
93
- rootMap.set(info.dom, root);
80
+ root = createRoot(dom);
81
+ rootMap.set(dom, root);
82
+ }
83
+
84
+ if ('render' in root) {
85
+ root.render(rootComponentWithErrorBoundary);
94
86
  }
95
- root.render(rootComponentWithErrorBoundary);
96
87
  }
97
88
 
98
89
  instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info) || {};
99
90
  },
100
91
 
101
92
  destroy(info: DestroyParams) {
93
+ const { dom } = info;
102
94
  LoggerInstance.debug(`createBridgeComponent destroy Info`, info);
103
- const root = rootMap.get(info.dom);
95
+ const root = rootMap.get(dom);
104
96
  if (root) {
105
97
  if ('unmount' in root) {
106
98
  root.unmount();
107
99
  } else {
108
100
  ReactDOM.unmountComponentAtNode(root as HTMLElement);
109
101
  }
110
- rootMap.delete(info.dom);
102
+ rootMap.delete(dom);
111
103
  }
112
104
  instance?.bridgeHook?.lifecycle?.afterBridgeDestroy?.emit(info);
113
105
  },
@@ -6,38 +6,13 @@ import React, {
6
6
  forwardRef,
7
7
  } from 'react';
8
8
  import * as ReactRouterDOM from 'react-router-dom';
9
- import type { ProviderParams } from '@module-federation/bridge-shared';
10
9
  import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
11
- import { ErrorBoundaryPropsWithComponent } from 'react-error-boundary';
12
10
  import { LoggerInstance, pathJoin, getRootDomDefaultClassName } from '../utils';
13
11
  import { federationRuntime } from '../provider/plugin';
14
-
15
- declare const __APP_VERSION__: string;
16
- export interface RenderFnParams extends ProviderParams {
17
- dom?: any;
18
- fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
19
- }
20
-
21
- interface RemoteModule {
22
- provider: () => {
23
- render: (
24
- info: ProviderParams & {
25
- dom: any;
26
- },
27
- ) => void;
28
- destroy: (info: { dom: any }) => void;
29
- };
30
- }
31
-
32
- interface RemoteAppParams {
33
- moduleName: string;
34
- providerInfo: NonNullable<RemoteModule['provider']>;
35
- exportName: string | number | symbol;
36
- fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
37
- }
12
+ import { RemoteComponentProps, RemoteAppParams } from '../types';
38
13
 
39
14
  const RemoteAppWrapper = forwardRef(function (
40
- props: RemoteAppParams & RenderFnParams,
15
+ props: RemoteAppParams & RemoteComponentProps,
41
16
  ref,
42
17
  ) {
43
18
  const {
@@ -1,33 +1,19 @@
1
1
  import React, { forwardRef } from 'react';
2
- import {
3
- ErrorBoundary,
4
- ErrorBoundaryPropsWithComponent,
5
- } from 'react-error-boundary';
2
+ import { ErrorBoundary } from 'react-error-boundary';
6
3
  import { LoggerInstance } from '../utils';
7
4
  import RemoteApp from './component';
8
- import type { ProviderParams } from '@module-federation/bridge-shared';
9
-
10
- export interface RenderFnParams extends ProviderParams {
11
- dom?: any;
12
- }
13
-
14
- interface RemoteModule {
15
- provider: () => {
16
- render: (info: RenderFnParams) => void;
17
- destroy: (info: { dom: any }) => void;
18
- };
19
- }
5
+ import {
6
+ RemoteComponentParams,
7
+ RemoteComponentProps,
8
+ RemoteModule,
9
+ } from '../types';
20
10
 
21
- type LazyRemoteComponentInfo<T, E extends keyof T> = {
22
- loader: () => Promise<T>;
23
- loading: React.ReactNode;
24
- fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
25
- export?: E;
26
- };
11
+ type LazyRemoteComponentInfo<T, E extends keyof T> = RemoteComponentParams<T>;
27
12
 
28
- function createLazyRemoteComponent<T, E extends keyof T>(
29
- info: LazyRemoteComponentInfo<T, E>,
30
- ) {
13
+ function createLazyRemoteComponent<
14
+ T = Record<string, unknown>,
15
+ E extends keyof T = keyof T,
16
+ >(info: LazyRemoteComponentInfo<T, E>) {
31
17
  const exportName = info?.export || 'default';
32
18
  return React.lazy(async () => {
33
19
  LoggerInstance.debug(`createRemoteComponent LazyComponent create >>>`, {
@@ -49,10 +35,7 @@ function createLazyRemoteComponent<T, E extends keyof T>(
49
35
  if (exportName in m && typeof exportFn === 'function') {
50
36
  const RemoteAppComponent = forwardRef<
51
37
  HTMLDivElement,
52
- {
53
- basename?: ProviderParams['basename'];
54
- memoryRoute?: ProviderParams['memoryRoute'];
55
- }
38
+ RemoteComponentProps
56
39
  >((props, ref) => {
57
40
  return (
58
41
  <RemoteApp
@@ -87,29 +70,18 @@ function createLazyRemoteComponent<T, E extends keyof T>(
87
70
  });
88
71
  }
89
72
 
90
- export function createRemoteComponent<T, E extends keyof T>(
91
- info: LazyRemoteComponentInfo<T, E>,
92
- ) {
93
- type ExportType = T[E] extends (...args: any) => any
94
- ? ReturnType<T[E]>
95
- : never;
96
-
97
- type RawComponentType = '__BRIDGE_FN__' extends keyof ExportType
98
- ? ExportType['__BRIDGE_FN__'] extends (...args: any) => any
99
- ? Parameters<ExportType['__BRIDGE_FN__']>[0]
100
- : {}
101
- : {};
102
-
73
+ export function createRemoteComponent<
74
+ T = Record<string, unknown>,
75
+ E extends keyof T = keyof T,
76
+ >(info: LazyRemoteComponentInfo<T, E>) {
103
77
  const LazyComponent = createLazyRemoteComponent(info);
104
- return forwardRef<HTMLDivElement, ProviderParams & RawComponentType>(
105
- (props, ref) => {
106
- return (
107
- <ErrorBoundary FallbackComponent={info.fallback}>
108
- <React.Suspense fallback={info.loading}>
109
- <LazyComponent {...props} ref={ref} />
110
- </React.Suspense>
111
- </ErrorBoundary>
112
- );
113
- },
114
- );
78
+ return forwardRef<HTMLDivElement, RemoteComponentProps>((props, ref) => {
79
+ return (
80
+ <ErrorBoundary FallbackComponent={info.fallback}>
81
+ <React.Suspense fallback={info.loading}>
82
+ <LazyComponent {...props} ref={ref} />
83
+ </React.Suspense>
84
+ </ErrorBoundary>
85
+ );
86
+ });
115
87
  }
package/src/types.ts ADDED
@@ -0,0 +1,128 @@
1
+ import * as React from 'react';
2
+ import { ErrorBoundaryPropsWithComponent } from 'react-error-boundary';
3
+
4
+ /**
5
+ * Options for creating a React root
6
+ */
7
+ export interface CreateRootOptions {
8
+ identifierPrefix?: string;
9
+ onRecoverableError?: (error: unknown) => void;
10
+ transitionCallbacks?: unknown;
11
+ }
12
+
13
+ /**
14
+ * Interface for a React root object
15
+ */
16
+ export interface Root {
17
+ render(children: React.ReactNode): void;
18
+ unmount(): void;
19
+ }
20
+
21
+ /**
22
+ * Type for a root element, which can be either an HTMLElement or a React root
23
+ */
24
+ export type RootType = HTMLElement | Root;
25
+
26
+ /**
27
+ * Parameters for the render function
28
+ */
29
+ export interface RenderParams {
30
+ moduleName?: string;
31
+ basename?: string;
32
+ memoryRoute?: {
33
+ entryPath: string;
34
+ initialState?: Record<string, unknown>;
35
+ };
36
+ dom: HTMLElement;
37
+ [key: string]: unknown;
38
+ }
39
+
40
+ /**
41
+ * Parameters for the destroy function
42
+ */
43
+ export interface DestroyParams {
44
+ moduleName: string;
45
+ dom: HTMLElement;
46
+ }
47
+
48
+ /**
49
+ * Parameters for the provider function
50
+ */
51
+ export interface ProviderParams {
52
+ moduleName?: string;
53
+ basename?: string;
54
+ memoryRoute?: {
55
+ entryPath: string;
56
+ initialState?: Record<string, unknown>;
57
+ };
58
+ style?: React.CSSProperties;
59
+ className?: string;
60
+ }
61
+
62
+ /**
63
+ * Parameters for the render function, extending ProviderParams
64
+ */
65
+ export interface RenderFnParams extends ProviderParams {
66
+ dom: HTMLElement;
67
+ fallback?: React.ComponentType<{ error: Error }>;
68
+ [key: string]: unknown;
69
+ }
70
+
71
+ /**
72
+ * Parameters for the provider function
73
+ */
74
+ export interface ProviderFnParams<T> {
75
+ rootComponent: React.ComponentType<T>;
76
+ render?: (
77
+ App: React.ReactElement,
78
+ id?: HTMLElement | string,
79
+ ) => RootType | Promise<RootType>;
80
+ createRoot?: (
81
+ container: Element | DocumentFragment,
82
+ options?: CreateRootOptions,
83
+ ) => Root;
84
+ }
85
+
86
+ /**
87
+ * Parameters for the remote component
88
+ */
89
+ export interface RemoteComponentProps<T = Record<string, unknown>> {
90
+ props?: T;
91
+ fallback?: React.ComponentType<{ error: Error }>;
92
+ loading?: React.ReactNode;
93
+ [key: string]: unknown;
94
+ }
95
+
96
+ /**
97
+ * Parameters for the remote component loader
98
+ */
99
+ export interface RemoteComponentParams<
100
+ T = Record<string, unknown>,
101
+ E extends keyof T = keyof T,
102
+ > {
103
+ loader: () => Promise<T>;
104
+ loading: React.ReactNode;
105
+ fallback: React.ComponentType<{ error: Error }>;
106
+ export?: E;
107
+ props?: T;
108
+ }
109
+
110
+ /**
111
+ * Interface for a remote module provider
112
+ */
113
+ export interface RemoteModule {
114
+ provider: () => {
115
+ render: (info: RenderFnParams) => void;
116
+ destroy: (info: { dom: any }) => void;
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Parameters for a remote app component
122
+ */
123
+ export interface RemoteAppParams extends ProviderParams {
124
+ moduleName: string;
125
+ providerInfo: NonNullable<RemoteModule['provider']>;
126
+ exportName: string | number | symbol;
127
+ fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
128
+ }