@module-federation/bridge-react 0.0.0-next-20241106033302 → 0.0.0-next-20241106104434

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,11 +1,16 @@
1
1
  # @module-federation/bridge-react
2
2
 
3
- ## 0.0.0-next-20241106033302
3
+ ## 0.0.0-next-20241106104434
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - @module-federation/sdk@0.0.0-next-20241106033302
8
- - @module-federation/bridge-shared@0.0.0-next-20241106033302
7
+ - 3082116: feat: feat: support lifecycyle hooks in module-deferation bridge
8
+ - Updated dependencies [8712967]
9
+ - Updated dependencies [6db4c5f]
10
+ - Updated dependencies [3082116]
11
+ - @module-federation/runtime@0.0.0-next-20241106104434
12
+ - @module-federation/sdk@0.0.0-next-20241106104434
13
+ - @module-federation/bridge-shared@0.0.0-next-20241106104434
9
14
 
10
15
  ## 0.7.0
11
16
 
@@ -29,8 +29,16 @@ var supportColor = () => {
29
29
  return supportsSubstitutions;
30
30
  }
31
31
  try {
32
- console.log("%c", "color:");
33
- supportsSubstitutions = true;
32
+ const testString = "color test";
33
+ const css = "color: red;";
34
+ const originalConsoleLog = console.log;
35
+ console.log = (...args) => {
36
+ if (args[0] === `%c${testString}` && args[1] === css) {
37
+ supportsSubstitutions = true;
38
+ }
39
+ };
40
+ console.log(`%c${testString}`, css);
41
+ console.log = originalConsoleLog;
34
42
  } catch (e) {
35
43
  supportsSubstitutions = false;
36
44
  }
@@ -28,8 +28,16 @@ var supportColor = () => {
28
28
  return supportsSubstitutions;
29
29
  }
30
30
  try {
31
- console.log("%c", "color:");
32
- supportsSubstitutions = true;
31
+ const testString = "color test";
32
+ const css = "color: red;";
33
+ const originalConsoleLog = console.log;
34
+ console.log = (...args) => {
35
+ if (args[0] === `%c${testString}` && args[1] === css) {
36
+ supportsSubstitutions = true;
37
+ }
38
+ };
39
+ console.log(`%c${testString}`, css);
40
+ console.log = originalConsoleLog;
33
41
  } catch (e) {
34
42
  supportsSubstitutions = false;
35
43
  }
package/dist/index.cjs.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const React = require("react");
4
- const context = require("./context-CefGbh9w.cjs");
4
+ const context = require("./context-BBLu8BlQ.cjs");
5
5
  const ReactRouterDOM = require("react-router-dom");
6
+ const runtime = require("@module-federation/runtime");
6
7
  const ReactDOM = require("react-dom");
