随着前端应用复杂度的提升,单体应用架构逐渐暴露出诸多问题:代码库庞大难以维护、团队协作效率低下、技术栈升级困难、构建部署耗时漫长。微前端架构应运而生,它将微服务的理念引入前端领域,为大型项目提供了一种优雅的模块化解决方案。
微前端是一种将多个可独立交付的前端应用组合成一个整体的架构风格。每个前端应用可以由不同的团队独立开发、测试和部署,最终在运行时组合成一个完整的用户界面。
这是最简单直接的方案,通过 Nginx 等反向代理服务器,根据路由规则将不同的请求分发到不同的前端应用。
# Nginx 配置示例
location /app1 {
proxy_pass http://app1-service:8081;
}
location /app2 {
proxy_pass http://app2-service:8082;
}
location /app3 {
proxy_pass http://app3-service:8083;
}
使用 iframe 标签将各个子应用嵌入到主应用中。
<div class="main-container">
<nav><!-- 主应用导航 --></nav>
<iframe id="micro-app" src="https://m.pinggu.org/bbs/app1"></iframe>
</div>
基于 Web Components 标准实现微前端。
// 定义自定义元素
class MicroApp extends HTMLElement {
connectedCallback() {
// 加载子应用
this.loadApp();
}
async loadApp() {
const appUrl = this.getAttribute('src');
const response = await fetch(appUrl);
const html = await response.text();
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = html;
}
}
customElements.define('micro-app', MicroApp);
<!-- 使用自定义元素 -->
<micro-app src="https://m.pinggu.org/bbs/app1"></micro-app>
这是目前最流行的实现方式,以 qiankun、micro-app 等框架为代表。
主应用配置:
// main.js
import { registerMicroApps, start } from 'qiankun';
// 注册子应用
registerMicroApps([
{
name: 'reactApp',
entry: '//localhost:3001',
container: '#subapp-container',
activeRule: '/react',
props: {
data: { user: 'admin' }
}
},
{
name: 'vueApp',
entry: '//localhost:3002',
container: '#subapp-container',
activeRule: '/vue'
}
]);
// 启动微前端
start({
prefetch: true, // 预加载
sandbox: {
strictStyleIsolation: true // 样式隔离
}
});
子应用配置(React):
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// 导出生命周期函数
export async function bootstrap() {
console.log('React app bootstraped');
}
export async function mount(props) {
console.log('React app mount', props);
ReactDOM.render(
<App />,
props.container
? props.container.querySelector('#root')
: document.getElementById('root')
);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(
container
? container.querySelector('#root')
: document.getElementById('root')
);
}
// 独立运行
if (!window.__POWERED_BY_QIANKUN__) {
mount({});
}
问题:多个应用的样式可能相互污染。
解决方案:
// qiankun 配置
start({
sandbox: {
strictStyleIsolation: true, // 使用 Shadow DOM
// 或使用 scope 方案
experimentalStyleIsolation: true
}
});
问题:全局变量污染、副作用影响。
解决方案:
// Proxy 沙箱实现原理
class ProxySandbox {
constructor() {
this.proxy = null;
this.running = false;
const fakeWindow = Object.create(null);
this.proxy = new Proxy(fakeWindow, {
set: (target, prop, value) => {
if (this.running) {
target[prop] = value;
}
return true;
},
get: (target, prop) => {
// 优先从代理对象取值
if (prop in target) {
return target[prop];
}
// 否则从真实 window 取值
return window[prop];
}
});
}
active() {
this.running = true;
}
inactive() {
this.running = false;
}
}
问题:如何在独立的应用之间传递数据?
解决方案:
// 主应用
registerMicroApps([{
name: 'app1',
entry: '//localhost:3001',
props: {
data: sharedData,
onGlobalStateChange: (state) => console.log(state)
}
}]);
// qiankun 提供的全局状态
import { initGlobalState } from 'qiankun';
// 主应用初始化
const actions = initGlobalState({
user: 'admin',
token: 'xxx'
});
actions.onGlobalStateChange((state, prev) => {
console.log('状态变化', state, prev);
});
// 子应用
export function mount(props) {
props.onGlobalStateChange((state, prev) => {
console.log('子应用接收状态', state);
});
// 修改全局状态
props.setGlobalState({ user: 'newUser' });
}
class EventBus {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data));
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event]
.filter(cb => cb !== callback);
}
}
}
// 全局事件总线
window.__EVENT_BUS__ = new EventBus();
问题:React、Vue 等公共库重复加载,造成资源浪费。
解决方案:
// webpack.config.js - 主应用
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
]
};
// webpack.config.js - 子应用
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./App': './src/App'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
]
};
// webpack.config.js
module.exports = {
externals: {
react: 'React',
'react-dom': 'ReactDOM'
}
};
<!-- index.html -->
<script src="https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js"></script>
// 预加载策略
import { prefetchApps } from 'qiankun';
// 在主应用空闲时预加载子应用
prefetchApps([
{ name: 'app1', entry: '//localhost:3001' },
{ name: 'app2', entry: '//localhost:3002' }
]);
// 按需加载
registerMicroApps([{
name: 'app3',
entry: '//localhost:3003',
activeRule: '/heavy-app',
props: {
loading: <Loading /> // 加载状态
}
}]);
// 统一的错误处理
import { addGlobalUncaughtErrorHandler } from 'qiankun';
addGlobalUncaughtErrorHandler((event) => {
console.error('子应用加载失败', event);
// 上报错误
reportError(event);
// 显示友好提示
showErrorMessage('应用加载失败,请刷新重试');
});
// 统一的生命周期日志
export async function mount(props) {
console.log('[LifeCycle] mount', props);
// 挂载逻辑
}
export async function unmount(props) {
console.log('[LifeCycle] unmount', props);
// 清理副作用
clearEventListeners();
clearTimers();
}
# docker-compose.yml
version: '3'
services:
main-app:
build: ./main-app
ports:
- "8080:80"
micro-app1:
build: ./micro-app1
ports:
- "8081:80"
micro-app2:
build: ./micro-app2
ports:
- "8082:80"
nginx:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
ports:
- "80:80"
depends_on:
- main-app
- micro-app1
- micro-app2
背景:
解决方案:
主应用(Shell)
├── 用户权限中心(React)
├── 商品管理系统(Vue)
├── 订单管理系统(React)
├── 营销活动平台(Vue)
├── 数据分析看板(Angular)
└── 财务结算系统(React)
效果:
| 维度 | 单体应用 | 微前端 |
|---|---|---|
| 代码库大小 | 巨大,难以维护 | 小而精,易于管理 |
| 构建速度 | 慢(10-30分钟) | 快(2-5分钟) |
| 部署频率 | 低,风险高 | 高,独立部署 |
| 技术栈 | 统一,升级困难 | 灵活,独立演进 |
| 团队协作 | 代码冲突频繁 | 独立开发,减少冲突 |
| 学习成本 | 低 | 中等 |
| 运维复杂度 | 低 | 较高 |
微前端架构为大型前端项目提供了一种有效的模块化解决方案。它解决了单体应用在规模化过程中遇到的多种问题,但也引入了新的复杂性。选择微前端需要综合考量团队规模、项目复杂度和技术储备等因素。
对于确实需要微前端的情境,建议:
微前端并非万能药,但在合适的场景下,它能够显著提高大型项目的开发效率和可维护性。
扫码加好友,拉您进群



收藏
