@module-federation/bridge-react 0.0.0-next-20240704021704 → 0.0.0-next-20240707072703

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,10 +1,10 @@
1
1
  # @module-federation/bridge-react
2
2
 
3
- ## 0.0.0-next-20240704021704
3
+ ## 0.0.0-next-20240707072703
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - @module-federation/bridge-shared@0.0.0-next-20240704021704
7
+ - @module-federation/bridge-shared@0.0.0-next-20240707072703
8
8
 
9
9
  ## 0.2.3
10
10
 
package/dist/index.cjs.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const React = require("react");
4
- const context = require("./context--mtFt3tp.cjs");
5
4
  const ReactRouterDOM = require("react-router-dom");
5
+ const context = require("./context--mtFt3tp.cjs");
6
6
  const ReactDOM = require("react-dom");
7
7
  function _interopNamespaceDefault(e) {
8
8
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -122,11 +122,26 @@ const RemoteApp = ({
122
122
  memoryRoute,
123
123
  basename,
124
124
  providerInfo,
125
+ dispathPopstate,
125
126
  ...resProps
126
127
  }) => {
127
128
  const rootRef = React.useRef(null);
128
129
  const renderDom = React.useRef(null);
129
130
  const providerInfoRef = React.useRef(null);
131
+ if (dispathPopstate) {
132
+ const location = ReactRouterDOM__namespace.useLocation();
133
+ const [pathname, setPathname] = React.useState(location.pathname);
134
+ React.useEffect(() => {
135
+ if (pathname !== "" && pathname !== location.pathname) {
136
+ context.LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
137
+ name,
138
+ pathname: location.pathname
139
+ });
140
+ context.f();
141
+ }
142
+ setPathname(location.pathname);
143
+ }, [location]);
144
+ }
130
145
  React.useEffect(() => {
131
146
  const renderTimeout = setTimeout(() => {
132
147
  const providerReturn = providerInfo();
@@ -164,9 +179,11 @@ const RemoteApp = ({
164
179
  return /* @__PURE__ */ React.createElement("div", { ref: rootRef });
165
180
  };
166
181
  RemoteApp["__APP_VERSION__"] = "0.2.3";
167
- function withRouterData(WrappedComponent) {
182
+ function createRemoteComponent(info) {
168
183
  return (props) => {
169
184
  var _a;
185
+ const exportName = (info == null ? void 0 : info.export) || "default";
186
+ let basename = "/";
170
187
  let enableDispathPopstate = false;
171
188
  let routerContextVal;
172
189
  try {
@@ -175,8 +192,9 @@ function withRouterData(WrappedComponent) {
175
192
  } catch {
176
193
  enableDispathPopstate = false;
177
194
  }
178
- let basename = "/";
179
- if (!props.basename && enableDispathPopstate) {
195
+ if (props.basename) {
196
+ basename = props.basename;
197
+ } else if (enableDispathPopstate) {
180
198
  const ReactRouterDOMAny = ReactRouterDOM__namespace;
181
199
  const useRouteMatch = ReactRouterDOMAny["useRouteMatch"];
182
200
  const useHistory = ReactRouterDOMAny["useHistory"];
@@ -187,10 +205,11 @@ function withRouterData(WrappedComponent) {
187
205
  basename = useHref == null ? void 0 : useHref("/");
188
206
  }
189
207
  routerContextVal = React.useContext(UNSAFE_RouteContext);
190
- if (routerContextVal && routerContextVal.matches && routerContextVal.matches.length > 0) {
191
- const matchIndex = routerContextVal.matches.length - 1;
192
- const pathnameBase = routerContextVal.matches[matchIndex].pathnameBase;
193
- basename = context.pathJoin(basename, pathnameBase || "/");
208
+ if (routerContextVal && routerContextVal.matches && routerContextVal.matches[0] && routerContextVal.matches[0].pathnameBase) {
209
+ basename = context.pathJoin(
210
+ basename,
211
+ routerContextVal.matches[0].pathnameBase || "/"
212
+ );
194
213
  }
195
214
  } else {
196
215
  const match = useRouteMatch == null ? void 0 : useRouteMatch();
@@ -203,80 +222,54 @@ function withRouterData(WrappedComponent) {
203
222
  }
204
223
  }
205
224
  }
206
- context.LoggerInstance.log(`createRemoteComponent withRouterData >>>`, {
207
- ...props,
208
- basename,
209
- routerContextVal,
210
- enableDispathPopstate
211
- });
212
- if (enableDispathPopstate) {
213
- const location = ReactRouterDOM__namespace.useLocation();
214
- const [pathname, setPathname] = React.useState(location.pathname);
215
- React.useEffect(() => {
216
- if (pathname !== "" && pathname !== location.pathname) {
217
- context.LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
218
- name: props.name,
219
- pathname: location.pathname
220
- });
221
- context.f();
222
- }
223
- setPathname(location.pathname);
224
- }, [location]);
225
- }
226
- return /* @__PURE__ */ React.createElement(WrappedComponent, { ...props, basename });
227
- };
228
- }
229
- const RemoteApp$1 = withRouterData(RemoteApp);
230
- function createLazyRemoteComponent(info) {
231
- const exportName = (info == null ? void 0 : info.export) || "default";
232
- return React.lazy(async () => {
233
- context.LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
234
- lazyComponent: info.loader,
235
- exportName
236
- });
237
- try {
238
- const m2 = await info.loader();
239
- const moduleName = m2 && m2[Symbol.for("mf_module_id")];
240
- context.LoggerInstance.log(
241
- `createRemoteComponent LazyComponent loadRemote info >>>`,
242
- { name: moduleName, module: m2, exportName }
243
- );
244
- const exportFn = m2[exportName];
245
- if (exportName in m2 && typeof exportFn === "function") {
246
- const RemoteAppComponent = React.forwardRef((props, _ref) => {
247
- return /* @__PURE__ */ React.createElement(
248
- RemoteApp$1,
249
- {
250
- name: moduleName,
251
- providerInfo: exportFn,
252
- exportName: info.export || "default",
253
- ...props
254
- }
255
- );
225
+ const LazyComponent = React.useMemo(() => {
226
+ return React.lazy(async () => {
227
+ context.LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
228
+ basename,
229
+ lazyComponent: info.loader,
230
+ exportName,
231
+ props,
232
+ routerContextVal
256
233
  });
257
- return {
258
- default: RemoteAppComponent
259
- };
260
- } else {
261
- context.LoggerInstance.log(
262
- `createRemoteComponent LazyComponent module not found >>>`,
263
- { name: moduleName, module: m2, exportName }
264
- );
265
- throw Error(
266
- `Make sure that ${moduleName} has the correct export when export is ${String(
267
- exportName
268
- )}`
269
- );
270
- }
271
- } catch (error) {
272
- throw error;
273
- }
274
- });
275
- }
276
- function createRemoteComponent(info) {
277
- const LazyComponent = createLazyRemoteComponent(info);
278
- return (props) => {
279
- return /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React.createElement(React.Suspense, { fallback: info.loading }, /* @__PURE__ */ React.createElement(LazyComponent, { ...props })));
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;
269
+ }
270
+ });
271
+ }, [exportName, basename, props.memoryRoute]);
272
+ return /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: info.fallback }, /* @__PURE__ */ React.createElement(React.Suspense, { fallback: info.loading }, /* @__PURE__ */ React.createElement(LazyComponent, null)));
280
273
  };
281
274
  }
