Beginning with version 13, the Angular CLI compiles emits EcmaScript modules. This also effects how entry points for Module Federation are generated. This guide shows how you can adjust to this.
Big thanks to all the people, that helped with this migration:
- Tobias Koppers, Founder of Webpack
- Colum Ferry, Senior Software Engineer at NRWL
- Thomas Sandeep
- Michael Zikes
yarn add @angular-architects/module-federation@14.0.0-rc.1
As we need a newer webpack version, don't go with Angular 13.0 but with 13.1 or higher.
In your tsconfig.json
or tsconfig.base.json
, make sure, your compilation target
is es2020
or higher:
{
"compileOnSave": false,
"compilerOptions": {
[...]
"target": "es2020",
[...]
},
[...]
}
Add the following setting to all your webpack configs:
[...]
module.exports = {
[...]
+ experiments: {
+ outputModule: true
+ },
plugins: [
new ModuleFederationPlugin({
+ library: { type: "module" },
[...]
})
]
};
If you use static federation, you need to further adjust your shell's webpack config. As EcmaScript modules can be directly imported, there is no remoteName
anymore. Before, this name was used as the name of a global variable that made the remote available. Hence, remove it from the values in your remotes
section:
[...]
module.exports = {
[...]
plugins: [
new ModuleFederationPlugin({
library: { type: "module" },
// For hosts (please adjust)
remotes: {
// Load as module
- "mfe1": "mfe1@http://localhost:3000/remoteEntry.js",
+ "mfe1": "http://localhost:3000/remoteEntry.js",
},
[...]
})
]
};
Adjust your usage of loadRemoteModule
, e. g. in your routing config:
{
path: 'flights',
loadChildren: () =>
loadRemoteModule({
+ type: 'module',
remoteEntry: 'http://localhost:3000/remoteEntry.js',
- remoteName: 'mfe1',
exposedModule: './Module'
})
.then(m => m.FlightsModule)
},
Also, adjust your usage of loadRemoteEntry
, e. g. in your main.ts
:
- loadRemoteEntry('http://localhost:3000/remoteEntry.js', 'mfe1')
+ loadRemoteEntry({ type: 'module', remoteEntry: 'http://localhost:3000/remoteEntry.js'})
.then(_ => import('./bootstrap').catch(err => console.error(err)))
To prevent issues with live reloads, you need to add a publicHost
property to your remote's configuration in your angular.json
. Hence, adjust the section project/remote-project-name/architect/serve/options
as follows:
[...]
"options": {
+ "publicHost": "http://localhost:3000",
"port": 3000,
"extraWebpackConfig": "projects/mfe1/webpack.config.js"
}
[...]
As remotes are now loaded as EcmaScript modules, the same origin policy is in place. Hence, if your micro frontends and the shell are deployed to different origins, you need to enable CORS. The same holds true if you run your application after building it with a command line web server like serve
(serve
, e. g., has a --cors
options).
If you also want to load (existing) script-based remotes into your shell, e. g. remotes built with Angular 12 used for a Multi-Version/Multi-Framework setup, you can pass type: 'script'
to both, loadRemoteModule
and loadRemoteEntry
. In this case, you also need to pass a remoteName
.
If you want to load (existing) script-based remote into your shell, e. g. such built with Angular 12, you can use the following syntax in the shell's webpack.config.js
.
In the following example, mfe1
is loaded as a module while mfe2
is loaded as a script:
remotes: {
// Load as module:
mfe1": "http://localhost:3000/remoteEntry.js",
// Load as script:
mfe2": "script mfe2@http://localhost:3000/remoteEntry.js",
}
While moving forward with Modules and aligning with the CLI is a good idea, you might to temporarily opt-out of using them. This gives you some additional time for the migration as it brings back the behavior of Angular 12. For this, adjust your webpack configs as follows:
module.exports = {
output: {
uniqueName: "dashboard",
publicPath: "auto",
+ scriptType: 'text/javascript'
},
[...]
}
Also, don't use the settings introduced above for Angular 13.1+:
[...]
module.exports = {
[...]
- experiments: {
- outputModule: true
- },
plugins: [
new ModuleFederationPlugin({
- library: { type: "module" },
[...]
})
]
};
We have a sound solution including Schematics for SSR in Angular 12. However, because of a bug in Angular Universal 13, SSR is currently not supported for Angular 13. However, we are monitoring this situation and providing a solution as soon as these issues are fixed.