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 43 commits into
base: main
Choose a base branch
from

Conversation

danpeen
Copy link
Contributor

@danpeen danpeen commented Sep 24, 2024

Description

feat: support lifecycyle hooks in module-deferation bridge so that we can support more scene with bridge capability

Related Issue

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have updated the documentation.

Copy link

changeset-bot bot commented Sep 24, 2024

🦋 Changeset detected

Latest commit: dade92f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
Name Type
@module-federation/bridge-react Patch
@module-federation/bridge-vue3 Patch
@module-federation/runtime Patch
@module-federation/devtools Patch
@module-federation/data-prefetch Patch
@module-federation/dts-plugin Patch
@module-federation/nextjs-mf Patch
@module-federation/node Patch
@module-federation/retry-plugin Patch
@module-federation/runtime-tools Patch
@module-federation/webpack-bundler-runtime Patch
@module-federation/enhanced Patch
@module-federation/modern-js Patch
@module-federation/rspack Patch
@module-federation/rsbuild-plugin Patch
@module-federation/storybook-addon Patch
@module-federation/modernjsapp Patch
@module-federation/sdk Patch
@module-federation/managers Patch
@module-federation/manifest Patch
@module-federation/third-party-dts-extractor Patch
@module-federation/bridge-shared Patch
@module-federation/bridge-react-webpack-plugin Patch
@module-federation/error-codes Patch
@module-federation/esbuild Patch
@module-federation/utilities Patch
website-new Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

netlify bot commented Sep 24, 2024

Deploy Preview for module-federation-docs ready!

Name Link
🔨 Latest commit dade92f
🔍 Latest deploy log https://app.netlify.com/sites/module-federation-docs/deploys/672dd6cf30c5640008e19cf3
😎 Deploy Preview https://deploy-preview-2992--module-federation-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Contributor

@squadronai squadronai bot left a comment

Choose a reason for hiding this comment

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

Summary

The core changes in this pull request introduce a new "bridgeHook" plugin system to the module-federation bridge, allowing for better support of lifecycle hooks and more flexibility in integrating different scenes with the bridge capability.

The key changes include:

  • Addition of a new plugin system called "bridgeHook" that provides lifecycle hooks such as "beforeBridgeRender", "afterBridgeRender", "beforeBridgeDestroy", and "afterBridgeDestroy". These hooks can be used to extend the functionality of the bridge and handle more diverse scenarios.
  • Updates to various components, including create.tsx, provider.tsx, remote/index.tsx, router-v5.tsx, router.tsx, and their Vue3 counterparts, to integrate the new bridgeHook plugin system.
  • Introduction of new utility functions like getModuleName and getRootDomDefaultClassName to improve module name handling and CSS class generation.
  • Refactoring of the SnapshotHandler class to separate remote and global snapshot handling and add a new afterLoadSnapshot hook.
  • Standardization of remote information representation through the new RemoteInfoCommon interface.

These changes aim to enhance the module-federation bridge's capabilities, allowing for more flexibility and support for different use cases when integrating various scenes with the bridge.

