Setting Up a Micro Frontend Project from Scratch
Project Initialization
Technology Stack Selection
- Main Framework: React/Vue/Angular + Webpack/Vite
- Micro Frontend Solution: Module Federation/Single-SPA/qiankun/Wujie
- State Management: Redux/Zustand/Jotai (as needed)
- Build Tools: Webpack 5 (recommended) or Vite (prioritizing developer experience)
Initialization Commands
# Initialize main application with Vite
npm create vite@latest main-app --template react
# Initialize sub-application with Webpack
npx create-react-app sub-app --template typescript
Directory Structure Planning
micro-frontend/
├── main-app/ # Main application
│ ├── src/
│ │ ├── app/ # Main application routes and layout
│ │ ├── shell/ # Micro frontend mounting points
│ │ └── ...
├── sub-apps/ # Sub-applications directory
│ ├── app1/ # Sub-application 1
│ ├── app2/ # Sub-application 2
│ └── ...
├── shared/ # Shared dependencies/components
└── package.json # Root package.json
Basic Architecture Setup
Webpack Configuration (Main Application)
// webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
// ...other configurations
plugins: [
new ModuleFederationPlugin({
name: 'mainApp',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
app2: 'app2@http://localhost:3002/remoteEntry.js',
},
shared: {
react: { singleton: true, requiredVersion: '^18.2.0' },
'react-dom': { singleton: true, requiredVersion: '^18.2.0' },
},
}),
],
};
Sub-Application Configuration
// app1/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
// ...other configurations
plugins: [
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./App': './src/App',
},
shared: {
react: { singleton: true, requiredVersion: '^18.2.0' },
'react-dom': { singleton: true, requiredVersion: '^18.2.0' },
},
}),
],
};
Core Functionality Implementation
Main Application Mounting Sub-Applications
// main-app/src/App.jsx
import { useState, useEffect } from 'react';
function App() {
const [apps, setApps] = useState([]);
useEffect(() => {
// Dynamically load sub-application configurations
import('./app-config').then(config => {
setApps(config.default);
});
}, []);
return (
<div className="main-app">
<header>Main Application Navigation</header>
<main>
{apps.map(app => (
<div key={app.name} id={`app-${app.name}`} />
))}
</main>
{/* Dynamically load sub-applications */}
{apps.map(app => {
const RemoteComponent = React.lazy(() => import(`app1/App`)); // Should use dynamic import in practice
return (
<React.Suspense fallback={<div>Loading...</div>}>
<RemoteComponent />
</React.Suspense>
);
})}
</div>
);
}
Sub-Application Entry Point
// app1/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// Micro frontend mounting point
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
export async function bootstrap() {
console.log('app1 bootstrapped');
}
export async function mount(props) {
ReactDOM.render(<App />, document.getElementById('app1'));
}
export async function unmount() {
ReactDOM.unmountComponentAtNode(document.getElementById('app1'));
}
} else {
// Run independently
ReactDOM.render(<App />, document.getElementById('root'));
}
Complex Scenario Implementation
Dynamic Sub-Application Loading
On-Demand Loading Implementation
// Dynamic loader
async function loadMicroApp(appName) {
try {
const module = await import(`../sub-apps/${appName}/remoteEntry.js`);
const app = await module[`${appName}App`]; // Adjust based on actual exports
// Mount application
app.mount(document.getElementById(`app-${appName}`));
return { success: true, app };
} catch (error) {
console.error(`Failed to load ${appName}:`, error);
return { success: false, error };
}
}
Dynamic Routing Integration
// Main application routing configuration
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route
path="/app1/*"
element={
<MicroAppLoader name="app1" />
}
/>
{/* Other routes */}
</Routes>
</BrowserRouter>
);
}
Deep Communication Between Main and Sub-Applications
Event Bus Implementation
// event-bus.js
class EventBus {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) this.events[event] = [];
this.events[event].push(listener);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(data));
}
}
}
export const eventBus = new EventBus();
Usage Example
// Main application sends message
eventBus.emit('user-login', { userId: 123 });
// Sub-application listens
eventBus.on('user-login', (data) => {
console.log('Sub-application received login event:', data);
});
Cross-Application State Sharing
Shared Redux Store
// store.js
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: {
user: userReducer,
settings: settingsReducer,
},
});
export default store;
Sub-Application Access to Shared Store
// Sub-application store configuration
import store from './store';
if (!window.__MICRO_APP_STORE__) {
window.__MICRO_APP_STORE__ = store;
}
export function getSharedStore() {
return window.__MICRO_APP_STORE__;
}
Performance Tuning Practice
Load Performance Analysis
Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
}),
],
};
Performance Metrics Monitoring
// Main application performance monitoring
const [performanceData, setPerformanceData] = useState({});
useEffect(() => {
const metrics = {
tbt: performance.metrics.totalBlockingTime,
fid: performance.getEntriesByName('first-input')[0]?.processingStart,
cls: performance.metrics.layoutShift.total,
};
setPerformanceData(metrics);
// Send to monitoring system
trackPerformance(metrics);
}, []);
Runtime Performance Monitoring
React Profiler
import React, { Profiler } from 'react';
function onRenderCallback(
id, // The "id" of the Profiler tree that has just committed
phase, // "mount" (initial mount) or "update" (subsequent updates)
actualDuration, // Time spent rendering the Profiler and its descendants
baseDuration, // Estimated time to render without memoization
startTime, // When React began rendering this update
commitTime, // When React committed this update
interactions // Set of interactions involved in this update
) {
console.log({
id, phase, actualDuration, baseDuration, startTime, commitTime
});
}
function App() {
return (
<Profiler id="App" onRender={onRenderCallback}>
<YourAppComponent />
</Profiler>
);
}
Optimization Strategies Implementation
Code Splitting Strategy
// Dynamic import for lazy loading
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</React.Suspense>
);
}
Preloading Critical Resources
<!-- Preload during idle time -->
<link rel="prefetch" href="/critical.css" as="style">
<link rel="preload" href="/main.js" as="script">
Image Lazy Loading
import LazyLoad from 'react-lazyload';
function ImageGallery() {
return (
<div>
{images.map(img => (
<LazyLoad key={img.id} height={200}>
<img src={img.url} alt={img.alt} />
</LazyLoad>
))}
</div>
);
}
Security Hardening Practice
Security Vulnerability Fixes
XSS Protection
// Use DOMPurify to sanitize HTML
import DOMPurify from 'dompurify';
function SafeHtml({ html }) {
const clean = DOMPurify.sanitize(html);
return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}
CSRF Protection
// Backend sets CSRF Token
app.get('/api/csrf-token', (req, res) => {
res.json({ token: req.csrfToken() });
});
// Frontend usage
async function fetchData() {
const { token } = await fetch('/api/csrf-token').then(res => res.json());
const response = await fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': token,
},
body: JSON.stringify({ data: 'value' }),
});
}
Security Strategy Implementation
Content Security Policy (CSP)
<!-- Set in HTML head -->
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self';
script-src 'self' https://cdn.example.com 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
connect-src 'self' https://api.example.com;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
"
/>
Dynamic Content Security Policy
// Dynamically set CSP (development environment)
if (process.env.NODE_ENV === 'development') {
const csp = "default-src *; script-src * 'unsafe-inline' 'unsafe-eval'";
res.setHeader('Content-Security-Policy', csp);
}
Security Monitoring Integration
Error Tracking
// Global error capture
window.addEventListener('error', (event) => {
trackError({
message: event.message,
stack: event.error?.stack,
url: window.location.href,
});
});
// Promise error capture
window.addEventListener('unhandledrejection', (event) => {
trackError({
message: event.reason?.message || String(event.reason),
stack: event.reason?.stack,
});
});
Security Logging
// Log sensitive operations
function logSecurityEvent(eventType, details) {
fetch('/api/security-logs', {
method: 'POST',
body: JSON.stringify({
eventType,
details,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
}),
});
}
Continuous Delivery Pipeline
CI/CD Configuration
GitHub Actions Configuration
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run tests
run: npm test
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: dist
path: ./dist
Automated Testing Integration
Test Configuration
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
},
};
End-to-End (E2E) Test Example
// cypress/integration/app_spec.js
describe('Microfrontend App', () => {
beforeEach(() => {
cy.visit('/');
});
it('loads the app', () => {
cy.contains('Welcome to Micro Frontend').should('be.visible');
});
it('loads remote app', () => {
cy.get('#app1').should('exist');
cy.get('#app1').contains('Remote App Content').should('be.visible');
});
});
Deployment Strategy Design
Blue-Green Deployment Strategy
# Kubernetes deployment configuration example
apiVersion: apps/v1
kind: Deployment
metadata:
name: micro-frontend
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: micro-frontend
spec:
containers:
- name: mf-container
image: your-registry/micro-frontend:v2
ports:
- containerPort: 80
Canary Release
# Perform canary release with kubectl
kubectl set image deployment/micro-frontend \
mf-container=your-registry/micro-frontend:v2 --record
# Gradually increase traffic
kubectl rollout status deployment/micro-frontend
# Rollback
kubectl rollout undo deployment/micro-frontend
Feature Toggles
// Dynamic feature toggles
const FEATURE_FLAGS = {
newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
experimentalSearch: false,
};
function Dashboard() {
if (!FEATURE_FLAGS.newDashboard) {
return <LegacyDashboard />;
}
return <NewDashboard />;
}
Summary
The successful implementation of a micro frontend project requires comprehensive consideration of:
- Architecture Design: Select an appropriate micro frontend solution (Module Federation, qiankun, etc.).
- Performance Optimization: Code splitting, lazy loading, and preloading strategies.
- Security Hardening: XSS/CSRF protection, CSP strategies, and security monitoring.
- Continuous Delivery: CI/CD pipelines, automated testing, and intelligent deployment strategies.
- Observability: Performance monitoring, error tracking, and logging systems.
Each aspect should be tailored to specific business requirements and technology stacks. It is recommended to start with simple scenarios, gradually introduce complex features, and continuously optimize performance and security.



