Lesson 14-Micro Frontend Comprehensive Project Implementation

Designing a Micro Frontend Application

Project Architecture Planning

Layered Architecture Design

Micro Frontend Architecture Layers:
1. Infrastructure Layer
   - Micro Frontend Framework (e.g., Module Federation)
   - Shared Dependency Management
   - Environment Configuration
2. Communication Layer
   - Event Bus
   - State Management
   - API Gateway Integration
3. Application Layer
   - Sub-Application 1 (User Management)
   - Sub-Application 2 (Order Management)
   - Sub-Application 3 (Product Display)
4. Presentation Layer
   - Main Application Shell
   - Layout Components
   - Global UI Components

Technology Selection Matrix

ComponentRecommended TechnologyAlternative Options
Micro Frontend FrameworkModule Federation (qiankun)Single-SPA
State ManagementRedux (Zustand)MobX (Jotai)
Communication MechanismCustom Events/ReduxRxJS
Build ToolWebpack (Vite)Rollup
Type CheckingTypeScriptFlow

Directory Structure Example

micro-frontend/
├── apps/                  # Sub-application directory
│   ├── user-service/      # User management sub-application
│   ├── order-service/     # Order management sub-application
│   └── product-service/   # Product display sub-application
├── shell/                 # Main application shell
│   ├── src/
│   │   ├── app-shell/     # Shell application core
│   │   ├── layouts/       # Global layouts
│   │   └── shared/        # Shared components
├── shared/                # Shared resources
│   ├── components/        # Shared UI components
│   ├── utils/             # Utility functions
│   └── hooks/             # Custom hooks
└── config/                # Configuration files
    ├── webpack.config.js  # Main application configuration
    └── mf-config.js       # Micro frontend configuration

Sub-Application Decomposition and Integration

Decomposition Principles

  1. Business Domain Boundaries: Divide by business domains (e.g., user, order, product)
  2. Team Structure Alignment: Each sub-application corresponds to an independent team
  3. Technology Stack Consistency: Maintain uniform tech stack within a sub-application
  4. Independent Deployment Capability: Each sub-application can be built and deployed independently

Integration Strategy

// Main application integration example (Module Federation)
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'mainApp',
      remotes: {
        userService: 'userService@http://localhost:3001/remoteEntry.js',
        orderService: 'orderService@http://localhost:3002/remoteEntry.js',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.2.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.2.0' },
      },
    }),
  ],
};

Dynamic Loading Implementation

// Dynamically load sub-application
async function loadMicroApp(appName) {
  const container = document.getElementById(`app-${appName}`);
  
  const { getModule } = await import(
    /* webpackIgnore: true */
    `http://localhost:300${appName === 'userService' ? '1' : '2'}/remoteEntry.js`
  );
  
  const module = await getModule(appName);
  const App = module.default;
  
  ReactDOM.render(<App />, container);
}

Communication and State Design

Communication Mode Selection

ScenarioRecommended ApproachImplementation Example
Parent-Child CommunicationProps/Callbacks<Child onEvent={handler} />
Sibling CommunicationEvent BuseventBus.emit('event', data)
Cross-Level CommunicationState Managementdispatch({ type: 'ACTION' })
Global StateShared ReduxuseSelector(state => state.user)

State Management Approach

// Redux shared state example
// store.js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';
import cartReducer from './cartSlice';

export const store = configureStore({
  reducer: {
    user: userReducer,
    cart: cartReducer,
  },
});

// Sub-application integration
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
  
  export const { store: qiankunStore } = await import('./store');
  
  export function initGlobalState(state) {
    if (qiankunStore) {
      qiankunStore.dispatch({ type: 'INIT', payload: state });
    }
  }
}

State Synchronization Strategies

  1. Unidirectional Data Flow: Main app → Sub-app (via props)
  2. Event-Driven: Sub-app → Main app (via event bus)
  3. State Hoisting: Elevate shared state to main application
  4. Change Notification: Publish events on state changes

Implementing High-Performance Micro Frontends

Loading and Rendering Optimization

Code Splitting Strategy

// Webpack dynamic import
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <React.Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </React.Suspense>
  );
}

Preloading Techniques

<!-- Preload critical resources -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="main.js" as="script">
<link rel="prefetch" href="optional.js" as="script">

Rendering Optimization

// Virtual list implementation
function VirtualList({ items, itemHeight, containerHeight }) {
  const [scrollTop, setScrollTop] = useState(0);
  const visibleCount = Math.ceil(containerHeight / itemHeight);
  const startIndex = Math.floor(scrollTop / itemHeight);
  
  const visibleItems = items.slice(startIndex, startIndex + visibleCount);
  
  return (
    <div style={{ height: containerHeight, overflowY: 'auto' }}>
      <div style={{ height: items.length * itemHeight, position: 'relative' }}>
        {visibleItems.map((item, index) => (
          <div 
            key={startIndex + index}
            style={{ 
              position: 'absolute', 
              top: (startIndex + index) * itemHeight,
              width: '100%'
            }}
          >
            {item}
          </div>
        ))}
      </div>
    </div>
  );
}

Data Management and Synchronization

State Synchronization Approach

