Closed KyleThen closed 3 years ago
Hi @KyleThenTR,
you can do so, I done it in a simple POC where I've simple empty object state as the forRoot for the shell application and reducers are set as forFeature in my remote applications
so you can see the shell application has simple AppModule with routings are store initialization like that:
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot(APP_ROUTES),
StoreModule.forRoot({}),
environment.production ? [] : StoreDevtoolsModule.instrument({})
],
declarations: [
AppComponent,
NotFoundComponent
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
and on the remove feature modules that I'm loading with module-federation I'm initiating the feature reducer like that:
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(FLIGHTS_ROUTES),
StoreModule.forFeature('flight', TestReducer),
SharedLibModule,
PortalModule
],
declarations: [
HomeComponent,
FlightsSearchComponent
],
exports:[CommonModule]
})
export class FlightsModule { }
Querying the store is done in a normal way with selectors:
@Component({
selector: 'flights-home',
templateUrl: './home.component.html'
})
export class HomeComponent implements OnInit {
public score$: Observable<number>;
constructor(
private store: Store
) {
this.score$ = this.store.pipe(select(scoreSelector));
}
}
Hello @o-b-one can you share your POC repo.
Thanks
For reference, if you want to go this approach make sure to "share" @ngrx/store
in webpack.config.ts for any microFrontend consuming it as well as for the shell application.
If you don't do this, you will get a NullInjectorError: No provider for ReducerManager!
unless you provide the root store as well in the microApp.
Hey @o-b-one, I would really appreciate if you share a POC if you still have it.
I am stuck with NullInjectorError: No provider for ReducerManager!
error for the past week and cannot get rid of it. I am totally sure that I am "sharing" all @angular/*
and @ngrx/*
dependencies in both host and remote microfrontends. But nevertheless remote application cannot be bootstrapped without Store.ForRoot()
call (it registers RedecerManager
there).
@krzkz94, did you really just add ngrx store into share
in webpack config and it works without calling .ForRoot
?
@Appius I used forRoot
as it's a must, so you will need to:
ngrx/*
to webpack share StoreModule.forRoot({})
on the shell app moduleStoreModule.forFeature
or featureCreator on your mfe you can see this POC project
Hi @o-b-one, Thanks for answering!
you can see this POC project
Actually, that's exactly what I DON'T want to do. In this POC, every 'feature' microframework eventually do the following:
@NgModule({
imports: [
...
StoreModule.forRoot({}),
StoreModule.forFeature(feedFeatureKey, feedReducer),
...
],
providers: [],
bootstrap: [AppComponent],
})
This way, every microfrontend will have ITS OWN store and will not share it with shell application.
What I want to do is to have only ONE store, only ONE call StoreModule.ForRoot()
across all microfrontends.
I have done a very small poc how to reproduce this based on well-known https://github.com/manfredsteyer/multi-framework-micro-frontend:
My repo - https://github.com/Appius/multi-framework-micro-frontend Commit with all my changes: a3cff904820c512585fadd4121843cd154963590
All changes are super easy - adding ngrx to package json, to webpack config and registering store with StoreModule.forRoot()
and StoreModule.forFeature()
.
And after these changes, I got the same error NullInjectorError: No provider for ReducerManager!
.
Also, I tried to modify webpack share to include singleton: true
and eager: true
to all @ngrx/*
packages, but no luck!
@Appius In the POC I shared each application doesn't have its own store as eventually it's just calling forFeature
(via the BootstrapModule
- consumed by the shell via module-federation) and not forRoot
(via AppModule for dev purposes)
please raise if I missed something here.
That way you get:
Shell --------------> MFE Bootstrap Module
MFE AppModule---^
That means you need to have:
@ngrx/*
with singleton: true
StoreModule.forRoot({})
on you Shell AppModule
StoreModule.forFeature()
on each of your micro-frontend BootstrapModule
(Not the AppModule
)
on yourFew suggestions from my own experience with Micro-frontend and module-federation:
eager: true
as it will increase the remoteEntry.js
while injecting all dependencies. @o-b-one, thank you very much for help, I made it work!
The solution by @o-b-one worked for me. However, I also needed to add the following to my MFE and shell/consumer so the shell did not have the Error: No provider for ReducerManager
shared: share({
"@ngrx/store": {
requiredVersion: 'auto',
singleton: true
},
"@ngrx/effects": {
requiredVersion: 'auto',
singleton: true
},
...sharedMappings.getDescriptors()
})
Hi @o-b-one, I'm new on microfrontend architecture. I set the state and relatives actions, reducers and selectors into the Shell app and my goal is share the state with the other remote apps.
Can you give me a reference for achieve this goal? Because I have some questions and I'm looking for answers.
For example:
StoreModule.forFeature('flight', TestReducer),
Thank you so much.
Had issues where this worked locally, but when deployed the MFE would still NullInjectorError: NullInjectorError: No provider for e!
which seemed to tie back to Error: No provider for ReducerManager
. Upgraded to ng14 LTS (14.2.12) and that seemed to fix that error if anyone else is still having issues.
Hi @o-b-one, I'm new on microfrontend architecture. I set the state and relatives actions, reducers and selectors into the Shell app and my goal is share the state with the other remote apps.
Can you give me a reference for achieve this goal? Because I have some questions and I'm looking for answers.
For example:
StoreModule.forFeature('flight', TestReducer),
* Where TestReduces comes from? * Does remote app need also ngrx library in its package.json?
Thank you so much.
Have you made any progress here?
Have questions myself.
@Bryelmo @albmafini
I have been working with MFE for quite a long time. I can share from my experience that decoupling must be found to achieve proper independent MFEs.
Decoupling of MFEs achieved by:
About your questions: * Where TestReduces comes from? - Following bullets # 1 and # 2 - the MFE itself
* Does remote app need also ngrx library in its package.json? - Following bullet # 1 - the MFE itself, but you should put it in the shared
to avoid double load of NgRX and multiple instances of the store.
Angular example (Please avoid using shareAll)
React example
Hope I was able to help, keep rocking!
@o-b-one Why do you not recommend using shareAll in angular?
@o-b-one Why do you not recommend using shareAll in angular?
In general, and not just in Angular, for few reasons:
shareAll
makes Webpack to generate for each one of your project dependencies (based on package.json
) an asset. Meaning, that for your application to be bootstrapped, all those assets will need to be downloaded and load. That makes vendors.js
size to be reduced while producing many additional scripts (per dependency). This will cause the dependencies code not to be completely optimized (like cross dependencies code duplication reduction). Also, in case you are not using HTTP2 this going to increase your page load timeI do not get it though for us it was working fine until angular 13 and MF 14 versions. Now it stopped working. I made changes based on the suggestion here, and this seems to be working for me, but still i am not sure how it was working and what broke it. So my expectation still would be to not needing to do Store.forRoot in shell UI because what if shell UI loads many other MFEs which are not using ngrx store. I would still prefer to see a way where we could still share the store (in angular 13 with MF 14 we were simply using Store.forRoot in our exposed MFCs), although I can see that it is not recommended practice to use forRoot twice in the app, but as long as the modules is purely used for shell app, it should be fine ?
@o-b-one Why do you not recommend using shareAll in angular?
@o-b-one how a right configuration would look like without sharing all?
Our scenario is like this:
we are working in a Nx Monorepo having multiple micro frontends in place and shell applications. Because of all apps are related to the same package.json all having the same dependencies in version context.
The thing is that outside of our repo there are other applications which also have an interest of consuming our micro frontends. And here we have no knowledge what dependency in version context they have.
For this I was thinking we need some kind of configuration if outside consumers having same versioned deps we sharing them and if not the apps are loading their own deps if they are not fit from version point of view.
Little background, I am trying to breakup our monolith UI into separate buildable and deployable pieces. Module federation seems like a perfect use case for this.
Problem is, in our current application, there is a shared application state that a lot of the would be micro-frontends rely on. The micro-frontends also have their own piece of the store for their application specific state.
I use StoreModule.forFeature in the remote apps, but get an error
NullInjectorError: No provider for ReducerManager!
which is provided when you do StoreModule.forRoot, however, I don't necessarily want to define another root store in the remote app. Is it possible to share the store state with all micro-frontends?