Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add bridgeHook plugin system to support lifecycyle in bridge #2992

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3118053
feat: add hook when snapshot is ready
nyqykk Aug 15, 2024
3082116
feat: support isolated report
nyqykk Aug 22, 2024
f716f18
chore: merge main
nyqykk Aug 22, 2024
edaffa2
Merge branch 'main' into feat/isolated-monitor
nyqykk Aug 26, 2024
62480b6
feat: support bridge lifecycle
nyqykk Aug 30, 2024
c868988
Merge branch 'feat/isolated-monitor' of github.com:module-federation/…
nyqykk Aug 30, 2024
cf83897
chore: modify bridge lifecycle
nyqykk Aug 30, 2024
aa05fc5
chore: change symbol name for module
nyqykk Sep 2, 2024
8aebc66
chore: sync main code
nyqykk Sep 3, 2024
e414ded
feat: add vue3 bridge lifecycle
nyqykk Sep 3, 2024
f575ec7
chore: export bridge plugin type
nyqykk Sep 4, 2024
fe9ad08
Merge branch 'main' into feat/isolated-monitor
nyqykk Sep 5, 2024
7257784
chore: sync branch
nyqykk Sep 5, 2024
74f057a
chore: merge main branch
danpeen Sep 14, 2024
14a30fa
fix: fix router ci failed issue
danpeen Sep 14, 2024
b47ea80
feat: update bridge render hook name
danpeen Sep 18, 2024
b02d9f0
chore: merge main branch
danpeen Sep 19, 2024
93627d9
chore: merge main branch
danpeen Sep 23, 2024
5e33da2
feat: update bridge hook
danpeen Sep 23, 2024
83e54ad
feat: update bridge lifecycle register logic in bridge-vue
danpeen Sep 23, 2024
2fac2ea
fix: bridge should use raw basename from application router itself
danpeen Sep 24, 2024
4e319bb
Merge branch 'main' into feat/bridge-lifecycle-hook
ScriptedAlchemy Sep 25, 2024
a891716
feat: add params to pass bridge hooks
danpeen Sep 30, 2024
5c7f0be
chore: merge main branch
danpeen Sep 30, 2024
a6c9c97
feat: add afterBridgeRender hook and afterBridgeDestroy hook
danpeen Oct 10, 2024
10bc78b
feat: receive extraProps from rederhook
danpeen Oct 15, 2024
19acf8b
feat: receive extraProps from rederhook update
danpeen Oct 15, 2024
25d850b
feat: add default className for bridge root component
danpeen Oct 18, 2024
8588609
chore: merge main branch
danpeen Oct 18, 2024
de94715
chore: bump peerDependency for react and react-dom verison >=17
danpeen Oct 21, 2024
fc7b133
chore: reset
danpeen Oct 21, 2024
f673f69
feat: add bridgeHook in runtime core
danpeen Nov 1, 2024
4431f2e
fix: add bridgehook type
danpeen Nov 1, 2024
324fcbc
feat: add bridgeHook when register plugins
danpeen Nov 4, 2024
93f3103
chore: clean code
danpeen Nov 5, 2024
d779f32
fix: fix bridge unit test failed
danpeen Nov 6, 2024
02ff2b2
chore: merge branch main
danpeen Nov 6, 2024
cd40591
chore: delete useless changes
danpeen Nov 6, 2024
8ff7ef6
chore: optimization types
danpeen Nov 7, 2024
dfb6d77
chore: optimization types
danpeen Nov 7, 2024
f2e9624
feat: add bridge hook type
danpeen Nov 7, 2024
b25a91b
feat: add moduleName to destory function
danpeen Nov 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/great-feet-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@module-federation/bridge-react': patch
'@module-federation/bridge-vue3': patch
'@module-federation/runtime': patch
---

