TL;DR
- Make sure any module dependencies your shared services have are also shared.
- Make sure you’ve structured your shared config correctly in
webpack.config.ts
I’m going to note that my project is an NX Monorepo using Angular CLI. I’m using (at the moment) Angular 11.0.0-next and Webpack 5, which is only available as an opt-in with ng11 at the time of writing.
If you’re using path aliases in your tsconfig, you are used to importing local libraries like “@common/my-lib”, but you can’t share modules by alias in your webpack config. Furthermore, if you’re on NX, your linting will complain if you import from absolute or relative library paths, so there is a disconnect between what Webpack wants, and what nx/tslint wants.
In my project I have some library aliases like the following
tsconfig.base.json
...
"paths": {
"@common/facades": [
"libs/common/facades/src/index.ts"
],
"@common/data-access": [
"libs/common/data-access/src/index.ts"
]
}
To make this work in my webpack config. We have to use those aliases, but tell webpack where to find the libraries by using the import
option
apps/shell/webpack.config.js
...
plugins: [
new ModuleFederationPlugin({
remotes: {
'dashboard': '[email protected]://localhost:8010/remoteEntry.js',
'reputation': '[email protected]://localhost:8020/remoteEntry.js'
},
shared: {
"@angular/core": {
"singleton": true
},
"@angular/common": {
"singleton": true
},
"@angular/router": {
"singleton": true
},
"@angular/material/icon": {
"singleton": true
},
"@common/data-access": {
"singleton": true,
"import": "libs/common/data-access/src/index"
},
"@common/facades": {
"singleton": true,
"import": "libs/common/facades/src/index"
},
"rxjs": {
"singleton": true
},
"ramda": {
"singleton": true
}
}
})
]
That solved the issues I was having with Webpack being unable to find modules at compile time.
My second problem was that I was attempting to share common facades that depended on common data access services. I didn’t think to share the data access services because they are stateless, but this caused my MFEs to instantiate new singletons. This must be because the shared services had ‘unshared’ dependencies. Sharing my data access layer along with my facade layer resulted in shared singletons throughout my app.
The issue of dependencies is the most important thing here, because it’s harder to debug. There are no errors or anything — things just don’t work like you expect. You may not even realize that you have two instances of a shared service at first. So, if you run into this issue take a look at your dependencies and make sure you’re sharing everything you need. This is probably an argument for keeping minimal shared state/dependencies across your apps.
- a quick note about @angular/material/icon share config. In my app I populate the MatIconRegistry with icons that every app needs. I had to share the @angular/material/icon specifically to share the singleton across every MFE.
CLICK HERE to find out more related problems solutions.