File Summaries
File Summary
packages/bridge/bridge-react/src/create.tsx The code changes introduce a new plugin system to support lifecycle hooks in the module-federation bridge, allowing for more flexibility and support for different use cases. The changes include the addition of an ErrorBoundary component and updates to the ProviderParams type to accommodate the new plugin system.
packages/bridge/bridge-react/src/provider.tsx The code changes introduce a new plugin system called "bridgeHook" to support lifecycle hooks in the module-federation bridge. This allows for more flexibility and customization when integrating different scenes with the bridge capability. The changes include adding new lifecycle hooks such as "beforeBridgeRender", "afterBridgeRender", "beforeBridgeDestroy", and "afterBridgeDestroy" that can be used to extend the functionality of the bridge.
packages/bridge/bridge-react/src/remote/index.tsx The code changes introduce a new plugin system called "bridgeHook" to support lifecycle hooks in the module-deferation bridge. This allows for more flexibility and support for different use cases when working with the bridge capability.
packages/bridge/bridge-react/src/router-v5.tsx The code changes introduce a new plugin system for the bridge-react library, allowing for the addition of lifecycle hooks to support more use cases within the module-deferation bridge. The changes focus on integrating the new bridgeHook plugin system into the existing router-v5 module, enabling developers to leverage lifecycle hooks in their bridge-based applications.
packages/bridge/bridge-react/src/router.tsx The changes in this file introduce a new feature to support lifecycle hooks in the module-deferation bridge, allowing for more scene support with bridge capability. The key modification is the addition of a new parameter, basename, to the createBrowserRouter function, which now defaults to the routerContextProps.basename or the router?.basename value.
packages/bridge/bridge-react/src/utils.ts The code changes introduce two new utility functions: getModuleName and getRootDomDefaultClassName. The getModuleName function extracts the module name from a given module ID, separating the module name from the detailed module path. The getRootDomDefaultClassName function generates a default CSS class name for the root component of a module based on the module name.
packages/bridge/vue3-bridge/src/create.ts The changes introduce a new plugin system for the module-deferation bridge, allowing for the support of lifecycle hooks to enable more scene-specific functionality. The key modifications include adding the useRoute function from vue-router and updating the import order to improve readability.
packages/bridge/vue3-bridge/src/provider.ts The code changes introduce a new plugin system called "bridgeHook" to the module-deferation bridge, allowing for the support of lifecycle hooks. This enables more flexibility and customization in the bridge's behavior, such as executing custom logic before and after rendering or destroying the bridge component.
packages/bridge/vue3-bridge/src/remoteApp.tsx The code changes introduce a new bridgeHook plugin system to support lifecycle events in the module-federation bridge. The changes include adding hooks for before the bridge component is rendered and after it is destroyed, allowing for additional functionality to be added to the bridge lifecycle.
packages/runtime/src/core.ts The code changes introduce a new bridgeHook plugin system to the FederationHost class, which allows for the addition of lifecycle hooks to support more scenarios with the bridge capability. The new plugin system includes four hooks: beforeBridgeRender, afterBridgeRender, beforeBridgeDestroy, and afterBridgeDestroy, which can be used to extend the functionality of the bridge.
packages/runtime/src/embedded.ts The code changes introduce a new bridgeHook property to the FederationHost class, which allows for the support of lifecycle hooks in the module-deferation bridge. This enhancement enables the handling of more diverse scenarios that require bridge capabilities.
packages/runtime/src/module/index.ts The code changes introduce a new feature to support lifecycle hooks in the module-deferation bridge, allowing for better support of different scenarios with bridge capability. The key modifications include adding a new utility function processModuleAlias to ensure consistent module name formatting, and updating the wraperFactory method to use the processed module name instead of the raw exposed name.
packages/runtime/src/plugins/snapshot/SnapshotHandler.ts The code changes introduce a new afterLoadSnapshot hook in the SnapshotHandler class, which is called after a remote snapshot has been loaded. This allows for additional processing or handling of the loaded snapshot data. The changes also refactor the existing snapshot loading logic to separate the remote snapshot and global snapshot handling, and emit the afterLoadSnapshot hook at the end of the loadSnapshot method.
packages/runtime/src/type/config.ts The code changes introduce a new RemoteInfoCommon interface that defines the common properties for remote information, including alias, shareScope, and type. This change likely aims to standardize the representation of remote information across the codebase, potentially to support more flexible and extensible module federation capabilities.
packages/runtime/src/type/plugin.ts The code changes introduce a new plugin system for the module-deferation bridge, allowing for the support of lifecycle hooks. This enables the bridge to handle more complex scenarios by providing a way to extend its functionality through plugins that can tap into various lifecycle events.
packages/runtime/src/utils/plugin.ts The changes introduce a new bridgeHook property to the Module['host'] interface, allowing for the registration of lifecycle hooks in the module-deferation bridge. This enhancement enables better support for various scenes that utilize the bridge capability.
packages/runtime/src/utils/tool.ts The code changes introduce a new function called processModuleAlias that takes a module name and a sub-path, and returns a processed module name. The function handles cases where the module name ends with a slash or the sub-path starts with a dot, and combines the module name and sub-path to create a new module name.

Copy link
Contributor

@squadronai squadronai bot left a comment

Choose a reason for hiding this comment

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

Incremental Review

Comments posted: 23

Configuration

Squadron Mode: essential

Commits Reviewed