feat: feat: support lifecycyle hooks in module-deferation bridge
3 changes: 2 additions & 1 deletion packages/bridge/bridge-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0",
"react-router-dom": ">=4"
"react-router-dom": ">=4",
"@module-federation/runtime": "workspace:*"
},
"devDependencies": {
"@testing-library/react": "15.0.7",
Expand Down
4 changes: 2 additions & 2 deletions packages/bridge/bridge-react/src/create.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { forwardRef } from 'react';
import type { ProviderParams } from '@module-federation/bridge-shared';
import { LoggerInstance } from './utils';
import {
ErrorBoundary,
ErrorBoundaryPropsWithComponent,
} from 'react-error-boundary';
import { LoggerInstance } from './utils';
import RemoteApp from './remote';
import type { ProviderParams } from '@module-federation/bridge-shared';

export interface RenderFnParams extends ProviderParams {
dom?: any;
Expand Down
61 changes: 53 additions & 8 deletions packages/bridge/bridge-react/src/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,37 @@ import { useLayoutEffect, useRef, useState } from 'react';
import * as React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMClient from 'react-dom/client';
import { RouterContext } from './context';
import type {
ProviderParams,
RenderFnParams,
} from '@module-federation/bridge-shared';
import { LoggerInstance, atLeastReact18 } from './utils';
import { ErrorBoundary } from 'react-error-boundary';
import { RouterContext } from './context';
import { LoggerInstance, atLeastReact18 } from './utils';

type RenderParams = RenderFnParams & any;
type DestroyParams = {
dom: HTMLElement;
};
type RootType = HTMLElement | ReactDOMClient.Root;

type BridgeHooks = {
beforeBridgeRender?: (params: RenderFnParams) => any;
zhoushaw marked this conversation as resolved.
Show resolved Hide resolved
afterBridgeRender?: (params: RenderFnParams) => any;
beforeBridgeDestroy?: (params: DestroyParams) => any;
afterBridgeDestroy?: (params: DestroyParams) => any;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BridgeHooks interface could benefit from standardizing the parameters. Consider creating a base params type and extending it:

Suggested change
type BridgeHooks = {
beforeBridgeRender?: (params: RenderFnParams) => any;
afterBridgeRender?: (params: RenderFnParams) => any;
beforeBridgeDestroy?: (params: DestroyParams) => any;
afterBridgeDestroy?: (params: DestroyParams) => any;
};
type BaseBridgeParams = {
dom: HTMLElement;
};
type BridgeHooks = {
beforeBridgeRender?: (params: RenderFnParams) => any;
afterBridgeRender?: (params: RenderFnParams) => any;
beforeBridgeDestroy?: (params: BaseBridgeParams) => any;
afterBridgeDestroy?: (params: BaseBridgeParams) => any;
};


type ProviderFnParams<T> = {
rootComponent: React.ComponentType<T>;
render?: (
App: React.ReactElement,
id?: HTMLElement | string,
) => RootType | Promise<RootType>;
hooks?: BridgeHooks;
};

export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
return () => {
return (params?: { hooks?: BridgeHooks }) => {
const rootMap = new Map<any, RootType>();
const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams }) => {
const { appInfo, propsInfo, ...restProps } = info;
Expand All @@ -37,7 +49,7 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
};

return {
async render(info: RenderFnParams & any) {
async render(info: RenderParams) {
LoggerInstance.log(`createBridgeComponent render Info`, info);
const {
moduleName,
Expand All @@ -47,6 +59,21 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
fallback,
...propsInfo
} = info;

const beforeBridgeRender =
(bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeRender) ||
params?.hooks?.beforeBridgeRender;

// you can return a props object through beforeBridgeRender to pass additional props parameters
const beforeBridgeRenderRes =
beforeBridgeRender && beforeBridgeRender(info);
const extraProps =
beforeBridgeRenderRes &&
typeof beforeBridgeRenderRes === 'object' &&
beforeBridgeRenderRes?.extraProps
? beforeBridgeRenderRes?.extraProps
: {};

const rootComponentWithErrorBoundary = (
// set ErrorBoundary for RawComponent rendering error, usually caused by user app rendering error
<ErrorBoundary FallbackComponent={fallback}>
Expand All @@ -56,11 +83,11 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
basename,
memoryRoute,
}}
propsInfo={propsInfo}
propsInfo={{ ...propsInfo, ...extraProps } as T}
/>
</ErrorBoundary>
);

// call render function
if (atLeastReact18(React)) {
if (bridgeInfo?.render) {
// in case bridgeInfo?.render is an async function, resolve this to promise
Expand All @@ -77,18 +104,36 @@ export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
const renderFn = bridgeInfo?.render || ReactDOM.render;
renderFn?.(rootComponentWithErrorBoundary, info.dom);
}

const afterBridgeRender =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
params?.hooks?.afterBridgeRender;
afterBridgeRender && afterBridgeRender(info);
},
async destroy(info: { dom: HTMLElement }) {

async destroy(info: DestroyParams) {
LoggerInstance.log(`createBridgeComponent destroy Info`, {
dom: info.dom,
});

const beforeBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeDestroy) ||
params?.hooks?.beforeBridgeDestroy;
beforeBridgeDestroy && beforeBridgeDestroy(info);

// call destroy function
if (atLeastReact18(React)) {
const root = rootMap.get(info.dom);
(root as ReactDOMClient.Root)?.unmount();
rootMap.delete(info.dom);
} else {
ReactDOM.unmountComponentAtNode(info.dom);
}

const afterBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
params?.hooks?.afterBridgeDestroy;
afterBridgeDestroy && afterBridgeDestroy(info);
},
rawComponent: bridgeInfo.rootComponent,
__BRIDGE_FN__: (_args: T) => {},
Expand Down
63 changes: 60 additions & 3 deletions packages/bridge/bridge-react/src/remote/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,28 @@ import React, {
} from 'react';
import * as ReactRouterDOM from 'react-router-dom';
import type { ProviderParams } from '@module-federation/bridge-shared';
import { LoggerInstance, pathJoin } from '../utils';
import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
import { ErrorBoundaryPropsWithComponent } from 'react-error-boundary';
import { LoggerInstance, pathJoin } from '../utils';
import { getInstance } from '@module-federation/runtime';

export const getModuleName = (id: string) => {
// separate module name without detailed module path
// @vmok-e2e/edenx-demo-app2/button -> @vmok-e2e/edenx-demo-app2
const idArray = id.split('/');
if (idArray.length < 2) {
return id;
}
return idArray[0] + '/' + idArray[1];
};

export const getRootDomDefaultClassName = (moduleName: string) => {
if (!moduleName) {
return '';
}
const name = getModuleName(moduleName).replace(/\@/, '').replace(/\//, '-');
return `bridge-root-component-${name}`;
};

declare const __APP_VERSION__: string;
export interface RenderFnParams extends ProviderParams {
Expand Down Expand Up @@ -39,6 +58,8 @@ const RemoteAppWrapper = forwardRef(function (
props: RemoteAppParams & RenderFnParams,
ref,
) {
const host = getInstance();
LoggerInstance.log(`RemoteAppWrapper host >>>`, host);
const RemoteApp = () => {
LoggerInstance.log(`RemoteAppWrapper RemoteApp props >>>`, { props });
const {
Expand All @@ -65,7 +86,7 @@ const RemoteAppWrapper = forwardRef(function (
const providerReturn = providerInfo();
providerInfoRef.current = providerReturn;

const renderProps = {
let renderProps = {
moduleName,
dom: rootRef.current,
basename,
Expand All @@ -78,6 +99,27 @@ const RemoteAppWrapper = forwardRef(function (
`createRemoteComponent LazyComponent render >>>`,
renderProps,
);

if (
host?.bridgeHook &&
host?.bridgeHook?.lifecycle?.beforeBridgeRender
) {
const beforeBridgeRenderRes =
host?.bridgeHook?.lifecycle?.beforeBridgeRender.emit({
...renderProps,
});
const extraProps =
beforeBridgeRenderRes &&
typeof beforeBridgeRenderRes === 'object' &&
beforeBridgeRenderRes?.extraProps
? beforeBridgeRenderRes?.extraProps
: {};

renderProps = {
...renderProps,
...extraProps,
} as any;
}
Comment on lines +103 to +122
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lifecycle hook handling could be simplified and made more type-safe. Consider extracting the beforeBridgeRender logic into a separate function and adding type guards:

Suggested change
if (
host?.bridgeHook &&
host?.bridgeHook?.lifecycle?.beforeBridgeRender
) {
const beforeBridgeRenderRes =
host?.bridgeHook?.lifecycle?.beforeBridgeRender.emit({
...renderProps,
});
const extraProps =
beforeBridgeRenderRes &&
typeof beforeBridgeRenderRes === 'object' &&
beforeBridgeRenderRes?.extraProps
? beforeBridgeRenderRes?.extraProps
: {};
renderProps = {
...renderProps,
...extraProps,
} as any;
}
const processBeforeBridgeRender = (host: any, renderProps: any) => {
if (!host?.bridgeHook?.lifecycle?.beforeBridgeRender) {
return renderProps;
}
const beforeBridgeRenderRes = host.bridgeHook.lifecycle.beforeBridgeRender.emit(renderProps);
if (!beforeBridgeRenderRes || typeof beforeBridgeRenderRes !== 'object') {
return renderProps;
}
return {
...renderProps,
...(beforeBridgeRenderRes.extraProps || {})
};
};
// Usage:
renderProps = processBeforeBridgeRender(host, renderProps);

providerReturn.render(renderProps);
});

Expand All @@ -89,6 +131,19 @@ const RemoteAppWrapper = forwardRef(function (
`createRemoteComponent LazyComponent destroy >>>`,
{ moduleName, basename, dom: renderDom.current },
);
if (
host?.bridgeHook &&
host?.bridgeHook?.lifecycle?.afterBridgeDestroy
) {
host?.bridgeHook?.lifecycle?.afterBridgeDestroy.emit({
moduleName,
dom: renderDom.current,
basename,
memoryRoute,
fallback,
...resProps,
});
}
Comment on lines +134 to +146
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the beforeBridgeRender hook, the afterBridgeDestroy hook handling could be extracted and simplified. The null checks could be combined:

Suggested change
if (
host?.bridgeHook &&
host?.bridgeHook?.lifecycle?.afterBridgeDestroy
) {
host?.bridgeHook?.lifecycle?.afterBridgeDestroy.emit({
moduleName,
dom: renderDom.current,
basename,
memoryRoute,
fallback,
...resProps,
});
}
if (host?.bridgeHook?.lifecycle?.afterBridgeDestroy) {
const destroyParams = {
moduleName,
dom: renderDom.current,
basename,
memoryRoute,
fallback,
...resProps,
};
host.bridgeHook.lifecycle.afterBridgeDestroy.emit(destroyParams);
}

providerInfoRef.current?.destroy({
dom: renderDom.current,
});
Expand All @@ -97,9 +152,11 @@ const RemoteAppWrapper = forwardRef(function (
};
}, []);

// bridge-remote-root
const rootComponentClassName = `${getRootDomDefaultClassName(moduleName)} ${props?.className}`;
return (
<div
className={props?.className}
className={rootComponentClassName}
style={props?.style}
ref={rootRef}
></div>
Comment on lines +157 to 163
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The className concatenation could be improved to handle undefined className prop. Also, consider using a more semantic HTML element:

Suggested change
const rootComponentClassName = `${getRootDomDefaultClassName(moduleName)} ${props?.className}`;
return (
<div
className={props?.className}
className={rootComponentClassName}
style={props?.style}
ref={rootRef}
></div>
const rootComponentClassName = [
getRootDomDefaultClassName(moduleName),
props?.className
].filter(Boolean).join(' ');
return (
<main
className={rootComponentClassName}
style={props?.style}
ref={rootRef}
data-bridge-component={moduleName}
/>
);

Expand Down
1 change: 0 additions & 1 deletion packages/bridge/bridge-react/src/router-v5.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useContext } from 'react';
// The upper alias react-router-dom$ into this file avoids the loop
// @ts-ignore
import * as ReactRouterDom from 'react-router-dom/index.js';

import { RouterContext } from './context';
import { LoggerInstance } from './utils';

Expand Down
2 changes: 1 addition & 1 deletion packages/bridge/bridge-react/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function WrapperRouterProvider(
return <RouterProvider router={MemeoryRouterInstance} />;
} else {
const BrowserRouterInstance = createBrowserRouter(routers, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The router configuration lacks TypeScript type definitions which could lead to runtime errors. Consider adding proper type annotations for the router configuration object.

basename: routerContextProps.basename,
basename: routerContextProps.basename || router?.basename,
future: router.future,
window: router.window,
});
Comment on lines 61 to 65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The createBrowserRouter configuration should include error handling for missing or undefined properties. Here's a safer implementation:

Suggested change
const BrowserRouterInstance = createBrowserRouter(routers, {
basename: routerContextProps.basename,
basename: routerContextProps.basename || router?.basename,
future: router.future,
window: router.window,
});
const BrowserRouterInstance = createBrowserRouter(routers, {
basename: routerContextProps?.basename || router?.basename || '/',
future: router?.future || {},
window: router?.window || (typeof window !== 'undefined' ? window : undefined),
});

This ensures the router won't throw errors if properties are undefined and provides sensible defaults.

Expand Down
3 changes: 2 additions & 1 deletion packages/bridge/vue3-bridge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
},
"peerDependencies": {
"vue": "=3",
"vue-router": "=3"
"vue-router": "=3",
"@module-federation/runtime": "workspace:*"
},
"dependencies": {
"@module-federation/bridge-shared": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion packages/bridge/vue3-bridge/src/create.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineAsyncComponent, h } from 'vue';
import { useRoute } from 'vue-router';
import RemoteApp from './remoteApp.jsx';
import { LoggerInstance } from './utils.js';
import { useRoute } from 'vue-router';

declare const __APP_VERSION__: string;

Expand Down
45 changes: 44 additions & 1 deletion packages/bridge/vue3-bridge/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,51 @@ import { LoggerInstance } from './utils';

declare const __APP_VERSION__: string;

type DestroyParams = {
dom: HTMLElement;
};

type BridgeHooks = {
beforeBridgeRender?: (params: RenderFnParams) => any;
afterBridgeRender?: (params: RenderFnParams) => any;
beforeBridgeDestroy?: (params: DestroyParams) => any;
afterBridgeDestroy?: (params: DestroyParams) => any;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BridgeHooks type could be more strongly typed by including the expected return type for beforeBridgeRender. Since it can return extraProps, consider:

Suggested change
type BridgeHooks = {
beforeBridgeRender?: (params: RenderFnParams) => any;
afterBridgeRender?: (params: RenderFnParams) => any;
beforeBridgeDestroy?: (params: DestroyParams) => any;
afterBridgeDestroy?: (params: DestroyParams) => any;
};
type BridgeHooks = {
beforeBridgeRender?: (params: RenderFnParams) => { extraProps?: Record<string, any> } | void;
afterBridgeRender?: (params: RenderFnParams) => void;
beforeBridgeDestroy?: (params: DestroyParams) => void;
afterBridgeDestroy?: (params: DestroyParams) => void;
};


export function createBridgeComponent(bridgeInfo: any) {
const rootMap = new Map();
return () => {
return (params: { hooks?: BridgeHooks }) => {
return {
__APP_VERSION__,
render(info: RenderFnParams) {
LoggerInstance.log(`createBridgeComponent render Info`, info);
const app = Vue.createApp(bridgeInfo.rootComponent);
rootMap.set(info.dom, app);
// bridgeInfo?.renderLifecycle?.(info);
const beforeBridgeRender =
(bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeRender) ||
params?.hooks?.beforeBridgeRender;

// you can return a props object through beforeBridgeRender to pass additional props parameters
const beforeBridgeRenderRes =
beforeBridgeRender && beforeBridgeRender(info);
const extraProps =
beforeBridgeRenderRes &&
typeof beforeBridgeRenderRes === 'object' &&
beforeBridgeRenderRes?.extraProps
? beforeBridgeRenderRes?.extraProps
: {};

const appOptions = bridgeInfo.appOptions({
basename: info.basename,
memoryRoute: info.memoryRoute,
...extraProps,
});

const history = info.memoryRoute
? VueRouter.createMemoryHistory(info.basename)
: VueRouter.createWebHistory(info.basename);

const router = VueRouter.createRouter({
...appOptions.router.options,
history,
Expand All @@ -42,11 +70,26 @@ export function createBridgeComponent(bridgeInfo: any) {
app.use(router);
app.mount(info.dom);
}

const afterBridgeRender =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
params?.hooks?.afterBridgeRender;
Comment on lines +74 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bug in the afterBridgeRender hook assignment. It's incorrectly using afterBridgeDestroy from bridgeInfo.hooks:

Suggested change
const afterBridgeRender =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
params?.hooks?.afterBridgeRender;
const afterBridgeRender =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeRender) ||
params?.hooks?.afterBridgeRender;

afterBridgeRender && afterBridgeRender(info);
},
destroy(info: { dom: HTMLElement }) {
LoggerInstance.log(`createBridgeComponent destroy Info`, info);
const root = rootMap.get(info?.dom);

const beforeBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeDestroy) ||
params?.hooks?.beforeBridgeDestroy;
beforeBridgeDestroy && beforeBridgeDestroy(info);

root?.unmount();
const afterBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
params?.hooks?.afterBridgeDestroy;
afterBridgeDestroy && afterBridgeDestroy(info);
},
Comment on lines 79 to 93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The destroy method should clean up the rootMap entry after unmounting to prevent memory leaks:

Suggested change
destroy(info: { dom: HTMLElement }) {
LoggerInstance.log(`createBridgeComponent destroy Info`, info);
const root = rootMap.get(info?.dom);
const beforeBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeDestroy) ||
params?.hooks?.beforeBridgeDestroy;
beforeBridgeDestroy && beforeBridgeDestroy(info);
root?.unmount();
const afterBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
params?.hooks?.afterBridgeDestroy;
afterBridgeDestroy && afterBridgeDestroy(info);
},
destroy(info: { dom: HTMLElement }) {
LoggerInstance.log(`createBridgeComponent destroy Info`, info);
const root = rootMap.get(info?.dom);
const beforeBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.beforeBridgeDestroy) ||
params?.hooks?.beforeBridgeDestroy;
beforeBridgeDestroy && beforeBridgeDestroy(info);
root?.unmount();
rootMap.delete(info?.dom);
const afterBridgeDestroy =
(bridgeInfo?.hooks && bridgeInfo?.hooks.afterBridgeDestroy) ||
params?.hooks?.afterBridgeDestroy;
afterBridgeDestroy && afterBridgeDestroy(info);
},

};
};
Expand Down
Loading
Loading