feat: add bridgeHook plugin system to support lifecycyle in bridge #2992
feat: add bridgeHook plugin system to support lifecycyle in bridge #2992
Conversation
…universe into feat/isolated-monitor
🦋 Changeset detectedLatest commit: e0b11d5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 27 packages
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 |
✅ Deploy Preview for module-federation-docs ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
There was a problem hiding this comment.
Summary
The pull request introduces a new "bridgeHook" plugin system to support lifecycle hooks in the module-deferation bridge, enabling better integration and support for more diverse use cases. The key changes include:
- Addition of lifecycle hooks such as "beforeBridgeRender", "afterBridgeRender", "beforeBridgeDestroy", and "afterBridgeDestroy" to the bridge-react and vue3-bridge packages, allowing for custom actions during the bridge's rendering and destruction processes.
- Enhancements to the FederationHost class in the runtime package to include the new bridgeHook plugin system, providing a way to extend the bridge's functionality.
- Improvements to the module handling logic, including a new utility function "processModuleAlias" to ensure consistent module name formatting.
- Updates to the SnapshotHandler class in the runtime package to include a new "afterLoadSnapshot" hook, enabling additional processing or handling of loaded snapshots.
- Refinements to the type definitions, such as the introduction of the "RemoteInfoCommon" interface, to better support the new lifecycle hook functionality.
These changes aim to provide more flexibility and extensibility to the module-deferation bridge, allowing for better integration with the overall application and support for a wider range of use cases.
File Summaries
| File | Summary |
|---|---|
| packages/bridge/bridge-react/src/create.tsx | The code changes introduce a new bridgeHook plugin system to support lifecycle hooks in the module-deferation bridge, allowing for more scene support with bridge capability. The changes include the addition of an ErrorBoundary component and updates to the ProviderParams type to enable this new functionality. |
| 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 extensibility in the bridge's capabilities, enabling support for additional use cases and scenarios. The changes include the implementation of several lifecycle hooks, such as "beforeBridgeRender", "afterBridgeRender", "beforeBridgeDestroy", and "afterBridgeDestroy", which can be used to perform custom actions during the bridge's rendering and destruction processes. |
| 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 scenarios where the bridge capability is used. |
| packages/bridge/bridge-react/src/router-v5.tsx | The code changes introduce a new plugin system for the bridge-react module, allowing for the addition of lifecycle hooks to support more use cases within the module-deferation bridge. The changes focus on enabling support for lifecycle hooks in the router-v5 component, which is a key part of the bridge-react module. |
| packages/bridge/bridge-react/src/router.tsx | The code changes introduce a new feature to support lifecycle hooks in the module-deferation bridge, allowing for more scene-specific functionality. The key modification is the addition of a new optional basename property to the createBrowserRouter function, which can be derived from the routerContextProps or the router object. |
| packages/bridge/bridge-react/src/utils.ts | The code changes introduce a new utility function getModuleName that extracts the module name from a given module ID, and a new function getRootDomDefaultClassName that generates a default CSS class name for the root component of a module based on its module name. These changes are likely part of a larger effort to add support for lifecycle hooks in the module-deferation bridge, which will enable more flexibility in handling different use cases. |
| packages/bridge/vue3-bridge/src/create.ts | The changes introduce a new plugin system for the bridge module, allowing for the support of lifecycle hooks in the module-deferation bridge. This enables the bridge to handle more complex scenarios and provide better integration with the overall application. |
| packages/bridge/vue3-bridge/src/provider.ts | The code changes introduce a new bridgeHook plugin system to support lifecycle hooks in the module-federation bridge. This allows for more flexibility and customization when using the bridge, enabling developers to hook into the bridge's lifecycle events and add additional functionality as needed. |
| packages/bridge/vue3-bridge/src/remoteApp.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 extensibility in handling different scenarios where the bridge capability is used. The changes include adding new lifecycle hooks such as "beforeBridgeRender", "afterBridgeRender", "beforeBridgeDestroy", and "afterBridgeDestroy" to enable better control and customization of the bridge's behavior. |
| 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 scenarios with 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 more scene support with bridge capability. The key modifications include adding a new utility function processModuleAlias to ensure a consistent module name format, and updating the wrapModuleFactory method to use the processed module name instead of the raw remote information. |
| packages/runtime/src/plugins/snapshot/SnapshotHandler.ts | The code changes introduce a new afterLoadSnapshot hook in the SnapshotHandler class. This hook is triggered after the remote snapshot is loaded, allowing for additional processing or handling of the loaded snapshot. The changes also refactor the existing snapshot loading logic to separate the assignment of the mSnapshot and gSnapshot variables, making the code more readable and maintainable. |
| packages/runtime/src/type/config.ts | The code changes introduce a new RemoteInfoCommon interface to the config.ts file, which defines the common properties for remote information. This change aims to support lifecycle hooks in the module-deferation bridge, enabling more scene-specific functionality to be added to the bridge capability. |
| 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 diverse scenarios by providing a way to extend its capabilities through plugins. |
| packages/runtime/src/utils/plugin.ts | The code 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 support for more diverse scenarios where the bridge capability is utilized, providing greater flexibility and extensibility to the application. |
| packages/runtime/src/utils/tool.ts | The code changes introduce a new utility 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 and the sub-path starts with a dot, ensuring the final module name is correctly formatted. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
| 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>; |
There was a problem hiding this comment.
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:
| 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.
There was a problem hiding this comment.
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
| SnapshotLifeCycleCyclePartial & | ||
| SharedLifeCycleCyclePartial & | ||
| RemoteLifeCycleCyclePartial & | ||
| ModuleLifeCycleCyclePartial & { | ||
| ModuleLifeCycleCyclePartial & | ||
| ModuleBridgeLifeCycleCyclePartial & { | ||
| name: string; | ||
| version?: string; | ||
| }; |
There was a problem hiding this comment.
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:
| 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 | |
| }; |
There was a problem hiding this comment.
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
| providerInfoRef.current?.destroy({ | ||
| moduleName, | ||
| dom: renderDom.current, | ||
| }); | ||
| } |
There was a problem hiding this comment.
The destroy call should handle errors gracefully to prevent potential crashes during cleanup. Consider wrapping it in a try-catch block:
| 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.
There was a problem hiding this comment.
Incremental Review
Comments posted: 9
Configuration
Squadron Mode: essential
Commits Reviewed
b25a91bd26bc94906c08848d36111af48e2a009d...7d6846c84022c63d0847a4e66af8bc06acd026da
Files Reviewed
- packages/bridge/bridge-react/src/provider.tsx
- packages/bridge/bridge-react/src/remote/index.tsx
- packages/bridge/bridge-react/src/utils.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
| async destroy(info: DestroyParams) { | ||
| LoggerInstance.log(`createBridgeComponent destroy Info`, { | ||
| dom: info.dom, | ||
| }); | ||
| const instance = getModuleInstance(info.moduleName); | ||
| LoggerInstance.log(`createBridgeComponent remote instance`, instance); | ||
| instance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit(info); | ||
|
|
There was a problem hiding this comment.
The destroy method has duplicate logging and similar lifecycle hook pattern. Consider extracting common logging logic:
| async destroy(info: DestroyParams) { | |
| LoggerInstance.log(`createBridgeComponent destroy Info`, { | |
| dom: info.dom, | |
| }); | |
| const instance = getModuleInstance(info.moduleName); | |
| LoggerInstance.log(`createBridgeComponent remote instance`, instance); | |
| instance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit(info); | |
| async destroy(info: DestroyParams) { | |
| const logContext = { | |
| action: 'destroy', | |
| dom: info.dom, | |
| moduleName: info.moduleName | |
| }; | |
| LoggerInstance.log('createBridgeComponent destroy info', logContext); | |
| const instance = getModuleInstance(info.moduleName); | |
| getLifecycleHook(instance, 'beforeBridgeDestroy')?.(info); |
| const getHostInstance = (moduleName: string) => { | ||
| let hostInstance: FederationHost | undefined = undefined; | ||
| const currentName = getModuleName(moduleName); | ||
| const remoteInstance = window?.__FEDERATION__?.__INSTANCES__?.find( | ||
| (v) => v.name === currentName, | ||
| ); | ||
|
|
||
| // @ts-ignore | ||
| if (remoteInstance && remoteInstance?.hostName) { | ||
| // @ts-ignore | ||
| hostInstance = window.__VMOK__.__INSTANCES__.find( | ||
| (instance) => instance.name === remoteInstance?.hostName, | ||
| ); | ||
| } | ||
| return hostInstance; | ||
| }; |
There was a problem hiding this comment.
The getHostInstance function contains multiple unsafe type assertions and optional chaining. Consider adding proper type guards and error handling:
| const getHostInstance = (moduleName: string) => { | |
| let hostInstance: FederationHost | undefined = undefined; | |
| const currentName = getModuleName(moduleName); | |
| const remoteInstance = window?.__FEDERATION__?.__INSTANCES__?.find( | |
| (v) => v.name === currentName, | |
| ); | |
| // @ts-ignore | |
| if (remoteInstance && remoteInstance?.hostName) { | |
| // @ts-ignore | |
| hostInstance = window.__VMOK__.__INSTANCES__.find( | |
| (instance) => instance.name === remoteInstance?.hostName, | |
| ); | |
| } | |
| return hostInstance; | |
| }; | |
| const getHostInstance = (moduleName: string): FederationHost | undefined => { | |
| if (!moduleName || !window?.__FEDERATION__?.__INSTANCES__) { | |
| return undefined; | |
| } | |
| const currentName = getModuleName(moduleName); | |
| const remoteInstance = window.__FEDERATION__.__INSTANCES__.find( | |
| (v) => v.name === currentName | |
| ); | |
| if (!remoteInstance?.hostName || !window.__VMOK__?.__INSTANCES__) { | |
| return undefined; | |
| } | |
| return window.__VMOK__.__INSTANCES__.find( | |
| (instance) => instance.name === remoteInstance.hostName | |
| ); | |
| }; |
| hostInstance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit({ | ||
| moduleName, | ||
| dom: renderDom.current, | ||
| basename, | ||
| memoryRoute, | ||
| fallback, | ||
| ...resProps, | ||
| }); |
There was a problem hiding this comment.
The lifecycle hook parameters are duplicated between beforeBridgeDestroy and afterBridgeDestroy. Consider extracting the common parameters into a shared object:
| hostInstance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit({ | |
| moduleName, | |
| dom: renderDom.current, | |
| basename, | |
| memoryRoute, | |
| fallback, | |
| ...resProps, | |
| }); | |
| const destroyParams = { | |
| moduleName, | |
| dom: renderDom.current, | |
| basename, | |
| memoryRoute, | |
| fallback, | |
| ...resProps, | |
| }; | |
| hostInstance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit(destroyParams); |
| export const getModuleName = (id: string) => { | ||
| if (!id) { | ||
| return id; | ||
| } | ||
| // 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]; | ||
| }; |
There was a problem hiding this comment.
The getModuleName function could be more robust and maintainable by using a regular expression pattern to handle module name extraction. Here's a suggested improvement:
| export const getModuleName = (id: string) => { | |
| if (!id) { | |
| return id; | |
| } | |
| // 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 getModuleName = (id: string) => { | |
| if (!id) { | |
| return id; | |
| } | |
| // Match scope/package pattern (e.g., @vmok-e2e/edenx-demo-app2) | |
| const match = id.match(/^(@[^/]+\/[^/]+)/); | |
| return match ? match[1] : id; | |
| }; |
This approach is more resilient to different module name patterns and easier to maintain.
| export const getRootDomDefaultClassName = (moduleName: string) => { | ||
| if (!moduleName) { | ||
| return ''; | ||
| } | ||
| const name = getModuleName(moduleName).replace(/\@/, '').replace(/\//, '-'); | ||
| return `bridge-root-component-${name}`; | ||
| }; |
There was a problem hiding this comment.
The getRootDomDefaultClassName function could benefit from improved string sanitization and TypeScript type safety:
| export const getRootDomDefaultClassName = (moduleName: string) => { | |
| if (!moduleName) { | |
| return ''; | |
| } | |
| const name = getModuleName(moduleName).replace(/\@/, '').replace(/\//, '-'); | |
| return `bridge-root-component-${name}`; | |
| }; | |
| export const getRootDomDefaultClassName = (moduleName: string): string => { | |
| if (!moduleName) { | |
| return ''; | |
| } | |
| const sanitizedName = getModuleName(moduleName) | |
| .replace(/[@/]/g, '-') | |
| .replace(/^-+/, ''); // Remove leading dashes | |
| return `bridge-root-component-${sanitizedName}`; | |
| }; |
This version:
- Uses a single regex replace for better performance
- Handles multiple occurrences of @ and /
- Removes potential leading dashes
- Adds explicit return type for better type safety
There was a problem hiding this comment.
Incremental Review
Comments posted: 6
Configuration
Squadron Mode: essential
Commits Reviewed
7d6846c84022c63d0847a4e66af8bc06acd026da...5177925fa52cf2780454005888454cf35dabe3d7
Files Reviewed
- packages/bridge/bridge-react/src/provider.tsx
- packages/bridge/bridge-react/src/remote/index.tsx
- packages/bridge/bridge-react/src/utils.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
| export const getHostInstance = (moduleName: string) => { | ||
| let hostInstance: FederationHost | undefined = undefined; | ||
| const currentName = getModuleName(moduleName); | ||
| const remoteInstance = window?.__FEDERATION__?.__INSTANCES__?.find( | ||
| (v) => v.name === currentName, | ||
| ); | ||
|
|
||
| // @ts-ignore | ||
| if (remoteInstance && remoteInstance?.hostName) { | ||
| hostInstance = window.__VMOK__.__INSTANCES__.find( | ||
| // @ts-ignore | ||
| (instance) => instance.name === remoteInstance?.hostName, | ||
| ); | ||
| } | ||
| return hostInstance; | ||
| }; |
There was a problem hiding this comment.
The getHostInstance function has several issues that should be addressed:
- Unsafe property access chains could lead to runtime errors. Use optional chaining consistently:
| export const getHostInstance = (moduleName: string) => { | |
| let hostInstance: FederationHost | undefined = undefined; | |
| const currentName = getModuleName(moduleName); | |
| const remoteInstance = window?.__FEDERATION__?.__INSTANCES__?.find( | |
| (v) => v.name === currentName, | |
| ); | |
| // @ts-ignore | |
| if (remoteInstance && remoteInstance?.hostName) { | |
| hostInstance = window.__VMOK__.__INSTANCES__.find( | |
| // @ts-ignore | |
| (instance) => instance.name === remoteInstance?.hostName, | |
| ); | |
| } | |
| return hostInstance; | |
| }; | |
| export const getHostInstance = (moduleName: string) => { | |
| const currentName = getModuleName(moduleName); | |
| const remoteInstance = window?.__FEDERATION__?.__INSTANCES__?.find( | |
| (v) => v.name === currentName, | |
| ); | |
| if (remoteInstance?.hostName) { | |
| return window?.__VMOK__?.__INSTANCES__?.find( | |
| (instance) => instance.name === remoteInstance.hostName, | |
| ); | |
| } | |
| return undefined; | |
| }; |
This improves:
- Type safety by removing @ts-ignore
- Null checks with consistent optional chaining
- Code readability with early return
- Removes unnecessary variable declaration
| export const getRemoteInstance = (moduleName: string) => { | ||
| const moduleNameWithoutExpose = getModuleName(moduleName); | ||
| const instance = window?.__FEDERATION__?.__INSTANCES__?.find( | ||
| (v) => v.name === moduleNameWithoutExpose, | ||
| ); | ||
| return instance; | ||
| }; |
There was a problem hiding this comment.
The getRemoteInstance function could be simplified and made more type-safe:
| export const getRemoteInstance = (moduleName: string) => { | |
| const moduleNameWithoutExpose = getModuleName(moduleName); | |
| const instance = window?.__FEDERATION__?.__INSTANCES__?.find( | |
| (v) => v.name === moduleNameWithoutExpose, | |
| ); | |
| return instance; | |
| }; | |
| export const getRemoteInstance = (moduleName: string) => { | |
| const moduleNameWithoutExpose = getModuleName(moduleName); | |
| return window?.__FEDERATION__?.__INSTANCES__?.find( | |
| (instance) => instance.name === moduleNameWithoutExpose, | |
| ) ?? undefined; | |
| }; |
This improves:
- Explicit return type with nullish coalescing
- Consistent parameter naming
- More descriptive variable name for the find callback
| const name = getModuleName(moduleName).replace(/\@/, '').replace(/\//, '-'); | ||
| return `bridge-root-component-${name}`; | ||
| }; |
There was a problem hiding this comment.
The string manipulation in this function could be more robust using a regular expression:
| const name = getModuleName(moduleName).replace(/\@/, '').replace(/\//, '-'); | |
| return `bridge-root-component-${name}`; | |
| }; | |
| const name = getModuleName(moduleName).replace(/[@/]/g, '-'); | |
| return `bridge-root-component-${name}`; |
This improves:
- Single regex replacement instead of multiple calls
- More efficient string manipulation
- Maintains the same functionality with cleaner code
| export const getHostInstance = (moduleName: string) => { | ||
| let hostInstance: FederationHost | undefined = undefined; | ||
| const currentName = getModuleName(moduleName); | ||
| const remoteInstance = window?.__FEDERATION__?.__INSTANCES__?.find( |
There was a problem hiding this comment.
Consider possibly running in node
There was a problem hiding this comment.
Incremental Review
Comments posted: 6
Configuration
Squadron Mode: essential
Commits Reviewed
5177925fa52cf2780454005888454cf35dabe3d7...afca10800fce591a5594cdcca04df1e2a944b5d1
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
| type RenderParams = RenderFnParams & any; | ||
| type DestroyParams = { |
There was a problem hiding this comment.
The RenderParams type extends RenderFnParams with any, which reduces type safety. Consider being more specific about additional parameters:
| type RenderParams = RenderFnParams & any; | |
| type DestroyParams = { | |
| type RenderParams = RenderFnParams & { | |
| // Add specific additional parameters here | |
| [key: string]: unknown; // If truly extensible is needed | |
| }; |
| const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams }) => { | ||
| const { appInfo, propsInfo, ...restProps } = info; | ||
| const { moduleName, memoryRoute, basename = '/' } = appInfo; |
There was a problem hiding this comment.
The destructuring in RawComponent includes ...restProps but it's not used in the type definition. Add proper typing for additional props:
| const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams }) => { | |
| const { appInfo, propsInfo, ...restProps } = info; | |
| const { moduleName, memoryRoute, basename = '/' } = appInfo; | |
| const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams; [key: string]: unknown }) => { | |
| const { appInfo, propsInfo, ...restProps } = info; | |
| const { moduleName, memoryRoute, basename = '/' } = appInfo; |
| import { LoggerInstance, pathJoin, getRootDomDefaultClassName } from '../utils'; | ||
| import { getInstance } from '@module-federation/runtime'; | ||
|
|
||
| declare const __APP_VERSION__: string; |
There was a problem hiding this comment.
The __APP_VERSION__ declaration lacks a JSDoc comment explaining its purpose and expected format. Add documentation since it appears to be an important global constant: ```suggestion
/** Application version identifier injected during build time */
declare const APP_VERSION: string;
For the second code block (lines 60-66):
| @@ -59,13 +60,15 @@ const RemoteAppWrapper = forwardRef(function ( | |||
|
|
|||
| const renderDom: React.MutableRefObject<HTMLElement | null> = useRef(null); | |||
| const providerInfoRef = useRef<any>(null); | |||
There was a problem hiding this comment.
The providerInfoRef uses any type which reduces type safety. Consider creating a proper interface for the provider info: ```suggestion
const providerInfoRef = useRef<ProviderParams | null>(null);
| const renderDom: React.MutableRefObject<HTMLElement | null> = useRef(null); | ||
| const providerInfoRef = useRef<any>(null); | ||
| const hostInstance = getInstance(); | ||
| LoggerInstance.log(`RemoteAppWrapper hostInstance >>>`, hostInstance); |
There was a problem hiding this comment.
Using string concatenation in logs makes it harder to parse and filter logs. Use object notation instead: ```suggestion
LoggerInstance.log('RemoteAppWrapper hostInstance', { hostInstance });
There was a problem hiding this comment.
Incremental Review
Comments posted: 7
Configuration
Squadron Mode: essential
Commits Reviewed
afca10800fce591a5594cdcca04df1e2a944b5d1...92368fce91493967859d54e8aa9ac109d9cea82f
Files Reviewed
- packages/bridge/bridge-react/src/provider.tsx
- packages/bridge/vue3-bridge/src/provider.ts
- packages/bridge/vue3-bridge/src/remoteApp.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
| const beforeBridgeRenderRes = | ||
| instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info) || {}; |
There was a problem hiding this comment.
The beforeBridgeRender hook result should be properly type-checked. Consider adding type safety:
| const beforeBridgeRenderRes = | |
| instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info) || {}; | |
| const beforeBridgeRenderRes = ( | |
| instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info) || {} | |
| ) as { extraProps?: Record<string, any> }; |
| app.mount(info.dom); | ||
| } | ||
|
|
||
| instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info) || {}; |
There was a problem hiding this comment.
The afterBridgeRender hook has an unnecessary || {} that doesn't serve any purpose since the result isn't used:
| instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info) || {}; | |
| instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info); |
| memoryRoute: props.memoryRoute, | ||
| }); | ||
|
|
||
| (providerInfoRef.value as any)?.destroy({ dom: rootRef.value }); |
There was a problem hiding this comment.
The type assertion and optional chaining could be improved with proper type checking:
| (providerInfoRef.value as any)?.destroy({ dom: rootRef.value }); | |
| if (providerInfoRef.value && typeof providerInfoRef.value.destroy === 'function') { | |
| providerInfoRef.value.destroy({ dom: rootRef.value }); | |
| } |
| return () => { | ||
| const rootMap = new Map<any, RootType>(); | ||
| const instance = getInstance(); | ||
| LoggerInstance.log(`createBridgeComponent remote instance`, instance); |
There was a problem hiding this comment.
instance may be null. What exception message is thrown for null
Description
feat: support lifecycyle hooks in module-deferation bridge so that we can support more scene with bridge capability
Related Issue
Types of changes
Checklist