// State synchronization using Redux
const store = configureStore({
  reducer: {
    user: userReducer,
    cart: cartReducer,
  },
});

// Sub-application integration
if (window.__POWERED_BY_QIANKUN__) {
  store.subscribe(() => {
    // Notify sub-applications on state changes
    window.postMessage({
      type: 'STATE_UPDATE',
      payload: store.getState(),
    }, '*');
  });
}

Data Caching Strategy

// Data caching using SWR
import useSWR from 'swr';

function UserProfile() {
  const { data, error } = useSWR('/api/user', fetcher, {
    revalidateOnFocus: false,
    dedupingInterval: 5000,
  });
  
  if (error) return <div>Error loading user</div>;
  if (!data) return <div>Loading...</div>;
  
  return <div>{data.name}</div>;
}

Performance Monitoring and Analysis

Key Metrics Monitoring

// Performance metrics collection
const performanceMetrics = {
  tbt: performance.metrics.totalBlockingTime,
  fid: performance.getEntriesByName('first-input')[0]?.processingStart,
  cls: performance.metrics.layoutShift.total,
  lcp: performance.getEntriesByType('largest-contentful-paint')[0]?.startTime,
};

// Send to monitoring system
trackPerformance(performanceMetrics);

Performance Analysis Tools

  1. Lighthouse: Comprehensive performance assessment
  2. WebPageTest: Multi-location testing
  3. Chrome DevTools: Detailed performance analysis
  4. React Profiler: Component-level performance analysis

Micro Frontend Deployment and Optimization

CI/CD Pipeline Implementation

Pipeline Configuration Example (GitHub Actions)

name: CI/CD Pipeline

on:
  push:
    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 applications
      run: |
        npm run build:shell
        npm run build:user-service
        npm run build:order-service
        
    - name: Upload artifacts
      uses: actions/upload-artifact@v2
      with:
        name: dist
        path: ./dist
        
  deploy:
    needs: build
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/download-artifact@v2
      with:
        name: dist
        
    - name: Deploy to production
      run: |
        scp -r dist user@server:/var/www/micro-frontend
        ssh user@server "cd /var/www/micro-frontend && npm install --production && pm2 restart all"

Automated Testing and Release

Testing Strategy

// Jest unit test example
describe('User Service', () => {
  it('should fetch user data', async () => {
    const response = await fetchUserData(1);
    expect(response).toHaveProperty('id', 1);
  });
});

// Cypress E2E test example
describe('Microfrontend App', () => {
  beforeEach(() => {
    cy.visit('/');
  });
  
  it('loads all microfrontends', () => {
    cy.get('[data-testid="user-service"]').should('exist');
    cy.get('[data-testid="order-service"]').should('exist');
  });
});

Automated Release Process

  1. Code Review: PR → Code Review → Merge
  2. Build: CI → Build all applications
  3. Testing: Automated tests → Manual review
  4. Staging: Validation in staging environment
  5. Production Release: Blue-green deployment/Canary release

Security and Operations Practices

Security Hardening Measures

  1. CSP Strategy:
<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self' https://cdn.example.com 'unsafe-inline';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data:;
">
  1. XSS Protection:
// Sanitize HTML using DOMPurify
import DOMPurify from 'dompurify';

function SafeHtml({ html }) {
  const clean = DOMPurify.sanitize(html);
  return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}

Operations Monitoring

  1. Log Aggregation: ELK Stack
  2. Performance Monitoring: Prometheus + Grafana
  3. Error Tracking: Sentry
  4. Health Checks:
// Health check endpoint
app.get('/health', (req, res) => {
  res.json({
    status: 'UP',
    uptime: process.uptime(),
    timestamp: new Date(),
  });
});

High-Availability Deployment

  1. Load Balancing: Nginx configuration example
upstream micro_frontend {
  server app1.example.com;
  server app2.example.com;
  server app3.example.com;
}

server {
  listen 80;
  
  location / {
    proxy_pass http://micro_frontend;
    proxy_set_header Host $host;
  }
}
  1. Auto-Scaling: Kubernetes HPA configuration
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: micro-frontend-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: micro-frontend
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Summary and Recommendations

  1. Architecture Design Principles:
    • Follow single responsibility principle for sub-application decomposition
    • Establish clear communication and state management mechanisms
    • Use progressive loading strategies to optimize performance
  2. Performance Optimization Focus:
    • Implement code splitting and lazy loading
    • Preload critical resources
    • Use virtual lists for large dataset rendering
  3. Deployment Strategy Recommendations:
    • Implement blue-green or canary releases
    • Build comprehensive monitoring systems
    • Automate testing for critical paths
  4. Security Practices:
    • Enforce CSP strategies
    • Sanitize user inputs
    • Conduct regular security audits
  5. Team Collaboration Recommendations:
    • Establish cross-team communication mechanisms
    • Define unified development standards
    • Conduct regular technical sharing and knowledge transfer

Implementing a micro frontend architecture is an ongoing optimization process that requires continuous adjustments based on business needs and technological advancements. Start with pilot projects to build experience before scaling organization-wide. Establish continuous feedback loops to regularly evaluate architecture effectiveness and make iterative improvements.

Share your love