7
8
  function _interopNamespaceDefault(e2) {
8
9
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -121,7 +122,23 @@ function e() {
121
122
  const t = new PopStateEvent("popstate", { state: window.history.state });
122
123
  window.dispatchEvent(t);
123
124
  }
125
+ const getModuleName = (id) => {
126
+ const idArray = id.split("/");
127
+ if (idArray.length < 2) {
128
+ return id;
129
+ }
130
+ return idArray[0] + "/" + idArray[1];
131
+ };
132
+ const getRootDomDefaultClassName = (moduleName) => {
133
+ if (!moduleName) {
134
+ return "";
135
+ }
136
+ const name = getModuleName(moduleName).replace(/\@/, "").replace(/\//, "-");
137
+ return `bridge-root-component-${name}`;
138
+ };
124
139
  const RemoteAppWrapper = React.forwardRef(function(props, ref) {
140
+ const host = runtime.getInstance();
141
+ context.LoggerInstance.log(`RemoteAppWrapper host >>>`, host);
125
142
  const RemoteApp2 = () => {
126
143
  context.LoggerInstance.log(`RemoteAppWrapper RemoteApp props >>>`, { props });
127
144
  const {
@@ -139,9 +156,10 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
139
156
  const providerInfoRef = React.useRef(null);
140
157
  React.useEffect(() => {
141
158
  const renderTimeout = setTimeout(() => {
159
+ var _a, _b, _c, _d;
142
160
  const providerReturn = providerInfo();
143
161
  providerInfoRef.current = providerReturn;
144
- const renderProps = {
162
+ let renderProps = {
145
163
  moduleName,
146
164
  dom: rootRef.current,
147
165
  basename,
@@ -154,28 +172,49 @@ const RemoteAppWrapper = React.forwardRef(function(props, ref) {
154
172
  `createRemoteComponent LazyComponent render >>>`,
155
173
  renderProps
156
174
  );
175
+ if ((host == null ? void 0 : host.bridgeHook) && ((_b = (_a = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.beforeBridgeRender)) {
176
+ const beforeBridgeRenderRes = (_d = (_c = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _c.lifecycle) == null ? void 0 : _d.beforeBridgeRender.emit({
177
+ ...renderProps
178
+ });
179
+ const extraProps = beforeBridgeRenderRes && typeof beforeBridgeRenderRes === "object" && (beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps) ? beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps : {};
180
+ renderProps = {
181
+ ...renderProps,
182
+ ...extraProps
183
+ };
184
+ }
157
185
  providerReturn.render(renderProps);
158
186
  });
159
187
  return () => {
160
188
  clearTimeout(renderTimeout);
161
189
  setTimeout(() => {
162
- var _a, _b;
190
+ var _a, _b, _c, _d, _e, _f;
163
191
  if ((_a = providerInfoRef.current) == null ? void 0 : _a.destroy) {
164
192
  context.LoggerInstance.log(
165
193
  `createRemoteComponent LazyComponent destroy >>>`,
166
194
  { moduleName, basename, dom: renderDom.current }
167
195
  );
168
- (_b = providerInfoRef.current) == null ? void 0 : _b.destroy({
196
+ if ((host == null ? void 0 : host.bridgeHook) && ((_c = (_b = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _b.lifecycle) == null ? void 0 : _c.afterBridgeDestroy)) {
197
+ (_e = (_d = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _d.lifecycle) == null ? void 0 : _e.afterBridgeDestroy.emit({
198
+ moduleName,
199
+ dom: renderDom.current,
200
+ basename,
201
+ memoryRoute,
202
+ fallback,
203
+ ...resProps
204
+ });
205
+ }
206
+ (_f = providerInfoRef.current) == null ? void 0 : _f.destroy({
169
207
  dom: renderDom.current
170
208
  });
171
209
  }
172
210
  });
173
211
  };
174
212
  }, []);
213
+ const rootComponentClassName = `${getRootDomDefaultClassName(moduleName)} ${props == null ? void 0 : props.className}`;
175
214
  return /* @__PURE__ */ React.createElement(
176
215
  "div",
177
216
  {
178
- className: props == null ? void 0 : props.className,
217
+ className: rootComponentClassName,
179
218
  style: props == null ? void 0 : props.style,
180
219
  ref: rootRef
181
220
  }
@@ -331,7 +370,7 @@ if (process.env.NODE_ENV === "production") {
331
370
  };
332
371
  }
333
372
  function createBridgeComponent(bridgeInfo) {
334
- return () => {
373
+ return (params) => {
335
374
  const rootMap = /* @__PURE__ */ new Map();
336
375
  const RawComponent = (info) => {
337
376
  const { appInfo, propsInfo, ...restProps } = info;
@@ -347,6 +386,7 @@ function createBridgeComponent(bridgeInfo) {
347
386
  };
348
387
  return {
349
388
  async render(info) {
389
+ var _a, _b;
350
390
  context.LoggerInstance.log(`createBridgeComponent render Info`, info);
351
391
  const {
352
392
  moduleName,
@@ -356,6 +396,9 @@ function createBridgeComponent(bridgeInfo) {
356
396
  fallback,
357
397
  ...propsInfo
358
398
  } = info;
399
+ const beforeBridgeRender = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.beforeBridgeRender) || ((_a = params == null ? void 0 : params.hooks) == null ? void 0 : _a.beforeBridgeRender);
400
+ const beforeBridgeRenderRes = beforeBridgeRender && beforeBridgeRender(info);
401
+ const extraProps = beforeBridgeRenderRes && typeof beforeBridgeRenderRes === "object" && (beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps) ? beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps : {};
359
402
  const rootComponentWithErrorBoundary = (
360
403
  // set ErrorBoundary for RawComponent rendering error, usually caused by user app rendering error
361
404
  /* @__PURE__ */ React__namespace.createElement(ErrorBoundary, { FallbackComponent: fallback }, /* @__PURE__ */ React__namespace.createElement(
@@ -366,7 +409,7 @@ function createBridgeComponent(bridgeInfo) {
366
409
  basename,
367
410
  memoryRoute
368
411
  },
369
- propsInfo
412
+ propsInfo: { ...propsInfo, ...extraProps }
370
413
  }
371
414
  ))
372
415
  );
@@ -384,11 +427,16 @@ function createBridgeComponent(bridgeInfo) {
384
427
  const renderFn = (bridgeInfo == null ? void 0 : bridgeInfo.render) || ReactDOM.render;
385
428
  renderFn == null ? void 0 : renderFn(rootComponentWithErrorBoundary, info.dom);
386
429
  }
430
+ const afterBridgeRender = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.afterBridgeDestroy) || ((_b = params == null ? void 0 : params.hooks) == null ? void 0 : _b.afterBridgeRender);
431
+ afterBridgeRender && afterBridgeRender(info);
387
432
  },
388
433
  async destroy(info) {
434
+ var _a, _b;
389
435
  context.LoggerInstance.log(`createBridgeComponent destroy Info`, {
390
436
  dom: info.dom
391
437
  });
438
+ const beforeBridgeDestroy = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.beforeBridgeDestroy) || ((_a = params == null ? void 0 : params.hooks) == null ? void 0 : _a.beforeBridgeDestroy);
439
+ beforeBridgeDestroy && beforeBridgeDestroy(info);
392
440
  if (context.atLeastReact18(React__namespace)) {
393
441
  const root = rootMap.get(info.dom);
394
442
  root == null ? void 0 : root.unmount();
@@ -396,6 +444,8 @@ function createBridgeComponent(bridgeInfo) {
396
444
  } else {
397
445
  ReactDOM.unmountComponentAtNode(info.dom);
398
446
  }
447
+ const afterBridgeDestroy = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.afterBridgeDestroy) || ((_b = params == null ? void 0 : params.hooks) == null ? void 0 : _b.afterBridgeDestroy);
448
+ afterBridgeDestroy && afterBridgeDestroy(info);
399
449
  },
400
450
  rawComponent: bridgeInfo.rootComponent,
401
451
  __BRIDGE_FN__: (_args) => {
package/dist/index.d.ts CHANGED
@@ -5,11 +5,18 @@ import { ErrorInfo } from 'react';
5
5
  import { PropsWithChildren } from 'react';
6
6
  import * as React_2 from 'react';
7
7
 
8
- export declare function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>): () => {
9
- render(info: RenderFnParams & any): Promise<void>;
10
- destroy(info: {
11
- dom: HTMLElement;
12
- }): Promise<void>;
8
+ declare type BridgeHooks = {
9
+ beforeBridgeRender?: (params: RenderFnParams) => any;
10
+ afterBridgeRender?: (params: RenderFnParams) => any;
11
+ beforeBridgeDestroy?: (params: DestroyParams) => any;
12
+ afterBridgeDestroy?: (params: DestroyParams) => any;
13
+ };
14
+
15
+ export declare function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>): (params?: {
16
+ hooks?: BridgeHooks;
17
+ }) => {
18
+ render(info: RenderParams): Promise<void>;
19
+ destroy(info: DestroyParams): Promise<void>;
13
20
  rawComponent: React_2.ComponentType<T>;
14
21
  __BRIDGE_FN__: (_args: T) => void;
15
22
  };
@@ -21,6 +28,10 @@ export declare function createRemoteComponent<T, E extends keyof T>(info: {
21
28
  export?: E;
22
29
  }): 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>>;
23
30
 
31
+ declare type DestroyParams = {
32
+ dom: HTMLElement;
33
+ };
34
+
24
35
  declare type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
25
36
  fallback?: never;
26
37
  FallbackComponent: ComponentType<FallbackProps>;
@@ -48,6 +59,7 @@ declare type FallbackProps = {
48
59
  declare type ProviderFnParams<T> = {
49
60
  rootComponent: React_2.ComponentType<T>;
50
61
  render?: (App: React_2.ReactElement, id?: HTMLElement | string) => RootType | Promise<RootType>;
62
+ hooks?: BridgeHooks;
51
63
  };
52
64
 
53
65
  export declare interface ProviderParams {
@@ -64,6 +76,8 @@ export declare interface RenderFnParams extends ProviderParams {
64
76
  dom: HTMLElement;
65
77
  }
66
78
 
79
+ declare type RenderParams = RenderFnParams & any;
80
+
67
81
  declare type RootType = HTMLElement | default_3.Root;
68
82
 
69
83
  export { }
package/dist/index.es.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as React from "react";
2
2
  import React__default, { createContext, Component, createElement, isValidElement, forwardRef, useRef, useEffect, useContext, useState } from "react";
3
- import { L as LoggerInstance, p as pathJoin, a as atLeastReact18, R as RouterContext } from "./context-DnCWjvho.js";
3
+ import { L as LoggerInstance, p as pathJoin, a as atLeastReact18, R as RouterContext } from "./context-BcyT-d0V.js";
4
4
  import * as ReactRouterDOM from "react-router-dom";
5
+ import { getInstance } from "@module-federation/runtime";
5
6
  import ReactDOM from "react-dom";
6
7
  const ErrorBoundaryContext = createContext(null);
7
8
  const initialState = {
@@ -102,7 +103,23 @@ function e() {
102
103
  const t = new PopStateEvent("popstate", { state: window.history.state });
103
104
  window.dispatchEvent(t);
104
105
  }
106
+ const getModuleName = (id) => {
107
+ const idArray = id.split("/");
108
+ if (idArray.length < 2) {
109
+ return id;
110
+ }
111
+ return idArray[0] + "/" + idArray[1];
112
+ };
113
+ const getRootDomDefaultClassName = (moduleName) => {
114
+ if (!moduleName) {
115
+ return "";
116
+ }
117
+ const name = getModuleName(moduleName).replace(/\@/, "").replace(/\//, "-");
118
+ return `bridge-root-component-${name}`;
119
+ };
105
120
  const RemoteAppWrapper = forwardRef(function(props, ref) {
121
+ const host = getInstance();
122
+ LoggerInstance.log(`RemoteAppWrapper host >>>`, host);
106
123
  const RemoteApp2 = () => {
107
124
  LoggerInstance.log(`RemoteAppWrapper RemoteApp props >>>`, { props });
108
125
  const {
@@ -120,9 +137,10 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
120
137
  const providerInfoRef = useRef(null);
121
138
  useEffect(() => {
122
139
  const renderTimeout = setTimeout(() => {
140
+ var _a, _b, _c, _d;
123
141
  const providerReturn = providerInfo();
124
142
  providerInfoRef.current = providerReturn;
125
- const renderProps = {
143
+ let renderProps = {
126
144
  moduleName,
127
145
  dom: rootRef.current,
128
146
  basename,
@@ -135,28 +153,49 @@ const RemoteAppWrapper = forwardRef(function(props, ref) {
135
153
  `createRemoteComponent LazyComponent render >>>`,
136
154
  renderProps
137
155
  );
156
+ if ((host == null ? void 0 : host.bridgeHook) && ((_b = (_a = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _a.lifecycle) == null ? void 0 : _b.beforeBridgeRender)) {
157
+ const beforeBridgeRenderRes = (_d = (_c = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _c.lifecycle) == null ? void 0 : _d.beforeBridgeRender.emit({
158
+ ...renderProps
159
+ });
160
+ const extraProps = beforeBridgeRenderRes && typeof beforeBridgeRenderRes === "object" && (beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps) ? beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps : {};
161
+ renderProps = {
162
+ ...renderProps,
163
+ ...extraProps
164
+ };
165
+ }
138
166
  providerReturn.render(renderProps);
139
167
  });
140
168
  return () => {
141
169
  clearTimeout(renderTimeout);
142
170
  setTimeout(() => {
143
- var _a, _b;
171
+ var _a, _b, _c, _d, _e, _f;
144
172
  if ((_a = providerInfoRef.current) == null ? void 0 : _a.destroy) {
145
173
  LoggerInstance.log(
146
174
  `createRemoteComponent LazyComponent destroy >>>`,
147
175
  { moduleName, basename, dom: renderDom.current }
148
176
  );
149
- (_b = providerInfoRef.current) == null ? void 0 : _b.destroy({
177
+ if ((host == null ? void 0 : host.bridgeHook) && ((_c = (_b = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _b.lifecycle) == null ? void 0 : _c.afterBridgeDestroy)) {
178
+ (_e = (_d = host == null ? void 0 : host.bridgeHook) == null ? void 0 : _d.lifecycle) == null ? void 0 : _e.afterBridgeDestroy.emit({
179
+ moduleName,
180
+ dom: renderDom.current,
181
+ basename,
182
+ memoryRoute,
183
+ fallback,
184
+ ...resProps
185
+ });
186
+ }
187
+ (_f = providerInfoRef.current) == null ? void 0 : _f.destroy({
150
188
  dom: renderDom.current
151
189
  });
152
190
  }
153
191
  });
154
192
  };
155
193
  }, []);
194
+ const rootComponentClassName = `${getRootDomDefaultClassName(moduleName)} ${props == null ? void 0 : props.className}`;
156
195
  return /* @__PURE__ */ React__default.createElement(
157
196
  "div",
158
197
  {
159
- className: props == null ? void 0 : props.className,
198
+ className: rootComponentClassName,
160
199
  style: props == null ? void 0 : props.style,
161
200
  ref: rootRef
162
201
  }
@@ -312,7 +351,7 @@ if (process.env.NODE_ENV === "production") {
312
351
  };
313
352
  }
314
353
  function createBridgeComponent(bridgeInfo) {
315
- return () => {
354
+ return (params) => {
316
355
  const rootMap = /* @__PURE__ */ new Map();
317
356
  const RawComponent = (info) => {
318
357
  const { appInfo, propsInfo, ...restProps } = info;
@@ -328,6 +367,7 @@ function createBridgeComponent(bridgeInfo) {
328
367
  };
329
368
  return {
330
369
  async render(info) {
370
+ var _a, _b;
331
371
  LoggerInstance.log(`createBridgeComponent render Info`, info);
332
372
  const {
333
373
  moduleName,
@@ -337,6 +377,9 @@ function createBridgeComponent(bridgeInfo) {
337
377
  fallback,
338
378
  ...propsInfo
339
379
  } = info;
380
+ const beforeBridgeRender = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.beforeBridgeRender) || ((_a = params == null ? void 0 : params.hooks) == null ? void 0 : _a.beforeBridgeRender);
381
+ const beforeBridgeRenderRes = beforeBridgeRender && beforeBridgeRender(info);
382
+ const extraProps = beforeBridgeRenderRes && typeof beforeBridgeRenderRes === "object" && (beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps) ? beforeBridgeRenderRes == null ? void 0 : beforeBridgeRenderRes.extraProps : {};
340
383
  const rootComponentWithErrorBoundary = (
341
384
  // set ErrorBoundary for RawComponent rendering error, usually caused by user app rendering error
342
385
  /* @__PURE__ */ React.createElement(ErrorBoundary, { FallbackComponent: fallback }, /* @__PURE__ */ React.createElement(
@@ -347,7 +390,7 @@ function createBridgeComponent(bridgeInfo) {
347
390
  basename,
348
391
  memoryRoute
349
392
  },
350
- propsInfo
393
+ propsInfo: { ...propsInfo, ...extraProps }
351
394
  }
352
395
  ))
353
396
  );
@@ -365,11 +408,16 @@ function createBridgeComponent(bridgeInfo) {
365
408
  const renderFn = (bridgeInfo == null ? void 0 : bridgeInfo.render) || ReactDOM.render;
366
409
  renderFn == null ? void 0 : renderFn(rootComponentWithErrorBoundary, info.dom);
367
410
  }
411
+ const afterBridgeRender = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.afterBridgeDestroy) || ((_b = params == null ? void 0 : params.hooks) == null ? void 0 : _b.afterBridgeRender);
412
+ afterBridgeRender && afterBridgeRender(info);
368
413
  },
369
414
  async destroy(info) {
415
+ var _a, _b;
370
416
  LoggerInstance.log(`createBridgeComponent destroy Info`, {
371
417
  dom: info.dom
372
418
  });
419
+ const beforeBridgeDestroy = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.beforeBridgeDestroy) || ((_a = params == null ? void 0 : params.hooks) == null ? void 0 : _a.beforeBridgeDestroy);
420
+ beforeBridgeDestroy && beforeBridgeDestroy(info);
373
421
  if (atLeastReact18(React)) {
374
422
  const root = rootMap.get(info.dom);
375
423
  root == null ? void 0 : root.unmount();
@@ -377,6 +425,8 @@ function createBridgeComponent(bridgeInfo) {
377
425
  } else {
378
426
  ReactDOM.unmountComponentAtNode(info.dom);
379
427
  }
428
+ const afterBridgeDestroy = (bridgeInfo == null ? void 0 : bridgeInfo.hooks) && (bridgeInfo == null ? void 0 : bridgeInfo.hooks.afterBridgeDestroy) || ((_b = params == null ? void 0 : params.hooks) == null ? void 0 : _b.afterBridgeDestroy);
429
+ afterBridgeDestroy && afterBridgeDestroy(info);
380
430
  },
381
431
  rawComponent: bridgeInfo.rootComponent,
382
432
  __BRIDGE_FN__: (_args) => {
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const React = require("react");
4
4
  const ReactRouterDom$1 = require("react-router-dom/index.js");
5
- const context = require("./context-CefGbh9w.cjs");
5
+ const context = require("./context-BBLu8BlQ.cjs");
6
6
  const ReactRouterDom = require("react-router-dom/index.js");
7
7
  function _interopNamespaceDefault(e) {
8
8
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -1,6 +1,6 @@
1
1
  import React__default, { useContext } from "react";
2
2
  import * as ReactRouterDom$1 from "react-router-dom/index.js";
3
- import { R as RouterContext, L as LoggerInstance } from "./context-DnCWjvho.js";
3
+ import { R as RouterContext, L as LoggerInstance } from "./context-BcyT-d0V.js";
4
4
  export * from "react-router-dom/index.js";
5
5
  function WraperRouter(props) {
6
6
  const { basename, ...propsRes } = props;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const React = require("react");
4
4
  const ReactRouterDom = require("react-router-dom/dist/index.js");
5
- const context = require("./context-CefGbh9w.cjs");
5
+ const context = require("./context-BBLu8BlQ.cjs");
6
6
  function _interopNamespaceDefault(e) {
7
7
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
8
8
  if (e) {
@@ -1,7 +1,7 @@
1
1
  import React__default, { useContext } from "react";
2
2
  import * as ReactRouterDom from "react-router-dom/dist/index.js";
3
3
  export * from "react-router-dom/dist/index.js";
4
- import { R as RouterContext, L as LoggerInstance } from "./context-DnCWjvho.js";
4
+ import { R as RouterContext, L as LoggerInstance } from "./context-BcyT-d0V.js";
5
5
  function WraperRouter(props) {
6
6
  const { basename, ...propsRes } = props;
7
7
  const routerContextProps = useContext(RouterContext) || {};
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const React = require("react");
4
4
  const ReactRouterDom = require("react-router-dom/");
5
- const context = require("./context-CefGbh9w.cjs");
5
+ const context = require("./context-BBLu8BlQ.cjs");
6
6
  function _interopNamespaceDefault(e) {
7
7
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
8
8
  if (e) {
@@ -65,7 +65,7 @@ function WrapperRouterProvider(props) {
65
65
  return /* @__PURE__ */ React.createElement(RouterProvider, { router: MemeoryRouterInstance });
66
66
  } else {
67
67
  const BrowserRouterInstance = createBrowserRouter(routers, {
68
- basename: routerContextProps.basename,
68
+ basename: routerContextProps.basename || (router == null ? void 0 : router.basename),
69
69
  future: router.future,
70
70
  window: router.window
71
71
  });
package/dist/router.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import React__default, { useContext } from "react";
2
2
  import * as ReactRouterDom from "react-router-dom/";
3
3
  export * from "react-router-dom/";
4
- import { R as RouterContext, L as LoggerInstance } from "./context-DnCWjvho.js";
4
+ import { R as RouterContext, L as LoggerInstance } from "./context-BcyT-d0V.js";
5
5
  function WrapperRouter(props) {
6
6
  const { basename, ...propsRes } = props;
7
7
  const routerContextProps = useContext(RouterContext) || {};
@@ -47,7 +47,7 @@ function WrapperRouterProvider(props) {
47
47
  return /* @__PURE__ */ React__default.createElement(RouterProvider, { router: MemeoryRouterInstance });
48
48
  } else {
49
49
  const BrowserRouterInstance = createBrowserRouter(routers, {
50
- basename: routerContextProps.basename,
50
+ basename: routerContextProps.basename || (router == null ? void 0 : router.basename),
51
51
  future: router.future,
52
52
  window: router.window
53
53
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/bridge-react",
3
- "version": "0.0.0-next-20241106033302",
3
+ "version": "0.0.0-next-20241106104434",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -41,13 +41,14 @@
41
41
  "dependencies": {
42
42
  "@loadable/component": "^5.16.4",
43
43
  "react-error-boundary": "^4.0.13",
44
- "@module-federation/bridge-shared": "0.0.0-next-20241106033302",
45
- "@module-federation/sdk": "0.0.0-next-20241106033302"
44
+ "@module-federation/bridge-shared": "0.0.0-next-20241106104434",
45
+ "@module-federation/sdk": "0.0.0-next-20241106104434"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "react": ">=16.9.0",
49
49
  "react-dom": ">=16.9.0",
50
- "react-router-dom": ">=4"
50
+ "react-router-dom": ">=4",
51
+ "@module-federation/runtime": "0.0.0-next-20241106104434"
51
52
  },
52
53
  "devDependencies": {
53
54
  "@testing-library/react": "15.0.7",
package/src/create.tsx CHANGED
@@ -1,11 +1,11 @@
1
1
  import React, { forwardRef } from 'react';
2
- import type { ProviderParams } from '@module-federation/bridge-shared';
3
- import { LoggerInstance } from './utils';
4
2
  import {
5
3
  ErrorBoundary,
6
4
  ErrorBoundaryPropsWithComponent,
7
5
  } from 'react-error-boundary';
6
+ import { LoggerInstance } from './utils';
8
7
  import RemoteApp from './remote';
8
+ import type { ProviderParams } from '@module-federation/bridge-shared';
9
9
 
10
10
  export interface RenderFnParams extends ProviderParams {
11
11
  dom?: any;
package/src/provider.tsx CHANGED
@@ -2,25 +2,37 @@ import { useLayoutEffect, useRef, useState } from 'react';
2
2
  import * as React from 'react';
3
3
  import ReactDOM from 'react-dom';
4
4
  import ReactDOMClient from 'react-dom/client';
5
- import { RouterContext } from './context';
6
5
  import type {
7
6
  ProviderParams,
8
7
  RenderFnParams,
9
8
  } from '@module-federation/bridge-shared';
10
- import { LoggerInstance, atLeastReact18 } from './utils';
11
9
  import { ErrorBoundary } from 'react-error-boundary';
10
+ import { RouterContext } from './context';
11
+ import { LoggerInstance, atLeastReact18 } from './utils';
12
12
 
13
+ type RenderParams = RenderFnParams & any;
14
+ type DestroyParams = {
15
+ dom: HTMLElement;
16
+ };
13
17
  type RootType = HTMLElement | ReactDOMClient.Root;
18
+
19
+ type BridgeHooks = {
20
+ beforeBridgeRender?: (params: RenderFnParams) => any;
21
+ afterBridgeRender?: (params: RenderFnParams) => any;
22
+ beforeBridgeDestroy?: (params: DestroyParams) => any;
23
+ afterBridgeDestroy?: (params: DestroyParams) => any;
24
+ };
25
+
14
26
  type ProviderFnParams<T> = {
15
27
  rootComponent: React.ComponentType<T>;
16
28
  render?: (
17
29
  App: React.ReactElement,
18
30
  id?: HTMLElement | string,
19
31
  ) => RootType | Promise<RootType>;
32
+ hooks?: BridgeHooks;
20
33
  };
21
-
22
34
  export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
23
- return () => {
35
+ return (params?: { hooks?: BridgeHooks }) => {
24
36
  const rootMap = new Map<any, RootType>();
25
37
  const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams }) => {
26
38
  const { appInfo, propsInfo, ...restProps } = info;
@@ -37,7 +49,7 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
37
49
  };
38
50
 
39
51
  return {
40
- async render(info: RenderFnParams & any) {
52
+ async render(info: RenderParams) {
41
53
  LoggerInstance.log(`createBridgeComponent render Info`, info);
42
54
  const {
43
55
  moduleName,
@@ -47,6 +59,21 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
47
59
  fallback,
48
60
  ...propsInfo
49
61
  } = info;
62
+
63
+ const beforeBridgeRender =
64
+ (bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeRender) ||
65
+ params?.hooks?.beforeBridgeRender;
66
+
67
+ // you can return a props object through beforeBridgeRender to pass additional props parameters
68
+ const beforeBridgeRenderRes =
69
+ beforeBridgeRender && beforeBridgeRender(info);
70
+ const extraProps =
71
+ beforeBridgeRenderRes &&
72
+ typeof beforeBridgeRenderRes === 'object' &&
73
+ beforeBridgeRenderRes?.extraProps
74
+ ? beforeBridgeRenderRes?.extraProps
75
+ : {};
76
+
50
77
  const rootComponentWithErrorBoundary = (
51
78
  // set ErrorBoundary for RawComponent rendering error, usually caused by user app rendering error
52
79
  <ErrorBoundary FallbackComponent={fallback}>
@@ -56,11 +83,11 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
56
83
  basename,
57
84
  memoryRoute,
58
85
  }}
59
- propsInfo={propsInfo}
86
+ propsInfo={{ ...propsInfo, ...extraProps } as T}
60
87
  />
61
88
  </ErrorBoundary>
62
89
  );
63
-
90
+ // call render function
64
91
  if (atLeastReact18(React)) {
65
92
  if (bridgeInfo?.render) {
66
93
  // in case bridgeInfo?.render is an async function, resolve this to promise
@@ -77,11 +104,24 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
77
104
  const renderFn = bridgeInfo?.render || ReactDOM.render;
78
105
  renderFn?.(rootComponentWithErrorBoundary, info.dom);
79
106
  }
107
+
108
+ const afterBridgeRender =
109
+ (bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
110
+ params?.hooks?.afterBridgeRender;
111
+ afterBridgeRender && afterBridgeRender(info);
80
112
  },
81
- async destroy(info: { dom: HTMLElement }) {
113
+
114
+ async destroy(info: DestroyParams) {
82
115
  LoggerInstance.log(`createBridgeComponent destroy Info`, {
83
116
  dom: info.dom,
84
117
  });
118
+
119
+ const beforeBridgeDestroy =
120
+ (bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeDestroy) ||
121
+ params?.hooks?.beforeBridgeDestroy;
122
+ beforeBridgeDestroy && beforeBridgeDestroy(info);
123
+
124
+ // call destroy function
85
125
  if (atLeastReact18(React)) {
86
126
  const root = rootMap.get(info.dom);
87
127
  (root as ReactDOMClient.Root)?.unmount();
@@ -89,6 +129,11 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
89
129
  } else {
90
130
  ReactDOM.unmountComponentAtNode(info.dom);
91
131
  }
132
+
133
+ const afterBridgeDestroy =
134
+ (bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
135
+ params?.hooks?.afterBridgeDestroy;
136
+ afterBridgeDestroy && afterBridgeDestroy(info);
92
137
  },
93
138
  rawComponent: bridgeInfo.rootComponent,
94
139
  __BRIDGE_FN__: (_args: T) => {},
@@ -7,9 +7,28 @@ import React, {
7
7
  } from 'react';
8
8
  import * as ReactRouterDOM from 'react-router-dom';
9
9
  import type { ProviderParams } from '@module-federation/bridge-shared';
10
- import { LoggerInstance, pathJoin } from '../utils';
11
10
  import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
12
11
  import { ErrorBoundaryPropsWithComponent } from 'react-error-boundary';
12
+ import { LoggerInstance, pathJoin } from '../utils';
13
+ import { getInstance } from '@module-federation/runtime';
14
+
15
+ export const getModuleName = (id: string) => {
16
+ // separate module name without detailed module path
17
+ // @vmok-e2e/edenx-demo-app2/button -> @vmok-e2e/edenx-demo-app2
18
+ const idArray = id.split('/');
19
+ if (idArray.length < 2) {
20
+ return id;
21
+ }
22
+ return idArray[0] + '/' + idArray[1];
23
+ };
24
+
25
+ export const getRootDomDefaultClassName = (moduleName: string) => {
26
+ if (!moduleName) {
27
+ return '';
28
+ }
29
+ const name = getModuleName(moduleName).replace(/\@/, '').replace(/\//, '-');
30
+ return `bridge-root-component-${name}`;
31
+ };
13
32
 
14
33
  declare const __APP_VERSION__: string;
15
34
  export interface RenderFnParams extends ProviderParams {
@@ -39,6 +58,8 @@ const RemoteAppWrapper = forwardRef(function (
39
58
  props: RemoteAppParams & RenderFnParams,
40
59
  ref,
41
60
  ) {
61
+ const host = getInstance();
62
+ LoggerInstance.log(`RemoteAppWrapper host >>>`, host);
42
63
  const RemoteApp = () => {
43
64
  LoggerInstance.log(`RemoteAppWrapper RemoteApp props >>>`, { props });
44
65
  const {
@@ -65,7 +86,7 @@ const RemoteAppWrapper = forwardRef(function (
65
86
  const providerReturn = providerInfo();
66
87
  providerInfoRef.current = providerReturn;
67
88
 
68
- const renderProps = {
89
+ let renderProps = {
69
90
  moduleName,
70
91
  dom: rootRef.current,
71
92
  basename,
@@ -78,6 +99,27 @@ const RemoteAppWrapper = forwardRef(function (
78
99
  `createRemoteComponent LazyComponent render >>>`,
79
100
  renderProps,
80
101
  );
102
+
103
+ if (
104
+ host?.bridgeHook &&
105
+ host?.bridgeHook?.lifecycle?.beforeBridgeRender
106
+ ) {
107
+ const beforeBridgeRenderRes =
108
+ host?.bridgeHook?.lifecycle?.beforeBridgeRender.emit({
109
+ ...renderProps,
110
+ });
111
+ const extraProps =
112
+ beforeBridgeRenderRes &&
113
+ typeof beforeBridgeRenderRes === 'object' &&
114
+ beforeBridgeRenderRes?.extraProps
115
+ ? beforeBridgeRenderRes?.extraProps
116
+ : {};
117
+
118
+ renderProps = {
119
+ ...renderProps,
120
+ ...extraProps,
121
+ } as any;
122
+ }
81
123
  providerReturn.render(renderProps);
82
124
  });
83
125
 
@@ -89,6 +131,19 @@ const RemoteAppWrapper = forwardRef(function (
89
131
  `createRemoteComponent LazyComponent destroy >>>`,
90
132
  { moduleName, basename, dom: renderDom.current },
91
133
  );
134
+ if (
135
+ host?.bridgeHook &&
136
+ host?.bridgeHook?.lifecycle?.afterBridgeDestroy
137
+ ) {
138
+ host?.bridgeHook?.lifecycle?.afterBridgeDestroy.emit({
139
+ moduleName,
140
+ dom: renderDom.current,
141
+ basename,
142
+ memoryRoute,
143
+ fallback,
144
+ ...resProps,
145
+ });
146
+ }
92
147
  providerInfoRef.current?.destroy({
93
148
  dom: renderDom.current,
94
149
  });
@@ -97,9 +152,11 @@ const RemoteAppWrapper = forwardRef(function (
97
152
  };
98
153
  }, []);
99
154
 
155
+ // bridge-remote-root
156
+ const rootComponentClassName = `${getRootDomDefaultClassName(moduleName)} ${props?.className}`;
100
157
  return (
101
158
  <div
102
- className={props?.className}
159
+ className={rootComponentClassName}
103
160
  style={props?.style}
104
161
  ref={rootRef}
105
162
  ></div>
package/src/router-v5.tsx CHANGED
@@ -2,7 +2,6 @@ import React, { useContext } from 'react';
2
2
  // The upper alias react-router-dom$ into this file avoids the loop
3
3
  // @ts-ignore
4
4
  import * as ReactRouterDom from 'react-router-dom/index.js';
5
-
6
5
  import { RouterContext } from './context';
7
6
  import { LoggerInstance } from './utils';
8
7
 
package/src/router.tsx CHANGED
@@ -59,7 +59,7 @@ function WrapperRouterProvider(
59
59
  return <RouterProvider router={MemeoryRouterInstance} />;
60
60
  } else {
61
61
  const BrowserRouterInstance = createBrowserRouter(routers, {
62
- basename: routerContextProps.basename,
62
+ basename: routerContextProps.basename || router?.basename,
63
63
  future: router.future,
64
64
  window: router.window,
65
65
  });