44ac346ef4212a17e4b2d611ba0e7948ba804947...4e319bb2d0708da2b1f89bad9f1b2aec4c1029c2

Files Reviewed
  • packages/bridge/bridge-react/src/create.tsx
  • packages/bridge/bridge-react/src/lifecycle.ts
  • packages/bridge/bridge-react/src/provider.tsx
  • packages/bridge/bridge-react/src/remote/index.tsx
  • packages/bridge/bridge-react/src/router-v6.tsx
  • packages/bridge/bridge-react/src/router.tsx
  • packages/bridge/vue3-bridge/src/create.ts
  • packages/bridge/vue3-bridge/src/lifecycle.ts
  • packages/bridge/vue3-bridge/src/provider.ts
  • packages/bridge/vue3-bridge/src/remoteApp.tsx
  • packages/runtime/src/helpers.ts
  • packages/runtime/src/module/index.ts
  • packages/runtime/src/plugins/snapshot/SnapshotHandler.ts
  • packages/runtime/src/type/config.ts
  • packages/runtime/src/type/plugin.ts
  • packages/runtime/src/utils/plugin.ts
  • packages/runtime/src/utils/tool.ts
Files Ignored

These files were ignored due to the filter in the squadron.yaml file.

  • .changeset/great-feet-rule.md
  • packages/bridge/bridge-react/package.json
  • packages/bridge/vue3-bridge/package.json
  • pnpm-lock.yaml

@module-federation module-federation deleted a comment from squadronai bot Sep 26, 2024
@module-federation module-federation deleted a comment from squadronai bot Sep 26, 2024
@module-federation module-federation deleted a comment from squadronai bot Sep 26, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 5, 2024
Copy link
Contributor

@squadronai squadronai bot left a comment

Choose a reason for hiding this comment

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

Incremental Review

Comments posted: 31

Configuration

Squadron Mode: essential

Commits Reviewed

8712967dd8594e99bb012c3ef5520d2e84ee3b58...cd405919b9dd79637fb73bd57e07d359739d7219

Files Reviewed
  • packages/runtime/src/module/index.ts
  • packages/runtime/src/plugins/snapshot/SnapshotHandler.ts
  • packages/bridge/bridge-react/src/provider.tsx
  • packages/bridge/vue3-bridge/src/provider.ts
  • packages/bridge/bridge-react/src/create.tsx
  • packages/bridge/bridge-react/src/remote/index.tsx
  • packages/bridge/vue3-bridge/src/create.ts
  • packages/bridge/vue3-bridge/src/remoteApp.tsx
  • packages/runtime/src/utils/plugin.ts
  • packages/runtime/src/utils/tool.ts
  • packages/runtime/src/type/config.ts
  • packages/bridge/bridge-react/src/router.tsx
  • packages/runtime/src/core.ts
  • packages/runtime/src/embedded.ts
Files Ignored

These files were ignored due to the filter in the squadron.yaml file.

  • .changeset/great-feet-rule.md
  • packages/bridge/bridge-react/package.json
  • packages/bridge/vue3-bridge/package.json
  • pnpm-lock.yaml

Comment on lines +139 to +141
// keep symbol for module name always one format
const symbolName = processModuleAlias(this.remoteInfo.name, expose);
const wrapModuleFactory = this.wraperFactory(moduleFactory, symbolName);
Copy link
Contributor

Choose a reason for hiding this comment

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

The symbolName generation and module factory wrapping could benefit from error handling to prevent potential runtime issues. Consider adding validation:

Suggested change
// keep symbol for module name always one format
const symbolName = processModuleAlias(this.remoteInfo.name, expose);
const wrapModuleFactory = this.wraperFactory(moduleFactory, symbolName);
// keep symbol for module name always one format
const symbolName = processModuleAlias(this.remoteInfo.name, expose);
assert(symbolName, `Failed to process module alias for ${expose}`);
const wrapModuleFactory = this.wraperFactory(moduleFactory, symbolName);
assert(wrapModuleFactory, `Failed to wrap module factory for ${symbolName}`);

