@module-federation/bridge-react 0.0.0-next-20240620060503 → 0.2.0

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,7 +1,12 @@
1
1
  # @module-federation/bridge-react
2
2
 
3
- ## 0.0.0-next-20240620060503
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d2ab821: feat(bridge): Supports exporting and loading of application-level modules (with routing), currently supports react and vue3
4
8
 
5
9
  ### Patch Changes
6
10
 
7
- - @module-federation/bridge-shared@0.0.0-next-20240620060503
11
+ - Updated dependencies [d2ab821]
12
+ - @module-federation/bridge-shared@0.2.0
@@ -51,15 +51,17 @@ describe('bridge', () => {
51
51
  const BridgeComponent = createBridgeComponent({
52
52
  rootComponent: Component,
53
53
  });
54
- const RemoteComponent = createRemoteComponent(async () => {
55
- return {
56
- default: BridgeComponent,
57
- };
54
+ const RemoteComponent = createRemoteComponent({
55
+ loader: async () => {
56
+ return {
57
+ default: BridgeComponent,
58
+ };
59
+ },
60
+ fallback: () => <div></div>,
61
+ loading: <div>loading</div>,
58
62
  });
59
63
 
60
- const { container } = render(
61
- <RemoteComponent fallback={<div>loading</div>} msg={'hello world'} />,
62
- );
64
+ const { container } = render(<RemoteComponent msg={'hello world'} />);
63
65
  expect(getHtml(container)).toMatch('loading');
64
66
 
65
67
  await sleep(200);
package/dist/index.cjs.js CHANGED
@@ -22,6 +22,101 @@ function _interopNamespaceDefault(e) {
22
22
  }
23
23
  const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
24
24
  const ReactRouterDOM__namespace = /* @__PURE__ */ _interopNamespaceDefault(ReactRouterDOM);
25
+ const ErrorBoundaryContext = React.createContext(null);
26
+ const initialState = {
27
+ didCatch: false,
28
+ error: null
29
+ };
30
+ class ErrorBoundary extends React.Component {
31
+ constructor(props) {
32
+ super(props);
33
+ this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
34
+ this.state = initialState;
35
+ }
36
+ static getDerivedStateFromError(error) {
37
+ return {
38
+ didCatch: true,
39
+ error
40
+ };
41
+ }
42
+ resetErrorBoundary() {
43
+ const {
44
+ error
45
+ } = this.state;
46
+ if (error !== null) {
47
+ var _this$props$onReset, _this$props;
48
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
49
+ args[_key] = arguments[_key];
50
+ }
51
+ (_this$props$onReset = (_this$props = this.props).onReset) === null || _this$props$onReset === void 0 ? void 0 : _this$props$onReset.call(_this$props, {
52
+ args,
53
+ reason: "imperative-api"
54
+ });
55
+ this.setState(initialState);
56
+ }
57
+ }
58
+ componentDidCatch(error, info) {
59
+ var _this$props$onError, _this$props2;
60
+ (_this$props$onError = (_this$props2 = this.props).onError) === null || _this$props$onError === void 0 ? void 0 : _this$props$onError.call(_this$props2, error, info);
61
+ }
62
+ componentDidUpdate(prevProps, prevState) {
63
+ const {
64
+ didCatch
65
+ } = this.state;
66
+ const {
67
+ resetKeys
68
+ } = this.props;
69
+ if (didCatch && prevState.error !== null && hasArrayChanged(prevProps.resetKeys, resetKeys)) {
70
+ var _this$props$onReset2, _this$props3;
71
+ (_this$props$onReset2 = (_this$props3 = this.props).onReset) === null || _this$props$onReset2 === void 0 ? void 0 : _this$props$onReset2.call(_this$props3, {
72
+ next: resetKeys,
73
+ prev: prevProps.resetKeys,
74
+ reason: "keys"
75
+ });
76
+ this.setState(initialState);
77
+ }
78
+ }
79
+ render() {
80
+ const {
81
+ children,
82
+ fallbackRender,
83
+ FallbackComponent,
84
+ fallback
85
+ } = this.props;
86
+ const {
87
+ didCatch,
88
+ error
89
+ } = this.state;
90
+ let childToRender = children;
91
+ if (didCatch) {
92
+ const props = {
93
+ error,
94
+ resetErrorBoundary: this.resetErrorBoundary
95
+ };
96
+ if (typeof fallbackRender === "function") {
97
+ childToRender = fallbackRender(props);
98
+ } else if (FallbackComponent) {
99
+ childToRender = React.createElement(FallbackComponent, props);
100
+ } else if (fallback === null || React.isValidElement(fallback)) {
101
+ childToRender = fallback;
102
+ } else {
103
+ throw error;
104
+ }
105
+ }
106
+ return React.createElement(ErrorBoundaryContext.Provider, {
107
+ value: {
108
+ didCatch,
109
+ error,
110
+ resetErrorBoundary: this.resetErrorBoundary
111
+ }
112
+ }, childToRender);
113
+ }
114
+ }
115
+ function hasArrayChanged() {
116
+ let a = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : [];
117
+ let b = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : [];
118
+ return a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]));
119
+ }
25
120
  const RemoteApp = ({
26
121
  name,
27
122
  memoryRoute,
@@ -83,8 +178,8 @@ const RemoteApp = ({
83
178
  }, []);
84
179
  return /* @__PURE__ */ React.createElement("div", { ref: rootRef });
85
180
  };
86
- RemoteApp["__APP_VERSION__"] = "0.0.1";
87
- function createRemoteComponent(lazyComponent, info) {
181
+ RemoteApp["__APP_VERSION__"] = "0.2.0";
182
+ function createRemoteComponent(info) {
88
183
  return (props) => {
89
184
  var _a;
90
185
  const exportName = (info == null ? void 0 : info.export) || "default";
@@ -131,37 +226,50 @@ function createRemoteComponent(lazyComponent, info) {
131
226
  return React.lazy(async () => {
132
227
  context.LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
133
228
  basename,
134
- lazyComponent,
229
+ lazyComponent: info.loader,
135
230
  exportName,
136
231
  props,
137
232
  routerContextVal
138
233
  });
139
- const m2 = await lazyComponent();
140
- const moduleName = m2 && m2[Symbol.for("mf_module_id")];
141
- context.LoggerInstance.log(
142
- `createRemoteComponent LazyComponent loadRemote info >>>`,
143
- { basename, name: moduleName, module: m2, exportName, props }
144
- );
145
- const exportFn = m2[exportName];
146
- if (exportName in m2 && typeof exportFn === "function") {
147
- return {
148
- default: () => /* @__PURE__ */ React.createElement(
149
- RemoteApp,
150
- {
151
- name: moduleName,
152
- dispathPopstate: enableDispathPopstate,
153
- ...info,
154
- ...props,
155
- providerInfo: exportFn,
156
- basename
157
- }
158
- )
159
- };
234
+ try {
235
+ const m2 = await info.loader();
236
+ const moduleName = m2 && m2[Symbol.for("mf_module_id")];
237
+ context.LoggerInstance.log(
238
+ `createRemoteComponent LazyComponent loadRemote info >>>`,
239
+ { basename, name: moduleName, module: m2, exportName, props }
240
+ );
241
+ const exportFn = m2[exportName];
242
+ if (exportName in m2 && typeof exportFn === "function") {
243
+ return {
244
+ default: () => /* @__PURE__ */ React.createElement(
245
+ RemoteApp,
246
+ {
247
+ name: moduleName,
248
+ dispathPopstate: enableDispathPopstate,
249
+ ...info,
250
+ ...props,
251
+ providerInfo: exportFn,
252
+ basename
253
+ }
254
+ )
255
+ };
256
+ } else {
257
+ context.LoggerInstance.log(
258
+ `createRemoteComponent LazyComponent module not found >>>`,
259
+ { basename, name: moduleName, module: m2, exportName, props }
260
+ );
261
+ throw Error(
262
+ `Make sure that ${moduleName} has the correct export when export is ${String(
263
+ exportName
264
+ )}`
265
+ );
266
+ }
267
+ } catch (error) {
268
+ throw error;
160
269
  }
161
- throw Error("module not found");
162
270
  });
163
271
  }, [exportName, basename, props.memoryRoute]);
164
- return /* @__PURE__ */ React.createElement(React.Suspense, { fallback: props.fallback }, /* @__PURE__ */ React.createElement(LazyComponent, null));
272
+ return /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React.createElement(React.Suspense, { fallback: info.loading }, /* @__PURE__ */ React.createElement(LazyComponent, null)));
165
273
  };