282
275
  var client = {};
package/dist/index.d.ts CHANGED
@@ -19,8 +19,8 @@ export declare function createRemoteComponent<T, E extends keyof T>(info: {
19
19
  fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
20
20
  export?: E;
21
21
  }): (props: {
22
- basename?: ProviderParams["basename"];
23
- memoryRoute?: ProviderParams["memoryRoute"];
22
+ basename?: ProviderParams['basename'];
23
+ memoryRoute?: ProviderParams['memoryRoute'];
24
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;
25
25
 
26
26
  declare type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
package/dist/index.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
- import React__default, { createContext, Component, createElement, isValidElement, useContext, useState, useEffect, useRef, forwardRef } from "react";
3
- import { p as pathJoin, L as LoggerInstance, f, a as atLeastReact18, R as RouterContext } from "./context-Bw2PEwa6.js";
2
+ import React__default, { createContext, Component, createElement, isValidElement, useContext, useMemo, useRef, useState, useEffect } from "react";
4
3
  import * as ReactRouterDOM from "react-router-dom";
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
6
  const ErrorBoundaryContext = createContext(null);
7
7
  const initialState = {
@@ -103,11 +103,26 @@ const RemoteApp = ({
103
103
  memoryRoute,
104
104
  basename,
105
105
  providerInfo,
106
+ dispathPopstate,
106
107
  ...resProps
107
108
  }) => {
108
109
  const rootRef = useRef(null);
109
110
  const renderDom = useRef(null);
110
111
  const providerInfoRef = useRef(null);
112
+ if (dispathPopstate) {
113
+ const location = ReactRouterDOM.useLocation();
114
+ const [pathname, setPathname] = useState(location.pathname);
115
+ useEffect(() => {
116
+ if (pathname !== "" && pathname !== location.pathname) {
117
+ LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
118
+ name,
119
+ pathname: location.pathname
120
+ });
121
+ f();
122
+ }
123
+ setPathname(location.pathname);
124
+ }, [location]);
125
+ }
111
126
  useEffect(() => {
112
127
  const renderTimeout = setTimeout(() => {
113
128
  const providerReturn = providerInfo();
@@ -145,9 +160,11 @@ const RemoteApp = ({
145
160
  return /* @__PURE__ */ React__default.createElement("div", { ref: rootRef });
146
161
  };
147
162
  RemoteApp["__APP_VERSION__"] = "0.2.3";
148
- function withRouterData(WrappedComponent) {
163
+ function createRemoteComponent(info) {
149
164
  return (props) => {
150
165
  var _a;
166
+ const exportName = (info == null ? void 0 : info.export) || "default";
167
+ let basename = "/";
151
168
  let enableDispathPopstate = false;
152
169
  let routerContextVal;
153
170
  try {
@@ -156,8 +173,9 @@ function withRouterData(WrappedComponent) {
156
173
  } catch {
157
174
  enableDispathPopstate = false;
158
175
  }
159
- let basename = "/";
160
- if (!props.basename && enableDispathPopstate) {
176
+ if (props.basename) {
177
+ basename = props.basename;
178
+ } else if (enableDispathPopstate) {
161
179
  const ReactRouterDOMAny = ReactRouterDOM;
162
180
  const useRouteMatch = ReactRouterDOMAny["useRouteMatch"];
163
181
  const useHistory = ReactRouterDOMAny["useHistory"];
@@ -168,10 +186,11 @@ function withRouterData(WrappedComponent) {
168
186
  basename = useHref == null ? void 0 : useHref("/");
169
187
  }
170
188
  routerContextVal = useContext(UNSAFE_RouteContext);
171
- if (routerContextVal && routerContextVal.matches && routerContextVal.matches.length > 0) {
172
- const matchIndex = routerContextVal.matches.length - 1;
173
- const pathnameBase = routerContextVal.matches[matchIndex].pathnameBase;
174
- basename = pathJoin(basename, pathnameBase || "/");
189
+ if (routerContextVal && routerContextVal.matches && routerContextVal.matches[0] && routerContextVal.matches[0].pathnameBase) {
190
+ basename = pathJoin(
191
+ basename,
192
+ routerContextVal.matches[0].pathnameBase || "/"
193
+ );
175
194
  }
176
195
  } else {
177
196
  const match = useRouteMatch == null ? void 0 : useRouteMatch();
@@ -184,80 +203,54 @@ function withRouterData(WrappedComponent) {
184
203
  }
185
204
  }
186
205
  }
187
- LoggerInstance.log(`createRemoteComponent withRouterData >>>`, {
188
- ...props,
189
- basename,
190
- routerContextVal,
191
- enableDispathPopstate
192
- });
193
- if (enableDispathPopstate) {
194
- const location = ReactRouterDOM.useLocation();
195
- const [pathname, setPathname] = useState(location.pathname);
196
- useEffect(() => {
197
- if (pathname !== "" && pathname !== location.pathname) {
198
- LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
199
- name: props.name,
200
- pathname: location.pathname
201
- });
202
- f();
203
- }
204
- setPathname(location.pathname);
205
- }, [location]);
206
- }
207
- return /* @__PURE__ */ React__default.createElement(WrappedComponent, { ...props, basename });
208
- };
209
- }
210
- const RemoteApp$1 = withRouterData(RemoteApp);
211
- function createLazyRemoteComponent(info) {
212
- const exportName = (info == null ? void 0 : info.export) || "default";
213
- return React__default.lazy(async () => {
214
- LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
215
- lazyComponent: info.loader,
216
- exportName
217
- });
218
- try {
219
- const m2 = await info.loader();
220
- const moduleName = m2 && m2[Symbol.for("mf_module_id")];
221
- LoggerInstance.log(
222
- `createRemoteComponent LazyComponent loadRemote info >>>`,
223
- { name: moduleName, module: m2, exportName }
224
- );
225
- const exportFn = m2[exportName];
226
- if (exportName in m2 && typeof exportFn === "function") {
227
- const RemoteAppComponent = forwardRef((props, _ref) => {
228
- return /* @__PURE__ */ React__default.createElement(
229
- RemoteApp$1,
230
- {
231
- name: moduleName,
232
- providerInfo: exportFn,
233
- exportName: info.export || "default",
234
- ...props
235
- }
236
- );
206
+ const LazyComponent = useMemo(() => {
207
+ return React__default.lazy(async () => {
208
+ LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
209
+ basename,
210
+ lazyComponent: info.loader,
211
+ exportName,
212
+ props,
213
+ routerContextVal
237
214
  });
238
- return {
239
- default: RemoteAppComponent
240
- };
241
- } else {
242
- LoggerInstance.log(
243
- `createRemoteComponent LazyComponent module not found >>>`,
244
- { name: moduleName, module: m2, exportName }
245
- );
246
- throw Error(
247
- `Make sure that ${moduleName} has the correct export when export is ${String(
248
- exportName
249
- )}`
250
- );
251
- }
252
- } catch (error) {
253
- throw error;
254
- }
255
- });
256
- }
257
- function createRemoteComponent(info) {
258
- const LazyComponent = createLazyRemoteComponent(info);
259
- return (props) => {
260
- 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 })));
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;
250
+ }
251
+ });
252
+ }, [exportName, basename, props.memoryRoute]);
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)));
261
254
  };