Comment on lines 143 to 144
if (!loadFactory) {
return wrapModuleFactory;
Copy link
Contributor

Choose a reason for hiding this comment

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

The early return logic could be more explicit about what's being returned. Add a type annotation to improve code clarity:

Suggested change
if (!loadFactory) {
return wrapModuleFactory;
if (!loadFactory) {
return wrapModuleFactory as () => Promise<any>;
}

Comment on lines 96 to 104
remoteSnapshot: ModuleInfo;
from: 'global' | 'manifest';
}>('loadRemoteSnapshot'),
afterLoadSnapshot: new AsyncWaterfallHook<{
options: Options;
moduleInfo: Remote;
remoteSnapshot: ModuleInfo;
}>('afterLoadSnapshot'),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

The hook definitions could benefit from more specific typing. Consider using a discriminated union type for the 'from' parameter to make the code more type-safe and self-documenting:

Suggested change
remoteSnapshot: ModuleInfo;
from: 'global' | 'manifest';
}>('loadRemoteSnapshot'),
afterLoadSnapshot: new AsyncWaterfallHook<{
options: Options;
moduleInfo: Remote;
remoteSnapshot: ModuleInfo;
}>('afterLoadSnapshot'),
});
type SnapshotSource = {
type: 'global';
} | {
type: 'manifest';
manifestUrl: string;
};
// Then use in hook:
loadRemoteSnapshot: new AsyncWaterfallHook<{
options: Options;
moduleInfo: Remote;
remoteSnapshot: ModuleInfo;
from: SnapshotSource;
}>('loadRemoteSnapshot'),

