angular-architects / module-federation-plugin

MIT License
715 stars 192 forks source link

Including React MFE inside Angular Shell #161

Open windbeneathyourwings opened 2 years ago

windbeneathyourwings commented 2 years ago

I have created a react mfe using standard webpack 5 module federation.

https://github.com/ng-druid/webpack-react

I have been successful loading that mfe as a script with loadRemoteModule using the below configuration in the shell.

loadRemoteModule({
  type: 'script',
  remoteEntry: 'http://127.0.0.1:8080/remoteEntry.js',
  exposedModule: './Button',
  remoteName: 'mfe_react_spear',
})

I created a component in the shell to render a react component based on the information I found in the below tutorial.

https://medium.com/@zacky_14189/embedding-react-components-in-angular-the-easy-way-60f796b68aef

That component can be seen here.

https://github.com/ng-druid/platform/blob/react-integration/modules/react/src/lib/components/mfe-react.component/mfe-react.component.ts

When the react mfe1 is loaded and output input in that component for render the below errors occur.

core.mjs:6464 ERROR Error: Objects are not valid as a React child (found: [object Module]). If you meant to render a collection of children, use an array instead.
    at throwOnInvalidObjectType (react-dom.development.js:13413:15)
    at reconcileChildFibers (react-dom.development.js:14313:7)
    at updateHostRoot (react-dom.development.js:17241:17)
    at beginWork (react-dom.development.js:18624:14)
    at HTMLUnknownElement.callCallback (react-dom.development.js:188:14)
    at ZoneDelegate.invokeTask (zone.js:406:1)
    at Object.onInvokeTask (core.mjs:25441:33)
    at ZoneDelegate.invokeTask (zone.js:405:1)
    at Zone.runTask (zone.js:178:1)
    at ZoneTask.invokeTask [as invoke] (zone.js:487:1)
defaultErrorLogger @ core.mjs:6464
handleError @ core.mjs:6511
next @ core.mjs:26008
(anonymous) @ Subscriber.js:110
_next @ Subscriber.js:60
next @ Subscriber.js:31
(anonymous) @ Subject.js:31
errorContext @ errorContext.js:19
next @ Subject.js:26
emit @ core.mjs:22387
(anonymous) @ core.mjs:25480
invoke @ zone.js:372
run @ zone.js:134
runOutsideAngular @ core.mjs:25353
onHandleError @ core.mjs:25480
handleError @ zone.js:376
runTask @ zone.js:181
invokeTask @ zone.js:487
invokeTask @ zone.js:1600
globalZoneAwareCallback @ zone.js:1626
invokeGuardedCallbackDev @ react-dom.development.js:237
invokeGuardedCallback @ react-dom.development.js:292
beginWork$1 @ react-dom.development.js:23203
performUnitOfWork @ react-dom.development.js:22157
workLoopSync @ react-dom.development.js:22130
performSyncWorkOnRoot @ react-dom.development.js:21756
scheduleUpdateOnFiber @ react-dom.development.js:21188
updateContainer @ react-dom.development.js:24373
(anonymous) @ react-dom.development.js:24758
unbatchedUpdates @ react-dom.development.js:21903
legacyRenderSubtreeIntoContainer @ react-dom.development.js:24757
hydrate @ react-dom.development.js:24823
render @ mfe-react.component.ts:62
ngAfterViewInit @ mfe-react.component.ts:48
callHook @ core.mjs:2525
callHooks @ core.mjs:2494
executeInitAndCheckHooks @ core.mjs:2445
refreshView @ core.mjs:9533
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
refreshEmbeddedViews @ core.mjs:10587
refreshView @ core.mjs:9486
refreshComponent @ core.mjs:10633
refreshChildComponents @ core.mjs:9258
refreshView @ core.mjs:9512
renderComponentOrTemplate @ core.mjs:9576
tickRootContext @ core.mjs:10807
detectChangesInRootView @ core.mjs:10832
detectChanges @ core.mjs:21403
tick @ core.mjs:26409
(anonymous) @ core.mjs:26264
invoke @ zone.js:372
onInvoke @ core.mjs:25454
invoke @ zone.js:371
run @ zone.js:134
run @ core.mjs:25308
next @ core.mjs:26263
(anonymous) @ Subscriber.js:110
_next @ Subscriber.js:60
next @ Subscriber.js:31
(anonymous) @ Subject.js:31
errorContext @ errorContext.js:19
next @ Subject.js:26
emit @ core.mjs:22387
checkStable @ core.mjs:25376
onHasTask @ core.mjs:25471
hasTask @ zone.js:426
_updateTaskCount @ zone.js:447
_updateTaskCount @ zone.js:274
runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:582
Promise.then (async)
scheduleMicroTask @ zone.js:565
scheduleTask @ zone.js:396
onScheduleTask @ zone.js:283
scheduleTask @ zone.js:386
scheduleTask @ zone.js:221
scheduleMicroTask @ zone.js:241
scheduleResolveOrReject @ zone.js:1266
resolvePromise @ zone.js:1204
(anonymous) @ zone.js:1120
r @ VM436 remoteEntry.js:1
r @ remoteEntry.js:1
(anonymous) @ 921.js:2
Show 80 more frames
core.mjs:6464 ERROR Error: An error was thrown inside one of your components, but React doesn't know what it was. This is likely due to browser flakiness. React does its best to preserve the "Pause on exceptions" behavior of the DevTools, which requires some DEV-mode only tricks. It's possible that these don't work in your browser. Try triggering the error in production mode, or switching to a modern browser. If you suspect that this is actually an issue with React, please file an issue.
    at Object.invokeGuardedCallbackDev (react-dom.development.js:246:19)
    at invokeGuardedCallback (react-dom.development.js:292:31)
    at beginWork$1 (react-dom.development.js:23203:7)
    at performUnitOfWork (react-dom.development.js:22157:12)
    at workLoopSync (react-dom.development.js:22130:22)
    at performSyncWorkOnRoot (react-dom.development.js:21756:9)
    at scheduleUpdateOnFiber (react-dom.development.js:21188:7)
    at updateContainer (react-dom.development.js:24373:3)
    at react-dom.development.js:24758:7
    at unbatchedUpdates (react-dom.development.js:21903:12)

I expect this to error.

However, it would be nice to know if anyone else has tried this and what solutions they might have.

That is rendering a react mfe inside an Angular shell.

It seems like I need to find a function in react that allows rendering of the compiled component to the react dom. Although I'm not even certain I need the react dom in the first place.

windbeneathyourwings commented 2 years ago

I was able to get this functioning.

The trick was the component name in the loaded module is "default". The default component is actually a function. Therefore, instead of passing component directly to ReactDOM.render() the result of the function was passed instead. I'm still not quite certain if the ReactDOM is needed or the function returns a dom element that can just be appended to the dom. I'm also not sure if that is the case if it would have unintended on consequences else where.