In the world of micro-frontends, ensuring that shared dependencies are correctly managed is paramount for optimal application performance and user experience. A common issue developers encounter when using the @angular-architects/module-federation
package is that shared dependencies are still being generated in both remote and shell applications. This can lead to increased bundle sizes and redundant loading of libraries, which we will address in this article.
Problem Scenario
The original problem can be summarized as follows:
"Shared dependencies are still generated in both remote and shell app in @angular-architects/module-federation."
This sentence can be simplified to: "In @angular-architects/module-federation
, shared dependencies are being duplicated in both the remote and shell applications."
Understanding the Issue
In micro-frontend architecture, applications (or modules) are designed to work independently, but they often share libraries or frameworks, such as Angular. When using module federation, developers expect that shared dependencies, such as @angular/core
, will only be loaded once in the shell application to minimize duplication and improve loading times.
Example of a Misconfiguration
In a typical Angular setup using module federation, you might see something like this in your webpack.config.js
:
// webpack.config.js
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
// Other configuration settings
plugins: [
new ModuleFederationPlugin({
name: "shell",
remotes: {
remoteApp: "remoteApp@http://localhost:4201/remoteEntry.js",
},
shared: {
'@angular/core': { singleton: true, eager: true },
'@angular/common': { singleton: true, eager: true },
},
}),
],
};
If you notice that your shared dependencies are still being duplicated in both the shell and remote applications, it may be due to the configuration settings within your webpack
setup.
Analysis of Configuration
Singleton vs. Eager Loading
One potential reason for duplicated dependencies could be the lack of proper configuration for shared dependencies. In the example above, the use of singleton: true
ensures that the same instance of the library is used across both applications, but if the eager
flag is set to true
, it forces the dependency to load regardless of whether it’s already included or not.
Correct Configuration Example
To resolve this issue, you should ensure that your configuration specifies singleton
and possibly remove eager
:
shared: {
'@angular/core': { singleton: true },
'@angular/common': { singleton: true },
},
Practical Example
Imagine two Angular applications: a shell app and a remote app that both use @angular/common
. If both applications are configured correctly with singleton: true
, when users load the shell app, it will fetch @angular/common
just once, and the remote app will utilize this single instance instead of fetching its own.
This not only optimizes performance by reducing network requests but also ensures that both apps remain synchronized with the same version of the shared library.
Additional Considerations
-
Version Compatibility: Ensure all applications are using compatible versions of the shared dependencies. Mismatched versions can lead to runtime errors.
-
Testing: Regularly test your setup in various environments to ensure that shared dependencies are correctly loaded. Use tools like Webpack Bundle Analyzer to visualize your bundle sizes.
-
Documentation and Best Practices: Stay updated with the official Angular Module Federation documentation for best practices and recommendations.
Conclusion
Effectively managing shared dependencies in a micro-frontend architecture using @angular-architects/module-federation
is crucial for enhancing application performance and user experience. By configuring your shared libraries correctly, you can eliminate duplication and optimize loading times.
For further reading, here are some useful resources:
- Webpack Module Federation Documentation
- Angular Architect's Module Federation Guide
- Angular Official Documentation
By implementing these strategies and configurations, you can ensure that your Angular applications are efficient, streamlined, and free of unnecessary redundancies.