Angular singleton service initiated multiple times
Hi everyone, I was following this tutorial , then i tried to share a library between the shell and the mfe1 app. I created the lib outside the workspace directory with one service injected in root, then added it to the tutorial package.json, and imported it in both shell and mfe1. Inside both projects webpack config, i added the following configuration
new ModuleFederationPlugin({
.....
},
shared: {
.....
"my-lib": { singleton: true, strictVersion: true, requiredVersion: '1.0.0'},
...sharedMappings.getDescriptors()
}
}),
When testing the shell, i noticed that the singleton service is being initiated twice, first time when loading the shell, second time when moving to the mfe1, maybe i'm missing something, but isn't the purpose of singleton: true config is to insure that only one instance of that service is existing?
Could be version mismatches? Does webpack throw warnings in terminal browser console
i'm using the same version on both projects, and there are no errors in browser console. I added the code in this repo in case it's needed. Could it be that my lib module being imported in both (shell & mfe1) modules is the issue?
I'm facing the same issue. I have a service as per the below:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class SharedServicesService {
constructor() { }
nameUpdated$ = new Subject<string>();
notifyNameUpdated(name: string) {
this.nameUpdated$.next(name);
}
}
The shell app.component.ts has this code to subscribe to nameUpdated$:
ngOnInit(): void {
this.sharedService.nameUpdated$.subscribe((name: string) => {
console.log("shell nameUpdated$: " + name);
});
}
The mfe1 has a component with this code:
ngOnInit(): void {
console.log('publishing message to sharedservice endpoint');
this.sharedService.notifyNameUpdated('updated name from manage-teams.component.ts');
}
When mfe1 publishes a new message, the shell code is not executed. When I debug mfe1, I can see there are no observers registered on this.sharedService.
NOTE: I'm using Angular 12.0.4
Here is the shell webpack.config.js
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
uniqueName: "shell",
publicPath: "auto"
},
optimization: {
runtimeChunk: false
},
plugins: [
new ModuleFederationPlugin({
shared: {
"@angular/core": { singleton: true, strictVersion: true, eager: true, requiredVersion: '12.0.4' },
"@angular/common": { singleton: true, strictVersion: true, eager: true, requiredVersion: '12.0.4' },
"@angular/common/http": { singleton: true, strictVersion: true, eager: true, requiredVersion: '12.0.4' },
"@angular/router": { singleton: true, strictVersion: true, eager: true, requiredVersion: '12.0.4' },
"projects/shared-services/src/public-api": { eager: true, singleton: true, requiredVersion: '0.0.1' },
}
}),
],
};
Here is the mfe1 webpack.config.js:
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
uniqueName: "mfe1",
publicPath: "auto"
},
optimization: {
runtimeChunk: false
},
plugins: [
new ModuleFederationPlugin({
name: "moduleAdministration",
filename: "remoteEntry.js",
exposes: {
'./Module': './projects/mfe1/src/app/administration/administration.module.ts',
},
shared: {
"@angular/core": { singleton: true, strictVersion: true, requiredVersion: '12.0.4' },
"@angular/common": { singleton: true, strictVersion: true, requiredVersion: '12.0.4' },
"@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: '12.0.4' },
"@angular/router": { singleton: true, strictVersion: true, requiredVersion: '12.0.4' },
"projects/shared-services/src/public-api": { singleton: true, requiredVersion: '0.0.1' },
}
}),
],
};
The team here found the issue and reading the Angular docs on providers: https://angular.io/guide/providers I can see what my issue was. We are lazy loading the modules and this was the cause of the multiple instances of the service being created.
I updated providedIn to be the containing module instead of 'root'
@Injectable({
providedIn: SharedServicesModule
})
Try without strictVersion
Tried without strictVersion but no luck, yet after many attempts, i managed to achieve what i need but still don't know if it's the correct solution or not. Shell:
- i left my library import inside the app module.
Mfe1:
- removed the library import in the exported module.
- imported only my library service inside the flight search component to check later if i'm running two instances of the services or one.
When running both apps, only one instance of the service is created by checking the log and incrementing the counter.
If you can, try PR one of the angular examples if this bug exists in the MF examples
@Hekek I downloaded your code and tried to test it, but it seems the problem still exists

its becuase its marked as eager which means every remote is going to have a copy of it. Eager sharing is generally a bad idea at all times
In case anyone lands here, I solved my own problem, the issue I was facing was due to using yarn link instead of adding the lib to the compiler options in tsconfig.json
My theory is that yarn link removes visibility of the lib (instead simulating involvement with symlinks) and therefore removes it from compilation and the configuration of webpack's shareAll functionality.
That'll do it. ShareAll should use webpacks resolvers. They can follow symlinks