DEV Community

Cover image for Exploring Microfrontends with Vite and React: A Step-by-Step Guide
Gleidson Leite da Silva
Gleidson Leite da Silva

Posted on

Exploring Microfrontends with Vite and React: A Step-by-Step Guide

Introduction

Imagine you're a developer tasked with building a complex application that needs to be scalable, modular, and easy to maintain. Have you ever faced the challenge of working on a monolithic project where even a small change can break the entire system? If so, you're not alone. Microfrontend architecture emerged as a powerful solution to these problems, allowing different parts of an application to be developed and deployed independently.

In this guide, you will learn how to set up a microfrontend project using Vite, React, and the OriginJS federation plugin. We’ll start by setting up a microfrontend (project-management), followed by integrating it into the main shell (project-shell). This step-by-step approach will ensure you understand both the creation of a microfrontend and its dynamic loading into a host application.

1. Setting Up the Microfrontend (project-management)

The microfrontend represents an independent part of the application. In our example, project-management will be a simple React application that gets loaded dynamically into a host application.

Step 1: Create the Microfrontend Project

First, create the microfrontend using Vite with React and TypeScript templates.

  1. Create the Project:
   npm create vite@latest project-management -- --template react-ts
   cd project-management
   npm install
Enter fullscreen mode Exit fullscreen mode

This command sets up a new Vite project with TypeScript and React, laying the foundation for our microfrontend.

  1. Install the Federation Plugin:

Next, install the federation plugin to configure the microfrontend as a remote module that can be consumed by the main shell.

   npm install @originjs/vite-plugin-federation
Enter fullscreen mode Exit fullscreen mode
  1. Configure vite.config.ts for the Microfrontend:

Open the vite.config.ts file and set up the federation plugin to expose the microfrontend:

   import { defineConfig } from 'vite';
   import react from '@vitejs/plugin-react';
   import federation from '@originjs/vite-plugin-federation';

   export default defineConfig({
     plugins: [
       react(),
       federation({
         name: 'project-management', // Name of the microfrontend
         filename: 'remoteEntry.js', // Filename for the exposed module
         exposes: {
           './App': './src/App.tsx', // Expose the App component
         },
         shared: ['react'], // Shared dependencies
       }),
     ],
     server: {
       port: 3001, // Development server port
     },
     preview: {
       port: 3001, // Preview server port
     },
     build: {
       target: 'esnext', // Build target for modern browsers
     },
   });
Enter fullscreen mode Exit fullscreen mode

This configuration exposes the App component from src/App.tsx, allowing it to be imported dynamically by the host application.

  1. Create the Main Component App.tsx:

