DEV Community

Cover image for Dependency Injection in Frontend Development: Enhancing UI Components and Micro Frontends
John Brooks
John Brooks

Posted on

Dependency Injection in Frontend Development: Enhancing UI Components and Micro Frontends

Dependency Injection (DI) is a powerful design pattern that enables flexibility, reusability, and maintainability in frontend development. It allows developers to inject dependencies (such as UI elements, services, or entire micro frontends) rather than hardcoding them within a component or application. This post explores two key use cases where DI significantly improves frontend development:

  1. Making UI components extensible and more reusable
  2. Integrating micro frontends into a platform or app shell using the Inversion of Control (IoC) pattern for build-time integration.

Both use cases have become increasingly relevant as Bit components are more frequently used to compose frontends.


1. Dependency Injection for Extensible UI Components

Reusable UI components are foundational in modern frontend development. However, when these components lack extensibility, developers often find themselves rebuilding them from scratch just to accommodate small modifications. Dependency injection solves this problem by allowing sub-elements of a component to be replaced or extended without altering the component itself.

For example:

const LoadingButton = ({ isLoading, Loader = Spinner, children }) => (
  <button disabled={isLoading}>
    {isLoading ? <Loader /> : children}
  </button>
);
Enter fullscreen mode Exit fullscreen mode

Bit components are not only a way to share code. When used as the building blocks of your application, they transform your codebase from a big pile of files into an elegant graph, where each node is a component with a meaningful name and a purpose.

Since every “building block” in your application is a component, not all components are generic and reusable. However, consumers of a component can suggest changes to make some elements of the component replaceable by other (injectable) elements. This makes the components more generic while keeping them backward compatible.


2. Dependency Injection in Build-Time Micro Frontends

Micro frontends (MFEs) help scale frontend development by allowing teams to work independently while maintaining a cohesive user experience. While runtime composition with Module Federation is common, build-time integration simplifies dependency management and improves performance.

A fundamental goal of micro frontends is independent deployment and development. However, when tightly coupled to the host app, they become harder to scale and modify. Inversion of Control (IoC) through the use of dependency-injection ensures that the host app dictates how MFEs integrate rather than the other way around.

For example, a “Blog” team might need to integrate a blog feature into an existing app maintained by another team. By following a standardized Platform API, the blog MFE can integrate seamlessly without requiring changes in the host app’s codebase.

In this case, the injected dependency is the instance of the app.

/**
 * @filename: blog.tsx 
 */
import type { Frontend, App } from '@learnbit/build-time-mf.platform';

export const blog: Frontend = (app: App) => {
  app.registerRoutes([{ path: '/blog', element: <BlogLandingPage /> }]);
  app.registerHeaderLinks([{ label: 'Blog', path: '/blog' }]);
  return app;
};
Enter fullscreen mode Exit fullscreen mode

The host app only needs a simple import to integrate the blog MFE:

import { App, type Frontend } from '@learnbit.build-time-mf.platform';
import { blog } from '@learnbit.build-time-mf.frontends.blog';

const app = new App();
[blog, ...otherMFEs].forEach((frontend) => frontend(app));
root.render({ app.renderApp() });
Enter fullscreen mode Exit fullscreen mode

Conclusion

Dependency Injection is a powerful pattern that enhances both UI component reusability and micro frontend integration. By allowing components and applications to remain flexible, dependency injection reduces the need for redundant implementations, enables extensibility, and fosters modularity. Whether used in customizable UI components or scalable micro frontend architectures, dependency injection is an essential tool for modern frontend development.

Top comments (0)