262
255
  }
263
256
  var client = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/bridge-react",
3
- "version": "0.0.0-next-20240704021704",
3
+ "version": "0.0.0-next-20240707072703",
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-20240704021704"
28
+ "@module-federation/bridge-shared": "0.0.0-next-20240707072703"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "react": ">=16.9.0",
package/src/create.tsx CHANGED
@@ -1,11 +1,14 @@
1
- import React, { forwardRef } from 'react';
1
+ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
2
+ import * as ReactRouterDOM from 'react-router-dom';
2
3
  import type { ProviderParams } from '@module-federation/bridge-shared';
3
- import { LoggerInstance } from './utils';
4
+ import { LoggerInstance, pathJoin } from './utils';
5
+ import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
4
6
  import {
5
7
  ErrorBoundary,
6
8
  ErrorBoundaryPropsWithComponent,
7
9
  } from 'react-error-boundary';
8
- import RemoteApp from './remote';
10
+
11
+ declare const __APP_VERSION__: string;
9
12
 
10
13
  export interface RenderFnParams extends ProviderParams {
11
14
  dom?: any;
@@ -22,67 +25,79 @@ interface RemoteModule {
22
25
  };
23
26
  }
24
27
 
25
- function createLazyRemoteComponent<T, E extends keyof T>(info: {
26
- loader: () => Promise<T>;
27
- loading: React.ReactNode;
28
- fallback: ErrorBoundaryPropsWithComponent['FallbackComponent'];
29
- export?: E;
30
- }) {
31
- const exportName = info?.export || 'default';
32
- return React.lazy(async () => {
33
- LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
34
- lazyComponent: info.loader,
35
- exportName,
36
- });
37
- try {
38
- const m = (await info.loader()) as RemoteModule;
39
- // @ts-ignore
40
- const moduleName = m && m[Symbol.for('mf_module_id')];
28
+ interface RemoteAppParams {
29
+ name: string;
30
+ providerInfo: NonNullable<RemoteModule['provider']>;
31
+ dispathPopstate: boolean;
32
+ }
33
+
34
+ const RemoteApp = ({
35
+ name,
36
+ memoryRoute,
37
+ basename,
38
+ providerInfo,
39
+ dispathPopstate,
40
+ ...resProps
41
+ }: RemoteAppParams & ProviderParams) => {
42
+ const rootRef = useRef(null);
43
+ const renderDom = useRef(null);
44
+ const providerInfoRef = useRef<any>(null);
45
+ if (dispathPopstate) {
46
+ const location = ReactRouterDOM.useLocation();
47
+ const [pathname, setPathname] = useState(location.pathname);
48
+
49
+ useEffect(() => {
50
+ if (pathname !== '' && pathname !== location.pathname) {
51
+ LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
52
+ name,
53
+ pathname: location.pathname,
54
+ });
55
+ dispatchPopstateEnv();
56
+ }
57
+ setPathname(location.pathname);
58
+ }, [location]);
59
+ }
60
+
61
+ useEffect(() => {
62
+ const renderTimeout = setTimeout(() => {
63
+ const providerReturn = providerInfo();
64
+ providerInfoRef.current = providerReturn;
65
+ const renderProps = {
66
+ name,
67
+ dom: rootRef.current,
68
+ basename,
69
+ memoryRoute,
70
+ ...resProps,
71
+ };
72
+ renderDom.current = rootRef.current;
41
73
  LoggerInstance.log(
42
- `createRemoteComponent LazyComponent loadRemote info >>>`,
43
- { name: moduleName, module: m, exportName },
74
+ `createRemoteComponent LazyComponent render >>>`,
75
+ renderProps,
44
76
  );
77
+ providerReturn.render(renderProps);
78
+ });
45
79
 
46
- // @ts-ignore
47
- const exportFn = m[exportName] as any;
48
-
49
- if (exportName in m && typeof exportFn === 'function') {
50
- const RemoteAppComponent = forwardRef<
51
- HTMLDivElement,
52
- {
53
- basename?: ProviderParams['basename'];
54
- memoryRoute?: ProviderParams['memoryRoute'];
55
- }
56
- >((props, _ref) => {
57
- return (
58
- <RemoteApp
59
- name={moduleName}
60
- providerInfo={exportFn}
61
- exportName={info.export || 'default'}
62
- {...props}
63
- />
80
+ return () => {
81
+ clearTimeout(renderTimeout);
82
+ setTimeout(() => {
83
+ if (providerInfoRef.current?.destroy) {
84
+ LoggerInstance.log(
85
+ `createRemoteComponent LazyComponent destroy >>>`,
86
+ { name, basename, dom: renderDom.current },
64
87
  );
65
- });
88
+ providerInfoRef.current?.destroy({
89
+ dom: renderDom.current,
90
+ });
91
+ }
92
+ });
93
+ };
94
+ }, []);
66
95
 
67
- return {
68
- default: RemoteAppComponent,
69
- };
70
- } else {
71
- LoggerInstance.log(
72
- `createRemoteComponent LazyComponent module not found >>>`,
73
- { name: moduleName, module: m, exportName },
74
- );
75
- throw Error(
76
- `Make sure that ${moduleName} has the correct export when export is ${String(
77
- exportName,
78
- )}`,
79
- );
80
- }
81
- } catch (error) {
82
- throw error;
83
- }
84
- });
85
- }
96
+ //@ts-ignore
97
+ return <div ref={rootRef}></div>;
98
+ };
99
+
100
+ (RemoteApp as any)['__APP_VERSION__'] = __APP_VERSION__;
86
101
 