In the src directory, create the main App.tsx component for the microfrontend:

   function App() {
     try {
       return (
         <div>
           <h1>Project Management</h1>
         </div>
       );
     } catch (error) {
       console.error(error);
       const errorMessage = 'An error occurred while rendering the component';
       return <div>{errorMessage}</div>;
     }
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

This simple component renders a heading and includes an error handling block to catch and report any rendering issues.

  1. Build and Preview the Microfrontend:

Before integrating with the main shell, build and run a preview of the microfrontend to ensure everything is set up correctly.

   npm run build
   npm run preview
Enter fullscreen mode Exit fullscreen mode

This compiles the microfrontend and starts a preview server, simulating the production environment.

2. Setting Up the Host Application (project-shell)

With the microfrontend ready, the next step is to configure the main shell, which will load and manage the microfrontends.

Step 1: Create the Main Shell with Vite and React

  1. Create the Project:

Now, create the main shell using Vite with React and TypeScript templates.

   npm create vite@latest project-shell -- --template react-ts
   cd project-shell
   npm install
Enter fullscreen mode Exit fullscreen mode

This command sets up a new Vite project with TypeScript and React, preparing it to host the microfrontends.

  1. Install Necessary Dependencies:

To manage routing and configure the microfrontends, install react-router-dom and the federation plugin.

   npm install react-router-dom
   npm install @originjs/vite-plugin-federation
Enter fullscreen mode Exit fullscreen mode
  1. Configure vite.config.ts for the Main Shell:

In the vite.config.ts file, add the configuration for the federation plugin. This allows the main shell to load the project-management microfrontend dynamically.

   import { defineConfig } from 'vite';
   import react from '@vitejs/plugin-react';
   import federation from '@originjs/vite-plugin-federation';

   export default defineConfig({
     plugins: [
       react(),
       federation({
         name: 'project-shell', // Name of the host application
         remotes: {
           'project-management': 'http://localhost:3001/remoteEntry.js', // URL of the exposed microfrontend
         },
         shared: ['react', 'react-dom'], // Shared dependencies
       }),
     ],
     server: {
       port: 3000, // Development server port
       strictPort: true,
     },
     preview: {
       port: 3000, // Preview server port
       strictPort: true,
     },
     build: {
       target: 'esnext', // Build target for modern browsers
     },
   });
Enter fullscreen mode Exit fullscreen mode
  1. Set Up Routing in the Main Shell:

Create a src/routes/Router.tsx file to manage routing in the main shell.

   import { Route, Routes } from "react-router-dom";
   import { Home } from "../pages/Home/Home";
   import { lazy, Suspense } from "react";

   // Dynamically import the microfrontend
   const ProjectManagement = lazy(() => import("project-management/App"));

   export function Router() {
     return (
       <Routes>
         <Route path="/" element={<Home />} />
         <Route
           path="/projects"
           element={
             <Suspense fallback={<div>Loading...</div>}>
               <ProjectManagement />
             </Suspense>
           }
         />
       </Routes>
     );
   }
Enter fullscreen mode Exit fullscreen mode

Why Use React.lazy?

We use React.lazy to dynamically import the ProjectManagement component. This allows the application to load the microfrontend only when needed, which improves performance by reducing the initial bundle size. The Suspense component acts as a fallback UI while the dynamic import is being loaded, ensuring a smooth user experience.

  1. Configure the Main Component App.tsx:

In the src/App.tsx file, import the BrowserRouter and the Router component created earlier.

   import { BrowserRouter } from "react-router-dom";
   import { Router } from "./routes/Router";

   function App() {
     return (
       <BrowserRouter>
         <Router />
       </BrowserRouter>
     );
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

This component sets up the global routing of the application, using BrowserRouter to wrap the routes defined in Router.

  1. Create the Home Page (Home.tsx):

Create a simple home page that serves as the entry point for navigating to the microfrontend.

   // src/pages/Home/Home.tsx
   import { NavLink } from "react-router-dom";

   export function Home() {
     return (
       <div>
         <nav>
           <ul>
             <li>
               <NavLink to="/projects">Projects</NavLink>
             </li>
             <li>
               <NavLink to="/teams">Teams</NavLink>
             </li>
           </ul>
         </nav>
       </div>
     );
   }
Enter fullscreen mode Exit fullscreen mode

This page includes navigation links to the project microfrontend (Projects) and an example route for Teams.

  1. Add Type Declarations for the Microfrontend:

To ensure TypeScript correctly recognizes the microfrontend module, add a type declaration file in src/types/remote.d.ts:

   declare module 'project-management/App' {
     import { ComponentType } from 'react';
     const App: ComponentType;
     export default App;
   }
Enter fullscreen mode Exit fullscreen mode

Why Add This Type Declaration?

This file informs TypeScript about the shape and type of the project-management/App module. Without this, TypeScript would not know what types to expect from the dynamically imported module, potentially causing type errors or issues with autocompletion in your IDE.

3. Building and Running the Project

After setting up the main shell and the microfrontend, the next step is to build and run the projects to ensure everything works correctly.

  1. Build and Run the Microfrontend:

In the

project-management directory, run the following commands:

   npm run build
   npm run preview
Enter fullscreen mode Exit fullscreen mode

This will compile the microfrontend and start a preview server to simulate the production environment.

  1. Build and Run the Main Shell:

In the project-shell directory, run the commands:

   npm run build
   npm run preview
Enter fullscreen mode Exit fullscreen mode

The main shell will now be able to load the project-management microfrontend when you navigate to http://localhost:3000/projects.

Conclusion

You now have a complete microfrontend setup using Vite, React, and Module Federation. By starting with the microfrontend setup, you gain a clear understanding of how to expose components as remote modules. Then, integrating them into the main shell shows how to dynamically load and use these modules, enhancing the application's modularity and scalability.

The clear routing structure in the main shell and the robust configuration of the microfrontend ensure that the application is easy to maintain and extend. The use of React.lazy for dynamic imports optimizes performance, and adding type declarations ensures TypeScript compatibility, making development smoother and more robust.

Continue exploring the possibilities of microfrontends and see how this architecture can transform the way you develop your applications. If you need more help or want to explore more about microfrontends, feel free to ask. Good luck on your development journey!

Top comments (0)