Comment on lines +199 to 203
let mSnapshot;
let gSnapshot;
// global snapshot includes manifest or module info includes manifest
if (globalRemoteSnapshot) {
if (isManifestProvider(globalRemoteSnapshot)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The variable names 'mSnapshot' and 'gSnapshot' are not descriptive enough. Consider using more meaningful names to improve code readability:

Suggested change
let mSnapshot;
let gSnapshot;
// global snapshot includes manifest or module info includes manifest
if (globalRemoteSnapshot) {
if (isManifestProvider(globalRemoteSnapshot)) {
let moduleSnapshot;
let globalSnapshot;
// global snapshot includes manifest or module info includes manifest
if (globalRemoteSnapshot) {
if (isManifestProvider(gl

Comment on lines +271 to +275
await this.hooks.lifecycle.afterLoadSnapshot.emit({
options,
moduleInfo,
remoteSnapshot: mSnapshot,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

The afterLoadSnapshot hook could benefit from error handling to ensure the system remains in a consistent state even if the hook handlers fail. Consider wrapping the hook emission in a try-catch block:

Suggested change
await this.hooks.lifecycle.afterLoadSnapshot.emit({
options,
moduleInfo,
remoteSnapshot: mSnapshot,
});
try {
await this.hooks.lifecycle.afterLoadSnapshot.emit({
options,
moduleInfo,
remoteSnapshot: mSnapshot,
});
} catch (error) {
console.error('Failed to process afterLoadSnapshot hook:', error);
// Consider whether to re-throw or handle the error
}

Comment on lines 130 to 133
beforeBridgeRender: new SyncHook<[Record<string, any>], any>(),
afterBridgeRender: new SyncHook<[Record<string, any>], any>(),
beforeBridgeDestroy: new SyncHook<[Record<string, any>], any>(),
afterBridgeDestroy: new SyncHook<[Record<string, any>], 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 bridge hook lifecycle methods use a generic Record<string, any> type which is too permissive. Consider creating specific interfaces for each hook's payload to ensure type safety and better documentation. For example:

Suggested change
beforeBridgeRender: new SyncHook<[Record<string, any>], any>(),
afterBridgeRender: new SyncHook<[Record<string, any>], any>(),
beforeBridgeDestroy: new SyncHook<[Record<string, any>], any>(),
afterBridgeDestroy: new SyncHook<[Record<string, any>], any>(),
beforeBridgeRender: new SyncHook<[BridgeRenderContext], any>(),
afterBridgeRender: new SyncHook<[BridgeRenderResult], any>(),
beforeBridgeDestroy: new SyncHook<[BridgeDestroyContext], any>(),
afterBridgeDestroy: new SyncHook<[BridgeDestroyResult], any>(),

Comment on lines 130 to 133
beforeBridgeRender: new SyncHook<[Record<string, any>], any>(),
afterBridgeRender: new SyncHook<[Record<string, any>], any>(),
beforeBridgeDestroy: new SyncHook<[Record<string, any>], any>(),
afterBridgeDestroy: new SyncHook<[Record<string, any>], 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 return type 'any' in the SyncHook generic parameters is too loose and could lead to type-safety issues. Consider defining specific return types for each hook to make the API more predictable and maintainable.

For the second code block (lines 291-297):

Comment on lines 291 to 295
this.sharedHandler.hooks,
this.snapshotHandler.hooks,
this.loaderHook,
this.bridgeHook,
]);
Copy link
Contributor

Choose a reason for hiding this comment

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

The registerPlugins call is passing hooks as an array which makes the relationship between plugins and hooks implicit. Consider restructuring to use a more explicit mapping of plugins to their corresponding hooks, making the code more maintainable and easier to understand. For example:

Suggested change
this.sharedHandler.hooks,
this.snapshotHandler.hooks,
this.loaderHook,
this.bridgeHook,
]);
this.registerPlugins({
shared: this.sharedHandler.hooks,
snapshot: this.snapshotHandler.hooks,
loader: this.loaderHook,
bridge: this.bridgeHook,
});

Comment on lines 140 to 142
initOptions(...args: Parameters<IndexModule.FederationHost['initOptions']>) {
return this._getInstance().initOptions(...args);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The initOptions method could benefit from type safety by explicitly declaring its return type. Based on the pattern seen in other methods, suggest adding the return type:

Suggested change
initOptions(...args: Parameters<IndexModule.FederationHost['initOptions']>) {
return this._getInstance().initOptions(...args);
}
initOptions(...args: Parameters<IndexModule.FederationHost['initOptions']>): ReturnType<IndexModule.FederationHost['initOptions']> {
return this._getInstance().initOptions(...args);
}

Comment on lines +136 to +138
get bridgeHook() {
return this._getInstance().bridgeHook;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The bridgeHook getter lacks documentation explaining its purpose and usage. Since this appears to be part of a public API for lifecycle hooks, adding JSDoc would improve maintainability:

Suggested change
get bridgeHook() {
return this._getInstance().bridgeHook;
}
/**
* Gets the bridge hook instance that handles module federation bridge lifecycle events
* @returns The bridge hook instance
*/
get bridgeHook() {
return this._getInstance().bridgeHook;
}

Copy link
Contributor

@squadronai squadronai bot left a comment

Choose a reason for hiding this comment

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

Incremental Review

Comments posted: 4

Configuration

Squadron Mode: essential

Commits Reviewed

cd405919b9dd79637fb73bd57e07d359739d7219...8ff7ef654a77f4388ccb8e29dd95df9d3a447925

Files Reviewed
  • packages/bridge/bridge-react/src/provider.tsx
  • packages/runtime/src/core.ts
Files Ignored

These files were ignored due to the filter in the squadron.yaml file.

  • .changeset/great-feet-rule.md
  • packages/bridge/bridge-react/package.json
  • packages/bridge/vue3-bridge/package.json
  • pnpm-lock.yaml

Comment on lines +129 to +146
bridgeHook = new PluginSystem({
beforeBridgeRender: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
afterBridgeRender: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
beforeBridgeDestroy: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
afterBridgeDestroy: new SyncHook<
[Record<string, any>],
void | Record<string, 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 bridgeHook initialization could benefit from a dedicated interface to improve code organization and reusability. Extract the hook definitions into a separate interface:

Suggested change
bridgeHook = new PluginSystem({
beforeBridgeRender: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
afterBridgeRender: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
beforeBridgeDestroy: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
afterBridgeDestroy: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
});
interface BridgeHooks {
beforeBridgeRender: SyncHook<[Record<string, any>], void | Record<string, any>>;
afterBridgeRender: SyncHook<[Record<string, any>], void | Record<string, any>>;
beforeBridgeDestroy: SyncHook<[Record<string, any>], void | Record<string, any>>;
afterBridgeDestroy: SyncHook<[Record<string, any>], void | Record<string, any>>;
}
bridgeHook = new PluginSystem<BridgeHooks>({
beforeBridgeRender: new SyncHook(),
afterBridgeRender: new SyncHook(),
beforeBridgeDestroy: new SyncHook(),
afterBridgeDestroy: new SyncHook(),
});

Comment on lines +130 to +145
beforeBridgeRender: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
afterBridgeRender: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
beforeBridgeDestroy: new SyncHook<
[Record<string, any>],
void | Record<string, any>
>(),
afterBridgeDestroy: new SyncHook<
[Record<string, any>],
void | Record<string, 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 return types for the hooks (void | Record<string, any>) are inconsistent with typical lifecycle patterns. Consider standardizing the return types - lifecycle hooks typically either return void (for side effects) or a specific result type. If modification of the context is needed, it should be done through the context parameter rather than the return value.

@@ -126,6 +126,24 @@ export class FederationHost {
Promise<(() => Promise<Module>) | undefined>
>(),
});
bridgeHook = new PluginSystem({
Copy link
Contributor

Choose a reason for hiding this comment

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

The variable name bridgeHook could be more descriptive. Consider renaming to bridgeLifecycle or bridgePluginSystem to better reflect its purpose and functionality.

@danpeen danpeen changed the title feat: support lifecycyle hooks in module-deferation bridge feat: add bridgeHook plugin system to support lifecycyle in bridge Nov 7, 2024
Copy link
Contributor

@squadronai squadronai bot left a comment

Choose a reason for hiding this comment

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

Incremental Review

Comments posted: 1

Configuration

Squadron Mode: essential

Commits Reviewed

8ff7ef654a77f4388ccb8e29dd95df9d3a447925...dfb6d7761330c4fa21e067e8b770d57bc5da9a3f

Files Reviewed
  • packages/bridge/vue3-bridge/src/provider.ts
Files Ignored

These files were ignored due to the filter in the squadron.yaml file.

  • .changeset/great-feet-rule.md
  • packages/bridge/bridge-react/package.json
  • packages/bridge/vue3-bridge/package.json
  • pnpm-lock.yaml

Comment on lines +13 to +16
beforeBridgeRender?: (params: RenderFnParams) => void | Record<string, any>;
afterBridgeRender?: (params: RenderFnParams) => void | Record<string, any>;
beforeBridgeDestroy?: (params: DestroyParams) => void | Record<string, any>;
afterBridgeDestroy?: (params: DestroyParams) => void | Record<string, 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 hook types should be more consistent in their return types. Currently, all hooks allow returning Record<string, any>, but typically only beforeBridgeRender needs to return extra props. Consider:

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

This makes the API more explicit about which hooks can meaningfully return data.

@module-federation module-federation deleted a comment from squadronai bot Nov 7, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 7, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 7, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 7, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 7, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 7, 2024
@module-federation module-federation deleted a comment from squadronai bot Nov 7, 2024
Copy link
Contributor

@squadronai squadronai bot left a comment

Choose a reason for hiding this comment

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

Incremental Review

Comments posted: 2

Configuration

Squadron Mode: essential

Commits Reviewed

dfb6d7761330c4fa21e067e8b770d57bc5da9a3f...f2e962492ecaab4795c702beaa18acabeeabd49a

Files Reviewed
  • packages/runtime/src/type/plugin.ts
Files Ignored

These files were ignored due to the filter in the squadron.yaml file.

  • .changeset/great-feet-rule.md
  • packages/bridge/bridge-react/package.json
  • packages/bridge/vue3-bridge/package.json
  • pnpm-lock.yaml

Comment on lines +22 to +27
type ModuleBridgeLifeCycle = Module['host']['bridgeHook']['lifecycle'];
type ModuleBridgeLifeCycleCyclePartial = Partial<{
[k in keyof ModuleBridgeLifeCycle]: Parameters<
ModuleBridgeLifeCycle[k]['on']
>[0];
}>;
Copy link
Contributor

Choose a reason for hiding this comment

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

The type definition for ModuleBridgeLifeCycle and ModuleBridgeLifeCycleCyclePartial could be simplified using a helper type to reduce code duplication. Here's a suggested improvement:

Suggested change
type ModuleBridgeLifeCycle = Module['host']['bridgeHook']['lifecycle'];
type ModuleBridgeLifeCycleCyclePartial = Partial<{
[k in keyof ModuleBridgeLifeCycle]: Parameters<
ModuleBridgeLifeCycle[k]['on']
>[0];
}>;
type CreateLifeCyclePartial<T> = Partial<{
[K in keyof T]: Parameters<T[K]['on']>[0];
}>;
type ModuleBridgeLifeCycle = Module['host']['bridgeHook']['lifecycle'];
type ModuleBridgeLifeCycleCyclePartial = CreateLifeCyclePartial<ModuleBridgeLifeCycle>;

This pattern could be reused for other similar lifecycle type definitions, making the code more maintainable and reducing repetition.

Comment on lines 40 to 47
SnapshotLifeCycleCyclePartial &
SharedLifeCycleCyclePartial &
RemoteLifeCycleCyclePartial &
ModuleLifeCycleCyclePartial & {
ModuleLifeCycleCyclePartial &
ModuleBridgeLifeCycleCyclePartial & {
name: string;
version?: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

The plugin interface combines multiple lifecycle partials. Consider adding a descriptive type comment to explain the purpose of each lifecycle component and their relationships. Additionally, the optional version field could benefit from a more specific type if there are expected version formats:

Suggested change
SnapshotLifeCycleCyclePartial &
SharedLifeCycleCyclePartial &
RemoteLifeCycleCyclePartial &
ModuleLifeCycleCyclePartial & {
ModuleLifeCycleCyclePartial &
ModuleBridgeLifeCycleCyclePartial & {
name: string;
version?: string;
};
/**
* Plugin configuration interface combining multiple lifecycle hooks:
* - SnapshotLifeCycle: Handles snapshot-related events
* - SharedLifeCycle: Manages shared module events
* - RemoteLifeCycle: Controls remote module loading
* - ModuleLifeCycle: Core module lifecycle events
* - ModuleBridgeLifeCycle: Bridge-specific events
*/
type Plugin =
SnapshotLifeCycleCyclePartial &
SharedLifeCycleCyclePartial &
RemoteLifeCycleCyclePartial &
ModuleLifeCycleCyclePartial &
ModuleBridgeLifeCycleCyclePartial & {
name: string;
version?: `${number}.${number}.${number}`; // Semantic versioning format
};

Copy link
Contributor

@squadronai squadronai bot left a comment

Choose a reason for hiding this comment

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

Incremental Review

Comments posted: 2

Configuration

Squadron Mode: essential

Commits Reviewed

f2e962492ecaab4795c702beaa18acabeeabd49a...b25a91bd26bc94906c08848d36111af48e2a009d

Files Reviewed
  • packages/bridge/bridge-react/src/provider.tsx
  • packages/bridge/bridge-react/src/remote/index.tsx
Files Ignored

These files were ignored due to the filter in the squadron.yaml file.

  • .changeset/great-feet-rule.md
  • packages/bridge/bridge-react/package.json
  • packages/bridge/vue3-bridge/package.json
  • pnpm-lock.yaml

Comment on lines +13 to +17
type RenderParams = RenderFnParams & any;
type DestroyParams = {
moduleName: string;
dom: HTMLElement;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

The type definitions could be improved for better type safety and consistency:

  1. RenderParams using & any defeats TypeScript's type checking. Define explicit parameters instead.
  2. DestroyParams should align with the suggested BaseBridgeParams pattern.

Here's a suggested improvement:

Suggested change
type RenderParams = RenderFnParams & any;
type DestroyParams = {
moduleName: string;
dom: HTMLElement;
};
type RenderParams = RenderFnParams & {
// Add specific render parameters here
};
type DestroyParams = BaseBridgeParams & {
moduleName: string;
};

This maintains type safety while providing a consistent parameter structure across the bridge lifecycle hooks.

Comment on lines 147 to 151
providerInfoRef.current?.destroy({
moduleName,
dom: renderDom.current,
});
}
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 call should handle errors gracefully to prevent potential crashes during cleanup. Consider wrapping it in a try-catch block:

Suggested change
providerInfoRef.current?.destroy({
moduleName,
dom: renderDom.current,
});
}
try {
providerInfoRef.current?.destroy({
moduleName,
dom: renderDom.current,
});
} catch (error) {
console.error('Error during bridge component destruction:', error);
}

This ensures that any errors during cleanup won't propagate up and potentially break the application's unmounting process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants