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.
- Create the Project:
npm create vite@latest project-management -- --template react-ts
cd project-management
npm install
This command sets up a new Vite project with TypeScript and React, laying the foundation for our microfrontend.
- 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
- 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
},
});
This configuration exposes the App
component from src/App.tsx
, allowing it to be imported dynamically by the host application.
- 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;
This simple component renders a heading and includes an error handling block to catch and report any rendering issues.
- 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
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
- 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
This command sets up a new Vite project with TypeScript and React, preparing it to host the microfrontends.
- 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
- 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
},
});
- 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>
);
}
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.
- 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;
This component sets up the global routing of the application, using BrowserRouter
to wrap the routes defined in Router
.
- 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>
);
}
This page includes navigation links to the project microfrontend (Projects
) and an example route for Teams
.
- 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;
}
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.
- Build and Run the Microfrontend:
In the
project-management
directory, run the following commands:
npm run build
npm run preview
This will compile the microfrontend and start a preview server to simulate the production environment.
- Build and Run the Main Shell:
In the project-shell
directory, run the commands:
npm run build
npm run preview
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 (1)
Hopefully this will save someone some time. Followed instructions above but the remote app would not load. I was getting an error saying the remoteEntry.js file could not be found. To fix: In the vite.config.ts file of the container/parent, change this (I changed the name of my remote app to 'global'):
to this:
just had the add /assets in the path then worked like a charm