166
274
  }
167
275
  var client = {};
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
+ import { ComponentType } from 'react';
1
2
  import { default as default_2 } from 'react';
3
+ import { ErrorInfo } from 'react';
4
+ import { PropsWithChildren } from 'react';
2
5
  import * as React_2 from 'react';
3
- import { ReactNode } from 'react';
4
6
 
5
7
  export declare function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>): () => {
6
8
  render(info: RenderFnParams & any): void;
@@ -11,14 +13,40 @@ export declare function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>
11
13
  __BRIDGE_FN__: (_args: T) => void;
12
14
  };
13
15
 
14
- export declare function createRemoteComponent<T, E extends keyof T>(lazyComponent: () => Promise<T>, info?: {
16
+ export declare function createRemoteComponent<T, E extends keyof T>(info: {
17
+ loader: () => Promise<T>;
18
+ loading: default_2.ReactNode;
19
+ fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
15
20
  export?: E;
16
21
  }): (props: {
17
- basename?: ProviderParams['basename'];
18
- memoryRoute?: ProviderParams['memoryRoute'];
19
- fallback: ReactNode;
22
+ basename?: ProviderParams["basename"];
23
+ memoryRoute?: ProviderParams["memoryRoute"];
20
24
  } & ("__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.JSX.Element;
21
25
 
26
+ declare type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
27
+ fallback?: never;
28
+ FallbackComponent: ComponentType<FallbackProps>;
29
+ fallbackRender?: never;
30
+ };
31
+
32
+ declare type ErrorBoundarySharedProps = PropsWithChildren<{
33
+ onError?: (error: Error, info: ErrorInfo) => void;
34
+ onReset?: (details: {
35
+ reason: "imperative-api";
36
+ args: any[];
37
+ } | {
38
+ reason: "keys";
39
+ prev: any[] | undefined;
40
+ next: any[] | undefined;
41
+ }) => void;
42
+ resetKeys?: any[];
43
+ }>;
44
+
45
+ declare type FallbackProps = {
46
+ error: any;
47
+ resetErrorBoundary: (...args: any[]) => void;
48
+ };
49
+
22
50
  declare type ProviderFnParams<T> = {
23
51
  rootComponent: React_2.ComponentType<T>;
24
52
  };
package/dist/index.es.js CHANGED
@@ -1,8 +1,103 @@
1
1
  import * as React from "react";
2
- import React__default, { useContext, useMemo, useRef, useState, useEffect } from "react";
2
+ import React__default, { createContext, Component, createElement, isValidElement, useContext, useMemo, useRef, useState, useEffect } from "react";
3
3
  import * as ReactRouterDOM from "react-router-dom";
4
4
  import { p as pathJoin, L as LoggerInstance, f, a as atLeastReact18, R as RouterContext } from "./context-Bw2PEwa6.js";
5
5
  import ReactDOM from "react-dom";
6
+ const ErrorBoundaryContext = createContext(null);
7
+ const initialState = {
8
+ didCatch: false,
9
+ error: null
10
+ };
11
+ class ErrorBoundary extends Component {
12
+ constructor(props) {
13
+ super(props);
14
+ this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
15
+ this.state = initialState;
16
+ }
17
+ static getDerivedStateFromError(error) {
18
+ return {
19
+ didCatch: true,
20
+ error
21
+ };
22
+ }
23
+ resetErrorBoundary() {
24
+ const {
25
+ error
26
+ } = this.state;
27
+ if (error !== null) {
28
+ var _this$props$onReset, _this$props;
29
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
30
+ args[_key] = arguments[_key];
31
+ }
32
+ (_this$props$onReset = (_this$props = this.props).onReset) === null || _this$props$onReset === void 0 ? void 0 : _this$props$onReset.call(_this$props, {
33
+ args,
34
+ reason: "imperative-api"
35
+ });
36
+ this.setState(initialState);
37
+ }
38
+ }
39
+ componentDidCatch(error, info) {
40
+ var _this$props$onError, _this$props2;
41
+ (_this$props$onError = (_this$props2 = this.props).onError) === null || _this$props$onError === void 0 ? void 0 : _this$props$onError.call(_this$props2, error, info);
42
+ }
43
+ componentDidUpdate(prevProps, prevState) {
44
+ const {
45
+ didCatch
46
+ } = this.state;
47
+ const {
48
+ resetKeys
49
+ } = this.props;
50
+ if (didCatch && prevState.error !== null && hasArrayChanged(prevProps.resetKeys, resetKeys)) {
51
+ var _this$props$onReset2, _this$props3;
52
+ (_this$props$onReset2 = (_this$props3 = this.props).onReset) === null || _this$props$onReset2 === void 0 ? void 0 : _this$props$onReset2.call(_this$props3, {
53
+ next: resetKeys,
54
+ prev: prevProps.resetKeys,
55
+ reason: "keys"
56
+ });
57
+ this.setState(initialState);
58
+ }
59
+ }
60
+ render() {
61
+ const {
62
+ children,
63
+ fallbackRender,
64
+ FallbackComponent,
65
+ fallback
66
+ } = this.props;
67
+ const {
68
+ didCatch,
69
+ error
70
+ } = this.state;
71
+ let childToRender = children;
72
+ if (didCatch) {
73
+ const props = {
74
+ error,
75
+ resetErrorBoundary: this.resetErrorBoundary
76
+ };
77
+ if (typeof fallbackRender === "function") {
78
+ childToRender = fallbackRender(props);
79
+ } else if (FallbackComponent) {
80
+ childToRender = createElement(FallbackComponent, props);
81
+ } else if (fallback === null || isValidElement(fallback)) {
82
+ childToRender = fallback;
83
+ } else {
84
+ throw error;
85
+ }
86
+ }
87
+ return createElement(ErrorBoundaryContext.Provider, {
88
+ value: {
89
+ didCatch,
90
+ error,
91
+ resetErrorBoundary: this.resetErrorBoundary
92
+ }
93
+ }, childToRender);
94
+ }
95
+ }
96
+ function hasArrayChanged() {
97
+ let a = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : [];
98
+ let b = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : [];
99
+ return a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]));
100
+ }
6
101
  const RemoteApp = ({
7
102
  name,
8
103
  memoryRoute,
@@ -64,8 +159,8 @@ const RemoteApp = ({
64
159
  }, []);
65
160
  return /* @__PURE__ */ React__default.createElement("div", { ref: rootRef });
66
161
  };
67
- RemoteApp["__APP_VERSION__"] = "0.0.1";
68
- function createRemoteComponent(lazyComponent, info) {
162
+ RemoteApp["__APP_VERSION__"] = "0.2.0";
163
+ function createRemoteComponent(info) {
69
164
  return (props) => {
70
165
  var _a;
71
166
  const exportName = (info == null ? void 0 : info.export) || "default";
@@ -112,37 +207,50 @@ function createRemoteComponent(lazyComponent, info) {
112
207
  return React__default.lazy(async () => {
113
208
  LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
114
209
  basename,
115
- lazyComponent,
210
+ lazyComponent: info.loader,
116
211
  exportName,
117
212
  props,
118
213
  routerContextVal
119
214
  });
120
- const m2 = await lazyComponent();
121
- const moduleName = m2 && m2[Symbol.for("mf_module_id")];
122
- LoggerInstance.log(
123
- `createRemoteComponent LazyComponent loadRemote info >>>`,
124
- { basename, name: moduleName, module: m2, exportName, props }
125
- );
126
- const exportFn = m2[exportName];
127
- if (exportName in m2 && typeof exportFn === "function") {
128
- return {
129
- default: () => /* @__PURE__ */ React__default.createElement(
130
- RemoteApp,
131
- {
132
- name: moduleName,
133
- dispathPopstate: enableDispathPopstate,
134
- ...info,
135
- ...props,
136
- providerInfo: exportFn,
137
- basename
138
- }
139
- )
140
- };
215
+ try {
216
+ const m2 = await info.loader();
217
+ const moduleName = m2 && m2[Symbol.for("mf_module_id")];
218
+ LoggerInstance.log(
219
+ `createRemoteComponent LazyComponent loadRemote info >>>`,
220
+ { basename, name: moduleName, module: m2, exportName, props }
221
+ );
222
+ const exportFn = m2[exportName];
223
+ if (exportName in m2 && typeof exportFn === "function") {
224
+ return {
225
+ default: () => /* @__PURE__ */ React__default.createElement(
226
+ RemoteApp,
227
+ {
228
+ name: moduleName,
229
+ dispathPopstate: enableDispathPopstate,
230
+ ...info,
231
+ ...props,
232
+ providerInfo: exportFn,
233
+ basename
234
+ }
235
+ )
236
+ };
237
+ } else {
238
+ LoggerInstance.log(
239
+ `createRemoteComponent LazyComponent module not found >>>`,
240
+ { basename, name: moduleName, module: m2, exportName, props }
241
+ );
242
+ throw Error(
243
+ `Make sure that ${moduleName} has the correct export when export is ${String(
244
+ exportName
245
+ )}`
246
+ );
247
+ }
248
+ } catch (error) {
249
+ throw error;
141
250
  }
142
- throw Error("module not found");
143
251
  });
144
252
  }, [exportName, basename, props.memoryRoute]);
145
- return /* @__PURE__ */ React__default.createElement(React__default.Suspense, { fallback: props.fallback }, /* @__PURE__ */ React__default.createElement(LazyComponent, null));
253
+ return /* @__PURE__ */ React__default.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React__default.createElement(React__default.Suspense, { fallback: info.loading }, /* @__PURE__ */ React__default.createElement(LazyComponent, null)));
146
254
  };