87
102
  export function createRemoteComponent<T, E extends keyof T>(info: {
88
103
  loader: () => Promise<T>;
@@ -99,18 +114,121 @@ export function createRemoteComponent<T, E extends keyof T>(info: {
99
114
  : {}
100
115
  : {};
101
116
 
102
- const LazyComponent = createLazyRemoteComponent(info);
103
-
104
117
  return (
105
118
  props: {
106
119
  basename?: ProviderParams['basename'];
107
120
  memoryRoute?: ProviderParams['memoryRoute'];
108
121
  } & RawComponentType,
109
122
  ) => {
123
+ const exportName = info?.export || 'default';
124
+ let basename = '/';
125
+ let enableDispathPopstate = false;
126
+ let routerContextVal: any;
127
+ try {
128
+ ReactRouterDOM.useLocation();
129
+ enableDispathPopstate = true;
130
+ } catch {
131
+ enableDispathPopstate = false;
132
+ }
133
+
134
+ if (props.basename) {
135
+ basename = props.basename;
136
+ } else if (enableDispathPopstate) {
137
+ const ReactRouterDOMAny: any = ReactRouterDOM;
138
+ // Avoid building tools checking references
139
+ const useRouteMatch = ReactRouterDOMAny['use' + 'RouteMatch']; //v5
140
+ const useHistory = ReactRouterDOMAny['use' + 'History']; //v5
141
+ const useHref = ReactRouterDOMAny['use' + 'Href'];
142
+ const UNSAFE_RouteContext = ReactRouterDOMAny['UNSAFE_' + 'RouteContext'];
143
+
144
+ if (UNSAFE_RouteContext /* react-router@6 */) {
145
+ if (useHref) {
146
+ basename = useHref?.('/');
147
+ }
148
+ routerContextVal = useContext(UNSAFE_RouteContext);
149
+ if (
150
+ routerContextVal &&
151
+ routerContextVal.matches &&
152
+ routerContextVal.matches[0] &&
153
+ routerContextVal.matches[0].pathnameBase
154
+ ) {
155
+ basename = pathJoin(
156
+ basename,
157
+ routerContextVal.matches[0].pathnameBase || '/',
158
+ );
159
+ }
160
+ } /* react-router@5 */ else {
161
+ const match = useRouteMatch?.(); // v5
162
+ if (useHistory /* react-router@5 */) {
163
+ // there is no dynamic switching of the router version in the project
164
+ // so hooks can be used in conditional judgment
165
+ const history = useHistory?.();
166
+ // To be compatible to history@4.10.1 and @5.3.0 we cannot write like this `history.createHref(pathname)`
167
+ basename = history?.createHref?.({ pathname: '/' });
168
+ }
169
+ if (match /* react-router@5 */) {
170
+ basename = pathJoin(basename, match?.path || '/');
171
+ }
172
+ }
173
+ }
174
+
175
+ const LazyComponent = useMemo(() => {
176
+ //@ts-ignore
177
+ return React.lazy(async () => {
178
+ LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
179
+ basename,
180
+ lazyComponent: info.loader,
181
+ exportName,
182
+ props,
183
+ routerContextVal,
184
+ });
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
+ );
193
+
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
+ }
224
+ });
225
+ }, [exportName, basename, props.memoryRoute]);
226
+
227
+ //@ts-ignore
110
228
  return (
111
229
  <ErrorBoundary FallbackComponent={info.fallback}>
112
230
  <React.Suspense fallback={info.loading}>
113
- <LazyComponent {...props} />
231
+ <LazyComponent />
114
232
  </React.Suspense>
115
233
  </ErrorBoundary>
116
234
  );
@@ -1,165 +0,0 @@
1
- import React, { useContext, useEffect, useRef, useState } from 'react';
2
- import * as ReactRouterDOM from 'react-router-dom';
3
- import type { ProviderParams } from '@module-federation/bridge-shared';
4
- import { LoggerInstance, pathJoin } from '../utils';
5
- import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
6
-
7
- declare const __APP_VERSION__: string;
8
-
9
- export interface RenderFnParams extends ProviderParams {
10
- dom?: any;
11
- }
12
-
13
- interface RemoteModule {
14
- provider: () => {
15
- render: (
16
- info: ProviderParams & {
17
- dom: any;
18
- },
19
- ) => void;
20
- destroy: (info: { dom: any }) => void;
21
- };
22
- }
23
-
24
- interface RemoteAppParams {
25
- name: string;
26
- providerInfo: NonNullable<RemoteModule['provider']>;
27
- exportName: string | number | symbol;
28
- }
29
-
30
- const RemoteApp = ({
31
- name,
32
- memoryRoute,
33
- basename,
34
- providerInfo,
35
- ...resProps
36
- }: RemoteAppParams & ProviderParams) => {
37
- const rootRef = useRef(null);
38
- const renderDom = useRef(null);
39
- const providerInfoRef = useRef<any>(null);
40
-
41
- useEffect(() => {
42
- const renderTimeout = setTimeout(() => {
43
- const providerReturn = providerInfo();
44
- providerInfoRef.current = providerReturn;
45
- const renderProps = {
46
- name,
47
- dom: rootRef.current,
48
- basename,
49
- memoryRoute,
50
- ...resProps,
51
- };
52
- renderDom.current = rootRef.current;
53
- LoggerInstance.log(
54
- `createRemoteComponent LazyComponent render >>>`,
55
- renderProps,
56
- );
57
- providerReturn.render(renderProps);
58
- });
59
-
60
- return () => {
61
- clearTimeout(renderTimeout);
62
- setTimeout(() => {
63
- if (providerInfoRef.current?.destroy) {
64
- LoggerInstance.log(
65
- `createRemoteComponent LazyComponent destroy >>>`,
66
- { name, basename, dom: renderDom.current },
67
- );
68
- providerInfoRef.current?.destroy({
69
- dom: renderDom.current,
70
- });
71
- }
72
- });
73
- };
74
- }, []);
75
-
76
- //@ts-ignore
77
- return <div ref={rootRef}></div>;
78
- };
79
-
80
- (RemoteApp as any)['__APP_VERSION__'] = __APP_VERSION__;
81
-
82
- interface ExtraDataProps {
83
- basename?: string;
84
- }
85
-
86
- export function withRouterData<P extends Parameters<typeof RemoteApp>[0]>(
87
- WrappedComponent: React.ComponentType<P & ExtraDataProps>,
88
- ): React.FC<Omit<P, keyof ExtraDataProps>> {
89
- return (props: any) => {
90
- let enableDispathPopstate = false;
91
- let routerContextVal: any;
92
- try {
93
- ReactRouterDOM.useLocation();
94
- enableDispathPopstate = true;
95
- } catch {
96
- enableDispathPopstate = false;
97
- }
98
- let basename = '/';
99
-
100
- if (!props.basename && enableDispathPopstate) {
101
- const ReactRouterDOMAny: any = ReactRouterDOM;
102
- // Avoid building tools checking references
103
- const useRouteMatch = ReactRouterDOMAny['use' + 'RouteMatch']; //v5
104
- const useHistory = ReactRouterDOMAny['use' + 'History']; //v5
105
- const useHref = ReactRouterDOMAny['use' + 'Href'];
106
- const UNSAFE_RouteContext = ReactRouterDOMAny['UNSAFE_' + 'RouteContext'];
107
-
108
- if (UNSAFE_RouteContext /* react-router@6 */) {
109
- if (useHref) {
110
- basename = useHref?.('/');
111
- }
112
- routerContextVal = useContext(UNSAFE_RouteContext);
113
- if (
114
- routerContextVal &&
115
- routerContextVal.matches &&
116
- routerContextVal.matches.length > 0
117
- ) {
118
- const matchIndex = routerContextVal.matches.length - 1;
119
- const pathnameBase =
120
- routerContextVal.matches[matchIndex].pathnameBase;
121
- basename = pathJoin(basename, pathnameBase || '/');
122
- }
123
- } /* react-router@5 */ else {
124
- const match = useRouteMatch?.(); // v5
125
- if (useHistory /* react-router@5 */) {
126
- // there is no dynamic switching of the router version in the project
127
- // so hooks can be used in conditional judgment
128
- const history = useHistory?.();
129
- // To be compatible to history@4.10.1 and @5.3.0 we cannot write like this `history.createHref(pathname)`
130
- basename = history?.createHref?.({ pathname: '/' });
131
- }
132
- if (match /* react-router@5 */) {
133
- basename = pathJoin(basename, match?.path || '/');
134
- }
135
- }
136
- }
137
-
138
- LoggerInstance.log(`createRemoteComponent withRouterData >>>`, {
139
- ...props,
140
- basename,
141
- routerContextVal,
142
- enableDispathPopstate,
143
- });
144
-
145
- if (enableDispathPopstate) {
146
- const location = ReactRouterDOM.useLocation();
147
- const [pathname, setPathname] = useState(location.pathname);
148
-
149
- useEffect(() => {
150
- if (pathname !== '' && pathname !== location.pathname) {
151
- LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
152
- name: props.name,
153
- pathname: location.pathname,
154
- });
155
- dispatchPopstateEnv();
156
- }
157
- setPathname(location.pathname);
158
- }, [location]);
159
- }
160
-
161
- return <WrappedComponent {...(props as P)} basename={basename} />;
162
- };
163
- }
164
-
165
- export default withRouterData(RemoteApp);