技术
19 min read微前端架构实践:从理论到落地
2025-01-14by LZG
#Micro-Frontend#Architecture#Engineering
引言
随着前端应用的规模不断增长,单体前端应用面临着维护困难、部署复杂、团队协作效率低等问题。微前端架构应运而生,它将前端应用拆分为多个可独立开发、部署和维护的小型应用。
1. 微前端核心概念
1.1 什么是微前端
微前端是一种架构风格,它将前端应用拆分为多个独立的、可组合的片段,每个片段由不同的团队负责开发和维护。
核心特征:
- 独立开发:不同团队可以独立开发各自的功能模块
- 独立部署:每个微应用可以独立部署,不影响其他应用
- 技术栈无关:可以使用不同的框架和技术栈
- 运行时组合:在运行时将多个微应用组合成一个完整的应用
1.2 适用场景
✅ 适合微前端的场景:
- 大型企业级应用,功能模块众多
- 多个团队协作开发
- 需要渐进式重构旧系统
- 不同业务模块使用不同技术栈
❌ 不适合微前端的场景:
- 小型应用,团队规模小
- 应用之间耦合度低
- 频繁跨应用通信
2. 技术方案对比
2.1 主流方案
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| qiankun | 成熟稳定,社区活跃 | 配置相对复杂 | 企业级应用 |
| micro-app | 轻量级,接入简单 | 功能相对较少 | 快速接入 |
| Module Federation | 原生支持,配置简单 | 需要 Webpack 5 | 现代化项目 |
| iframe | 隔离性好 | 通信复杂,体验差 | 第三方集成 |
2.2 方案选型
基于我们的项目需求,选择了 micro-app 方案:
// 主应用配置
import microApp from '@micro-zoe/micro-app';
microApp.start({
shadowDOM: true,
inline: true,
destroy: true,
lifeCycles: {
created(e) {
console.log('微应用创建', e.detail.appName);
},
mounted(e) {
console.log('微应用挂载', e.detail.appName);
},
unmount(e) {
console.log('微应用卸载', e.detail.appName);
}
}
});
3. 架构设计
3.1 整体架构
┌─────────────────────────────────────────┐
│ 主应用 (Shell App) │
│ - 路由管理 │
│ - 权限控制 │
│ - 公共组件 │
│ - 状态管理 │
└─────────────────────────────────────────┘
│
┌───────────┼───────────┐
│ │ │
┌───────▼────┐ ┌───▼────┐ ┌───▼────┐
│ 微应用 A │ │微应用 B │ │微应用 C │
│ (React) │ │(Vue 3) │ │(Vue 2) │
└────────────┘ └────────┘ └────────┘
3.2 主应用职责
// 主应用路由配置
const routes = [
{
path: '/',
component: Layout,
children: [
{
path: 'dashboard',
component: Dashboard
},
{
path: 'products',
name: 'products',
url: 'http://localhost:3001',
baseroute: '/products'
},
{
path: 'orders',
name: 'orders',
url: 'http://localhost:3002',
baseroute: '/orders'
}
]
}
];
// 权限控制
function ProtectedRoute({ children, requiredPermission }) {
const { user } = useAuth();
if (!hasPermission(user, requiredPermission)) {
return <Forbidden />;
}
return children;
}
3.3 微应用配置
// 微应用入口
export async function mount() {
const container = document.querySelector('#subapp-container');
const root = createRoot(container);
root.render(<App />);
}
export async function unmount() {
const container = document.querySelector('#subapp-container');
const root = getRoot(container);
root.unmount();
}
// 微应用配置
export const microAppConfig = {
name: 'products',
entry: '//localhost:3001',
container: '#subapp-container',
activeRule: '/products'
};
4. 通信机制
4.1 主应用向微应用传递数据
// 主应用
function dispatchToMicroApp(appName, data) {
const detail = { data };
const event = new CustomEvent('main-app-data', { detail });
window.dispatchEvent(event);
}
// 微应用
useEffect(() => {
const handler = (event) => {
const { data } = event.detail;
console.log('收到主应用数据:', data);
};
window.addEventListener('main-app-data', handler);
return () => {
window.removeEventListener('main-app-data', handler);
};
}, []);
4.2 微应用间通信
// 使用 micro-app 的数据通信
import microApp from '@micro-zoe/micro-app';
// 发送数据
function sendData(targetApp, data) {
microApp.setData(targetApp, data);
}
// 接收数据
function onDataReceive(data) {
console.log('收到数据:', data);
}
// 监听数据变化
microApp.addDataListener('app-name', onDataReceive);
// 移除监听
microApp.removeDataListener('app-name', onDataReceive);
4.3 共享状态管理
// 主应用提供共享状态
import { createStore } from 'redux';
const sharedStore = createStore(userReducer);
// 微应用访问共享状态
function useSharedState() {
const [state, setState] = useState(() => {
return window.__SHARED_STATE__ || {};
});
useEffect(() => {
const handler = (event) => {
setState(event.detail);
};
window.addEventListener('shared-state-change', handler);
return () => {
window.removeEventListener('shared-state-change', handler);
};
}, []);
return state;
}
5. 样式隔离
5.1 Shadow DOM 方案
// micro-app 自动开启 Shadow DOM
microApp.start({
shadowDOM: true,
// 样式隔离配置
shadowDOMStyle: {
// 排除某些样式
exclude: ['global-styles']
}
});
5.2 CSS Modules
/* 微应用使用 CSS Modules */
.container {
padding: 20px;
}
.title {
font-size: 24px;
}
// 组件中使用
import styles from './App.module.css';
function App() {
return (
<div className={styles.container}>
<h1 className={styles.title}>微应用</h1>
</div>
);
}
5.3 命名约定
/* 使用前缀避免冲突 */
.products-app__container {
padding: 20px;
}
.products-app__title {
font-size: 24px;
}
6. 性能优化
6.1 按需加载
// 路由级别的懒加载
const ProductsApp = lazy(() => import('./apps/products'));
const OrdersApp = lazy(() => import('./apps/orders'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/products" element={<ProductsApp />} />
<Route path="/orders" element={<OrdersApp />} />
</Routes>
</Suspense>
);
}
6.2 资源预加载
// 预加载微应用资源
function preloadMicroApp(url) {
const link = document.createElement('link');
link.rel = 'prefetch';
link.href = url;
document.head.appendChild(link);
}
// 在用户可能访问之前预加载
useEffect(() => {
if (user.hasPermission('products')) {
preloadMicroApp('http://localhost:3001');
}
}, [user]);
6.3 缓存策略
// 微应用资源缓存
microApp.start({
// 缓存配置
iframe: false,
inline: false,
destroy: false, // 保持微应用实例
keep-alive: true // 保持微应用活跃状态
});
7. 实战经验
7.1 渐进式迁移
// 1. 识别可拆分的模块
const modules = [
{ name: 'products', path: '/products', priority: 'high' },
{ name: 'orders', path: '/orders', priority: 'medium' },
{ name: 'users', path: '/users', priority: 'low' }
];
// 2. 按优先级迁移
async function migrateModules() {
for (const module of modules) {
await migrateModule(module);
await validateModule(module);
}
}
// 3. 验证迁移结果
async function validateModule(module) {
const tests = await runTests(module.name);
if (tests.passed) {
console.log(`${module.name} 迁移成功`);
} else {
console.error(`${module.name} 迁移失败`, tests.errors);
}
}
7.2 错误边界
// 微应用错误边界
class MicroAppErrorBoundary extends Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error('微应用错误:', error, errorInfo);
// 上报错误
reportError({
error,
errorInfo,
app: this.props.appName
});
}
render() {
if (this.state.hasError) {
return (
<div className="error-fallback">
<h2>应用加载失败</h2>
<button onClick={() => window.location.reload()}>
重新加载
</button>
</div>
);
}
return this.props.children;
}
}
7.3 监控与日志
// 微应用性能监控
function trackMicroAppPerformance(appName) {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name.includes(appName)) {
console.log(`${appName} 加载时间:`, entry.duration);
// 上报性能数据
reportPerformance({
app: appName,
duration: entry.duration,
timestamp: entry.startTime
});
}
}
});
observer.observe({ entryTypes: ['measure', 'navigation'] });
}
8. 最佳实践
8.1 开发规范
// 统一的微应用接口
interface MicroAppConfig {
name: string;
version: string;
mount: () => Promise<void>;
unmount: () => Promise<void>;
update: (props: any) => Promise<void>;
}
// 微应用必须实现标准接口
export const config: MicroAppConfig = {
name: 'products',
version: '1.0.0',
mount: async () => { /* ... */ },
unmount: async () => { /* ... */ },
update: async (props) => { /* ... */ }
};
8.2 版本管理
// 微应用版本控制
interface MicroAppVersion {
version: string;
entry: string;
compatible: boolean;
releaseDate: string;
}
const versions: MicroAppVersion[] = [
{
version: '1.0.0',
entry: '//cdn.example.com/products/v1.0.0',
compatible: true,
releaseDate: '2025-01-01'
},
{
version: '1.1.0',
entry: '//cdn.example.com/products/v1.1.0',
compatible: true,
releaseDate: '2025-01-15'
}
];
// 根据兼容性选择版本
function selectVersion(appVersions: MicroAppVersion[]) {
return appVersions.find(v => v.compatible) || appVersions[0];
}
8.3 安全考虑
// 内容安全策略
const csp = {
'default-src': "'self'",
'script-src': "'self' 'unsafe-inline' 'unsafe-eval'",
'style-src': "'self' 'unsafe-inline'",
'img-src': "'self' data: https:",
'connect-src': "'self' https://api.example.com"
};
// 设置 CSP
function setCSP() {
const meta = document.createElement('meta');
meta.httpEquiv = 'Content-Security-Policy';
meta.content = Object.entries(csp)
.map(([key, value]) => `${key} ${value}`)
.join('; ');
document.head.appendChild(meta);
}
结语
微前端架构为大型前端应用提供了一种有效的解决方案。通过合理的技术选型、架构设计和实施策略,我们可以构建出可维护、可扩展的前端系统。关键是要根据项目需求选择合适的方案,并在实践中不断优化和改进。