147
255
  }
148
256
  var client = {};
@@ -57,26 +57,23 @@ function WraperRouterProvider(props) {
57
57
  WraperRouterProviderProps: props,
58
58
  router
59
59
  });
60
+ const RouterProvider = ReactRouterDom__namespace["RouterProvider"];
61
+ const createMemoryRouter = ReactRouterDom__namespace["createMemoryRouter"];
62
+ const createBrowserRouter = ReactRouterDom__namespace["createBrowserRouter"];
60
63
  if (!routerContextProps)
61
- return /* @__PURE__ */ React.createElement(ReactRouterDom__namespace.RouterProvider, { ...props });
64
+ return /* @__PURE__ */ React.createElement(RouterProvider, { ...props });
62
65
  if (routerContextProps.memoryRoute) {
63
- const MemeoryRouterInstance = ReactRouterDom__namespace.createMemoryRouter(routers, {
66
+ const MemeoryRouterInstance = createMemoryRouter(routers, {
64
67
  initialEntries: [routerContextProps == null ? void 0 : routerContextProps.memoryRoute.entryPath]
65
68
  });
66
- return /* @__PURE__ */ React.createElement(ReactRouterDom__namespace.RouterProvider, { router: MemeoryRouterInstance });
69
+ return /* @__PURE__ */ React.createElement(RouterProvider, { router: MemeoryRouterInstance });
67
70
  } else {
68
- const BrowserRouterInstance = ReactRouterDom__namespace.createBrowserRouter(routers, {
71
+ const BrowserRouterInstance = createBrowserRouter(routers, {
69
72
  basename: routerContextProps.basename,
70
73
  future: router.future,
71
74
  window: router.window
72
75
  });
73
- return /* @__PURE__ */ React.createElement(
74
- ReactRouterDom__namespace.RouterProvider,
75
- {
76
- ...propsRes,
77
- router: BrowserRouterInstance
78
- }
79
- );
76
+ return /* @__PURE__ */ React.createElement(RouterProvider, { ...propsRes, router: BrowserRouterInstance });
80
77
  }
81
78
  }
82
79
  exports.BrowserRouter = WraperRouter;
package/dist/router.es.js CHANGED
@@ -39,26 +39,23 @@ function WraperRouterProvider(props) {
39
39
  WraperRouterProviderProps: props,
40
40
  router
41
41
  });
42
+ const RouterProvider = ReactRouterDom["RouterProvider"];
43
+ const createMemoryRouter = ReactRouterDom["createMemoryRouter"];
44
+ const createBrowserRouter = ReactRouterDom["createBrowserRouter"];
42
45
  if (!routerContextProps)
43
- return /* @__PURE__ */ React__default.createElement(ReactRouterDom.RouterProvider, { ...props });
46
+ return /* @__PURE__ */ React__default.createElement(RouterProvider, { ...props });
44
47
  if (routerContextProps.memoryRoute) {
45
- const MemeoryRouterInstance = ReactRouterDom.createMemoryRouter(routers, {
48
+ const MemeoryRouterInstance = createMemoryRouter(routers, {
46
49
  initialEntries: [routerContextProps == null ? void 0 : routerContextProps.memoryRoute.entryPath]
47
50
  });
48
- return /* @__PURE__ */ React__default.createElement(ReactRouterDom.RouterProvider, { router: MemeoryRouterInstance });
51
+ return /* @__PURE__ */ React__default.createElement(RouterProvider, { router: MemeoryRouterInstance });
49
52
  } else {
50
- const BrowserRouterInstance = ReactRouterDom.createBrowserRouter(routers, {
53
+ const BrowserRouterInstance = createBrowserRouter(routers, {
51
54
  basename: routerContextProps.basename,
52
55
  future: router.future,
53
56
  window: router.window
54
57
  });
55
- return /* @__PURE__ */ React__default.createElement(
56
- ReactRouterDom.RouterProvider,
57
- {
58
- ...propsRes,
59
- router: BrowserRouterInstance
60
- }
61
- );
58
+ return /* @__PURE__ */ React__default.createElement(RouterProvider, { ...propsRes, router: BrowserRouterInstance });
62
59
  }
63
60
  }
64
61
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/bridge-react",
3
- "version": "0.0.0-next-20240620060503",
3
+ "version": "0.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@loadable/component": "^5.16.4",
27
27
  "react-error-boundary": "^4.0.13",
28
- "@module-federation/bridge-shared": "0.0.0-next-20240620060503"
28
+ "@module-federation/bridge-shared": "0.2.0"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "react": ">=16.9.0",
package/src/create.tsx CHANGED
@@ -1,15 +1,12 @@
1
- import React, {
2
- ReactNode,
3
- useContext,
4
- useEffect,
5
- useMemo,
6
- useRef,
7
- useState,
8
- } from 'react';
1
+ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
9
2
  import * as ReactRouterDOM from 'react-router-dom';
10
3
  import type { ProviderParams } from '@module-federation/bridge-shared';
11
4
  import { LoggerInstance, pathJoin } from './utils';
12
5
  import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
6
+ import {
7
+ ErrorBoundary,
8
+ ErrorBoundaryPropsWithComponent,
9
+ } from 'react-error-boundary';
13
10
 
14
11
  declare const __APP_VERSION__: string;
15
12
 
@@ -102,12 +99,12 @@ const RemoteApp = ({
102
99
 
103
100
  (RemoteApp as any)['__APP_VERSION__'] = __APP_VERSION__;
104
101
 
105
- export function createRemoteComponent<T, E extends keyof T>(
106
- lazyComponent: () => Promise<T>,
107
- info?: {
108
- export?: E;
109
- },
110
- ) {
102
+ export function createRemoteComponent<T, E extends keyof T>(info: {
103
+ loader: () => Promise<T>;
104
+ loading: React.ReactNode;
105
+ fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
106
+ export?: E;
107
+ }) {
111
108
  type ExportType = T[E] extends (...args: any) => any
112
109
  ? ReturnType<T[E]>
113
110
  : never;
@@ -121,7 +118,6 @@ export function createRemoteComponent<T, E extends keyof T>(
121
118
  props: {
122
119
  basename?: ProviderParams['basename'];
123
120
  memoryRoute?: ProviderParams['memoryRoute'];
124
- fallback: ReactNode;
125
121
  } & RawComponentType,
126
122
  ) => {
127
123
  const exportName = info?.export || 'default';
@@ -181,46 +177,60 @@ export function createRemoteComponent<T, E extends keyof T>(
181
177
  return React.lazy(async () => {
182
178
  LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
183
179
  basename,
184
- lazyComponent,
180
+ lazyComponent: info.loader,
185
181
  exportName,
186
182
  props,
187
183
  routerContextVal,
188
184
  });
189
- const m = (await lazyComponent()) as RemoteModule;
190
- // @ts-ignore
191
- const moduleName = m && m[Symbol.for('mf_module_id')];
192
- LoggerInstance.log(
193
- `createRemoteComponent LazyComponent loadRemote info >>>`,
194
- { basename, name: moduleName, module: m, exportName, props },
195
- );
196
-
197
- // @ts-ignore
198
- const exportFn = m[exportName] as any;
199
-
200
- if (exportName in m && typeof exportFn === 'function') {
201
- return {
202
- default: () => (
203
- <RemoteApp
204
- name={moduleName}
205
- dispathPopstate={enableDispathPopstate}
206
- {...info}
207
- {...props}
208
- providerInfo={exportFn}
209
- basename={basename}
210
- />
211
- ),
212
- };
213
- }
185
+ try {
186
+ const m = (await info.loader()) as RemoteModule;
187
+ // @ts-ignore
188
+ const moduleName = m && m[Symbol.for('mf_module_id')];
189
+ LoggerInstance.log(
190
+ `createRemoteComponent LazyComponent loadRemote info >>>`,
191
+ { basename, name: moduleName, module: m, exportName, props },
192
+ );
214
193
 
215
- throw Error('module not found');
194
+ // @ts-ignore
195
+ const exportFn = m[exportName] as any;
196
+
197
+ if (exportName in m && typeof exportFn === 'function') {
198
+ return {
199
+ default: () => (
200
+ <RemoteApp
201
+ name={moduleName}
202
+ dispathPopstate={enableDispathPopstate}
203
+ {...info}
204
+ {...props}
205
+ providerInfo={exportFn}
206
+ basename={basename}
207
+ />
208
+ ),
209
+ };
210
+ } else {
211
+ LoggerInstance.log(
212
+ `createRemoteComponent LazyComponent module not found >>>`,
213
+ { basename, name: moduleName, module: m, exportName, props },
214
+ );
215
+ throw Error(
216
+ `Make sure that ${moduleName} has the correct export when export is ${String(
217
+ exportName,
218
+ )}`,
219
+ );
220
+ }
221
+ } catch (error) {
222
+ throw error;
223
+ }
216
224
  });
217
225
  }, [exportName, basename, props.memoryRoute]);
218
226
 
219
227
  //@ts-ignore
220
228
  return (
221
- <React.Suspense fallback={props.fallback}>
222
- <LazyComponent />
223
- </React.Suspense>
229
+ <ErrorBoundary FallbackComponent={info.fallback}>
230
+ <React.Suspense fallback={info.loading}>
231
+ <LazyComponent />
232
+ </React.Suspense>
233
+ </ErrorBoundary>
224
234
  );
225
235
  };
226
236
  }
package/src/router.tsx CHANGED
@@ -47,24 +47,25 @@ function WraperRouterProvider(
47
47
  WraperRouterProviderProps: props,
48
48
  router,
49
49
  });
50
- if (!routerContextProps) return <ReactRouterDom.RouterProvider {...props} />;
50
+ const RouterProvider = (ReactRouterDom as any)['Router' + 'Provider'];
51
+ const createMemoryRouter = (ReactRouterDom as any)['create' + 'MemoryRouter'];
52
+ const createBrowserRouter = (ReactRouterDom as any)[
53
+ 'create' + 'BrowserRouter'
54
+ ];
55
+ if (!routerContextProps) return <RouterProvider {...props} />;
56
+
51
57
  if (routerContextProps.memoryRoute) {
52
- const MemeoryRouterInstance = ReactRouterDom.createMemoryRouter(routers, {
58
+ const MemeoryRouterInstance = createMemoryRouter(routers, {
53
59
  initialEntries: [routerContextProps?.memoryRoute.entryPath],
54
60
  });
55
- return <ReactRouterDom.RouterProvider router={MemeoryRouterInstance} />;
61
+ return <RouterProvider router={MemeoryRouterInstance} />;
56
62
  } else {
57
- const BrowserRouterInstance = ReactRouterDom.createBrowserRouter(routers, {
63
+ const BrowserRouterInstance = createBrowserRouter(routers, {
58
64
  basename: routerContextProps.basename,
59
65
  future: router.future,
60
66
  window: router.window,
61
67
  });
62
- return (
63
- <ReactRouterDom.RouterProvider
64
- {...propsRes}
65
- router={BrowserRouterInstance}
66
- />
67
- );
68
+ return <RouterProvider {...propsRes} router={BrowserRouterInstance} />;
68
69
  }
69
70
  }
70
71