This content originally appeared on Bits and Pieces - Medium and was authored by Ashan Fernando
Understanding the dynamics behind dependency handling in Microfrontends
Microfrontends are gaining traction as a proven approach to building scalable, maintainable front-end heavy applications. Yet, it also introduces a new set of challenges. Out of these, dependency handling becomes trivial as it affects the overall architecture of Microfrontends.
In this blog post, we will explore different types of dependencies in microfrontends, their impact on the architecture, unhealthy dependency practices, and how to handle them properly.
Additionally, we will discuss the importance of understanding the dependency structure, how toolchains like Bit help visualize and manage functional dependencies, framework dependencies, and various strategies for making the overall process efficient.
Types of Dependencies in Microfrontends
First of all, let's look at the various types of dependencies we come across in Microfrontends.
1. Code Blocks
Imagine you have a utility function used across various parts of your application. Accessing this code block in a monorepo setup where all the microfrontends are in a single repository is straightforward. Technically, you can import it as a dependency from any directories within the codebase.
However, accessing code blocks directly outside a Microfrontend boundary is risky. It could create a dependency that may go under the carpet.
Besides, things get tricky in a multiple repository setup. Here, the code is not co-located, making it challenging to reuse code blocks. Techniques like Git submodules and Git subtree can help. Git submodules allow you to include one repository as a subdirectory of another, while Git subtree includes the contents of one repository into another while preserving its history of commits.
Despite their usefulness, both techniques come with coordination and versioning challenges.
2. Package Dependencies (npm)
You include third-party libraries and frameworks in your micro frontend, such as React, Lodash, or any npm package that provides additional functionality. Typically, they are already versioned and served through a package registry.
You should have a strategy for automatically updating these dependencies. Solutions like Dependable (GitHub) can help keep these dependencies current.
Overall, effectively managing these dependencies ensures consistency and avoids conflicts.
3. Component Dependencies (Bit)
Components shared across different microfrontends fall into this category. They can be UI components, JavaScript entities, or any reusable code block managed and distributed using platforms like Bit.
Here, the fundamental unit of code or dependency becomes the Bit Component.
Properly managing these dependencies is essential to maintain consistency and reliability across microfrontends.
Impact of Dependencies on Microfrontend Architecture
Improper management of dependencies can severely undermine the efficiency and maintainability of a microfrontend architecture. High coupling between microfrontends with shared dependencies creates a fragile system where changes in one microfrontend unexpectedly break others.
Unversioned dependencies could also lead to inconsistencies, complicate deployments, and introduce errors. Additionally, large and unoptimized dependencies bloat the microfrontend bundle, negatively impacting load times and overall performance.
Unhealthy Dependencies and Their Management
Tight Coupling
Avoid dependencies that tightly couple different microfrontends whenever possible. Each microfrontend should remain independent to enable isolated development and deployment. For example, refrain from directly importing components or utilities from one microfrontend into another without proper versioning and isolation. This practice prevents changes in one microfrontend from unexpectedly impacting others.
Transitive Dependencies
Transitive dependencies or, in other words, dependencies of dependencies can cause unexpected issues. It’s crucial to track these dependencies and understand their impact on the project. Toolchains like Bit can help visualize and manage these dependencies, making the process easier and more efficient.
Unversioned Dependencies
Failing to version dependencies can lead to compatibility issues. Each dependency should have a clear versioning strategy to manage updates and changes effectively. This approach ensures you can track and control changes, maintaining stability across your microfrontends.
Handling Dependencies Properly
There are several practices to avoid causing dependency conflicts and duplication.
- Versioning: Use semantic versioning for all dependencies to ensure compatibility and manage updates. This approach helps you understand which updates are backwards compatible and which are not. Semantic versioning allows you to maintain consistency and control over your dependencies.
- Boundary Management: Keep dependencies within the boundary of each microfrontend whenever possible. If dependencies must be shared across boundaries, ensure they are versioned and managed properly. This practice reduces the risk of dependency conflicts and enhances the stability of your microfrontends.
- Dependency Injection: Use dependency injection to manage dependencies. This technique allows for more flexible and testable code. You can easily swap out implementations by injecting dependencies, making your codebase more adaptable and maintainable.
- Shared Libraries: Create shared libraries for common functionality. These libraries can be versioned and maintained separately, reducing duplication and ensuring consistency across microfrontends. Shared libraries streamline code reuse and simplify maintenance and are managed by the platform team.
Planning Framework Dependencies as Peer Dependencies
Peer Dependencies in Build Time Integrations
When defining your microfrontend components, specify framework dependencies (like React and Angular) as peer dependencies in your package.json. This ensures that these dependencies are not bundled within each microfrontend, reducing the overall bundle size. Ensure that all microfrontends use the same framework version to avoid conflicts by setting a common version in the project’s root package.json.
Loading Framework Dependencies from the App Shell for Runtime Integrations
For runtime integrations, load the necessary framework dependencies in the shell application (the main application that integrates all microfrontends). This approach ensures the framework libraries are loaded once and shared across all microfrontends. Doing so prevents duplicate loading and bundling of the same libraries, significantly reducing the JavaScript payload size and improving performance.
Accessing Code Blocks in Different Repository Setups
Monorepo Setup
In a monorepo setup, accessing code blocks from different directories within the same repository is straightforward. This setup promotes easy sharing and reuse of code. Centralized management of code simplifies dependency management and version control, ensuring consistency across your microfrontends.
Polyrepo (Multi-repo) Setup
Accessing code blocks is more challenging in a polyrepo setup since the code is not co-located.
- Code sharing technique limitations: Techniques like Git submodules and Git subtree make the development process complex and error-prone, especially with frequent updates.
- Coordination Overhead: Keeping track of changes and synchronizing updates across multiple repositories requires significant coordination.
- Version Conflicts: Different repositories may have different versions of the same dependency, leading to potential conflicts and inconsistencies.
Importance of Understanding Dependency Structure
Understanding the dependency structure of your micro frontend application is crucial for maintaining a healthy architecture. It helps identify potential issues, manage updates, and ensure that the system remains robust and scalable. Regularly analyzing the dependency structure can help maintain a healthy architecture.
How Bit Helps Visualize and Manage Dependencies
Clear Dependency Graph
Bit clearly visualizes how each component is connected. This helps users understand the impact of changes and manage dependencies effectively.
Component Versioning: Bit handles component versioning automatically, ensuring that updates are tracked and managed properly. This avoids the risk of breaking changes and ensures compatibility.
Isolation and Reusability: Bit promotes the creation of isolated, reusable components. This reduces the need for tight coupling between microfrontends and encourages better dependency management.
CI Integration: Bit makes Continuous Integration (CI) more efficient using Ripple CI. It ensures that all dependencies are up-to-date and compatible, reducing the risk of deployment issues.
Conclusion
Handling dependencies in microfrontends is critical to maintaining a scalable and maintainable architecture. You can ensure a robust system by understanding the different types of dependencies, their impact, and best practices for managing them. Toolchains like Bit provide valuable support in visualizing and managing dependencies and building and maintaining complex microfrontend applications easier.
Planning for framework dependencies as peer dependencies and loading them in the shell for runtime integrations are effective strategies to avoid dependency loading issues and reduce bundle sizes. Understanding and managing dependencies effectively can help avoid common pitfalls and ensure your microfrontend architecture remains efficient, scalable, and maintainable.
By leveraging these strategies and tools, professional developers can navigate the complexities of microfrontend dependencies, ensuring their applications are resilient, performant, and easy to maintain.
Thank you for reading! Cheers!
Learn More
- Micro Frontends: A Practical Step-by-Step Guide
- How We Build Micro Frontends
- Integrating Micro Frontends via Shared Types
- Mastering Microfrontends: 9 Patterns Every Developer Should Know
- Composable Software Architectures are Trending: Here’s Why
How to Handle Dependencies in Microfrontends was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Ashan Fernando
Ashan Fernando | Sciencx (2024-07-18T21:42:36+00:00) How to Handle Dependencies in Microfrontends. Retrieved from https://www.scien.cx/2024/07/18/how-to-handle-dependencies-in-microfrontends/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.