I'm working on a new project using Angular 11 and Webpack 5. I am basing my work on Manfred Steyer's Module Federation Plugin Example repo, which uses Angular CLI. I can't figure out how to share a singleton service from a shared local Angular library between my two apps.
I'll do my best to explain my setup.. Real sorry about how long this is going to be.
Simplified File Structure
root
package.json
projects/
shell/
src/app/
app.module.ts
app.component.ts
webpack.config.ts <-- partial config
mfe1/
src/app/
app.module.ts
app.component.ts
webpack.config.ts <-- partial config
shared/
src/lib/
global.service.ts
package.json <-- package.json for lib
Angular
both app.component.ts files are identical
import {GlobalService} from 'shared';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
constructor(shared: SharedService) {}
}
global.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class GlobalService {
constructor() {
console.log('constructed SharedService');
}
}
Webpack
shell/webpack.config.ts
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
publicPath: "http://localhost:5000/",
uniqueName: "shell"
},
optimization: {
// Only needed to bypass a temporary bug
runtimeChunk: false
},
plugins: [
new ModuleFederationPlugin({
remotes: {
'mfe1': "mfe1@http://localhost:3000/remoteEntry.js"
},
shared: ["@angular/core", "@angular/common", "@angular/router"]
})
],
};
mfe1/webpack.config.ts
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
publicPath: "http://localhost:3000/",
uniqueName: "mfe1"
},
optimization: {
// Only needed to bypass a temporary bug
runtimeChunk: false
},
plugins: [
new ModuleFederationPlugin({
// For remotes (please adjust)
name: "mfe1",
library: {type: "var", name: "mfe1"},
filename: "remoteEntry.js",
exposes: {
'./Module': './projects/mfe1/src/app/app.module.ts',
},
shared: ["@angular/core", "@angular/common", "@angular/router"]
})
],
};
shared library package.json
{
"name": "shared",
"version": "0.0.1",
"main": "src/public-api.ts",
"peerDependencies": {
"@angular/common": "^11.0.0-next.5",
"@angular/core": "^11.0.0-next.5"
},
"dependencies": {
"tslib": "^2.0.0"
}
}
This configuration compiles and runs, but mfe1
instantiates a new GlobalService
. I see "constructed SharedService" logged on app load, then again as soon as the remote module is loaded. I tried to follow another example by ScriptedAlchemy, but I can't figure out how to make it work. It either compiles and runs and creates two instances, or it fails to compile citing a missing module depending on how i mess up my configuration I'm sure.
The ScriptedAlchemy example makes it seem like I need to reference my shared library in my shared
library array in the webpack.config.ts
files. This makes complete sense but i can't get it to work
shell/webpack.config.ts and mfe1/webpack.config.ts
...
shared: ["@angular/core", "@angular/common", "@angular/router", "shared"]
If I reference the local library this way I inevitably end up with errors during builds
Error: Module not found: Error: Can't resolve 'shared' in '/Path/to/module-federation-plugin-example/projects/shell/src/app'
The examples I posted are simplified. Hopefully not overly so, but here is a link to a repo that shows the issue