工程化与框架系列(10)--微前端架构
- 手机
- 2025-09-15 11:09:02

微前端架构 🏗️
微前端是一种将前端应用分解成更小、更易管理的独立部分的架构模式。本文将详细介绍微前端的核心概念、实现方案和最佳实践。
微前端概述 🌟💡 小知识:微前端的核心理念是将前端应用分解成一系列独立部署、松耦合的小型应用,每个应用可以由不同的团队使用不同的技术栈开发。
为什么需要微前端在大型前端应用开发中,微前端架构能带来以下优势:
技术栈灵活性
支持多框架共存渐进式技术迁移团队技术选择自由复用已有应用资产团队自主性
独立开发部署团队边界清晰降低协作成本提高开发效率应用可维护性
代码库规模可控模块职责单一降低耦合度简化测试和部署性能优化空间
按需加载应用独立缓存策略资源并行加载性能瓶颈隔离 实现方案详解 ⚡ 基于路由的实现 // router-based.ts interface MicroApp { name: string; entry: string; container: string; activeRule: string; } export class RouterBasedMicroFrontend { private apps: MicroApp[] = []; constructor(apps: MicroApp[]) { this.apps = apps; this.initializeRouter(); } private initializeRouter(): void { window.addEventListener('popstate', () => { this.handleRouteChange(); }); // 初始化时加载匹配的应用 this.handleRouteChange(); } private handleRouteChange(): void { const path = window.location.pathname; const app = this.apps.find(app => path.startsWith(app.activeRule) ); if (app) { this.loadApp(app); } } private async loadApp(app: MicroApp): Promise<void> { try { // 加载应用资源 const html = await this.fetchAppHTML(app.entry); const container = document.querySelector(app.container); if (container) { container.innerHTML = html; this.executeAppScripts(app); } } catch (error) { console.error(`Failed to load app ${app.name}:`, error); } } private async fetchAppHTML(entry: string): Promise<string> { const response = await fetch(entry); return await response.text(); } private executeAppScripts(app: MicroApp): void { // 执行应用脚本 // 这里需要处理JS隔离等问题 } } // 使用示例 const microFrontend = new RouterBasedMicroFrontend([ { name: 'app1', entry: 'http://localhost:3001', container: '#app1-container', activeRule: '/app1' }, { name: 'app2', entry: 'http://localhost:3002', container: '#app2-container', activeRule: '/app2' } ]); 基于Web Components的实现 // web-components.ts interface WebComponentApp { name: string; element: string; url: string; } export class WebComponentMicroFrontend { constructor(apps: WebComponentApp[]) { this.registerApps(apps); } private registerApps(apps: WebComponentApp[]): void { apps.forEach(app => { this.defineCustomElement(app); }); } private async defineCustomElement(app: WebComponentApp): Promise<void> { class MicroApp extends HTMLElement { private shadow: ShadowRoot; constructor() { super(); this.shadow = this.attachShadow({ mode: 'open' }); } async connectedCallback() { try { const content = await this.loadAppContent(app.url); this.shadow.innerHTML = content; await this.executeScripts(); } catch (error) { console.error(`Failed to load ${app.name}:`, error); } } private async loadAppContent(url: string): Promise<string> { const response = await fetch(url); return await response.text(); } private async executeScripts(): Promise<void> { // 执行应用脚本,确保在Shadow DOM上下文中运行 } } customElements.define(app.element, MicroApp); } } // 使用示例 const webComponentMicro = new WebComponentMicroFrontend([ { name: 'app1', element: 'micro-app1', url: 'http://localhost:3001/app1' }, { name: 'app2', element: 'micro-app2', url: 'http://localhost:3002/app2' } ]); 通信机制实现 🔄 事件总线 // event-bus.ts type EventHandler = (data: any) => void; export class EventBus { private static instance: EventBus; private events: Map<string, EventHandler[]>; private constructor() { this.events = new Map(); } public static getInstance(): EventBus { if (!EventBus.instance) { EventBus.instance = new EventBus(); } return EventBus.instance; } public on(event: string, handler: EventHandler): void { if (!this.events.has(event)) { this.events.set(event, []); } this.events.get(event)!.push(handler); } public off(event: string, handler: EventHandler): void { if (!this.events.has(event)) return; const handlers = this.events.get(event)!; const index = handlers.indexOf(handler); if (index > -1) { handlers.splice(index, 1); } } public emit(event: string, data: any): void { if (!this.events.has(event)) return; this.events.get(event)!.forEach(handler => { try { handler(data); } catch (error) { console.error(`Error in event handler for ${event}:`, error); } }); } } // 使用示例 const eventBus = EventBus.getInstance(); // 在应用A中订阅事件 eventBus.on('userLogin', (user) => { console.log('User logged in:', user); }); // 在应用B中触发事件 eventBus.emit('userLogin', { id: 1, name: 'John Doe' }); 状态共享 // shared-state.ts interface StateChangeListener<T> { (newState: T, oldState: T): void; } export class SharedState<T extends object> { private state: T; private listeners: StateChangeListener<T>[] = []; constructor(initialState: T) { this.state = new Proxy(initialState, { set: (target, property, value) => { const oldState = { ...this.state }; target[property as keyof T] = value; this.notifyListeners(this.state, oldState); return true; } }); } public getState(): T { return this.state; } public setState(partial: Partial<T>): void { const oldState = { ...this.state }; Object.assign(this.state, partial); this.notifyListeners(this.state, oldState); } public subscribe(listener: StateChangeListener<T>): () => void { this.listeners.push(listener); return () => { const index = this.listeners.indexOf(listener); if (index > -1) { this.listeners.splice(index, 1); } }; } private notifyListeners(newState: T, oldState: T): void { this.listeners.forEach(listener => { try { listener(newState, oldState); } catch (error) { console.error('Error in state change listener:', error); } }); } } // 使用示例 interface UserState { isLoggedIn: boolean; user: { id: number; name: string; } | null; } const sharedState = new SharedState<UserState>({ isLoggedIn: false, user: null }); // 在应用A中订阅状态变化 sharedState.subscribe((newState, oldState) => { console.log('State changed:', { newState, oldState }); }); // 在应用B中更新状态 sharedState.setState({ isLoggedIn: true, user: { id: 1, name: 'John Doe' } }); 样式隔离方案 🎨 CSS Module Federation // style-isolation.ts interface StyleConfig { prefix: string; scope: string; } export class StyleIsolation { private config: StyleConfig; constructor(config: StyleConfig) { this.config = config; this.initializeStyleIsolation(); } private initializeStyleIsolation(): void { // 添加样式作用域 document.documentElement.setAttribute( 'data-app-scope', this.config.scope ); // 处理动态添加的样式 this.observeStyleChanges(); } private observeStyleChanges(): void { const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node instanceof HTMLStyleElement) { this.processStyle(node); } }); }); }); observer.observe(document.head, { childList: true }); } private processStyle(styleElement: HTMLStyleElement): void { const css = styleElement.textContent || ''; const scopedCss = this.scopeCSS(css); styleElement.textContent = scopedCss; } private scopeCSS(css: string): string { // 为所有选择器添加作用域前缀 return css.replace(/([^}]*){/g, (match) => { return match .split(',') .map(selector => `[data-app-scope="${this.config.scope}"] ${selector.trim()}` ) .join(','); }); } } // 使用示例 const styleIsolation = new StyleIsolation({ prefix: 'app1', scope: 'micro-app1' }); 性能优化策略 ⚡ 资源加载优化 // resource-loader.ts interface ResourceConfig { js: string[]; css: string[]; prefetch?: string[]; } export class ResourceLoader { private loadedResources: Set<string> = new Set(); private loading: Map<string, Promise<void>> = new Map(); public async loadApp(config: ResourceConfig): Promise<void> { try { // 并行加载JS和CSS资源 await Promise.all([ this.loadJSResources(config.js), this.loadCSSResources(config.css) ]); // 预加载其他资源 if (config.prefetch) { this.prefetchResources(config.prefetch); } } catch (error) { console.error('Failed to load resources:', error); throw error; } } private async loadJSResources(urls: string[]): Promise<void> { const promises = urls.map(url => this.loadJS(url)); await Promise.all(promises); } private async loadCSSResources(urls: string[]): Promise<void> { const promises = urls.map(url => this.loadCSS(url)); await Promise.all(promises); } private async loadJS(url: string): Promise<void> { if (this.loadedResources.has(url)) { return; } if (this.loading.has(url)) { return this.loading.get(url); } const promise = new Promise<void>((resolve, reject) => { const script = document.createElement('script'); script.src = url; script.async = true; script.onload = () => { this.loadedResources.add(url); this.loading.delete(url); resolve(); }; script.onerror = () => { this.loading.delete(url); reject(new Error(`Failed to load script: ${url}`)); }; document.head.appendChild(script); }); this.loading.set(url, promise); return promise; } private async loadCSS(url: string): Promise<void> { if (this.loadedResources.has(url)) { return; } return new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = url; link.onload = () => { this.loadedResources.add(url); resolve(); }; link.onerror = () => { reject(new Error(`Failed to load CSS: ${url}`)); }; document.head.appendChild(link); }); } private prefetchResources(urls: string[]): void { urls.forEach(url => { if (!this.loadedResources.has(url)) { const link = document.createElement('link'); link.rel = 'prefetch'; link.href = url; document.head.appendChild(link); } }); } } 最佳实践建议 ⭐ 应用设计原则独立性原则
应用间松耦合独立开发部署运行时隔离故障隔离统一规范
通信协议标准路由管理规范样式命名规范错误处理机制性能优化
按需加载策略资源复用机制缓存优化方案预加载策略 开发流程建议 项目初始化 # 创建微前端项目结构 mkdir micro-frontend && cd micro-frontend mkdir container app1 app2 shared # 初始化基座应用 cd container npm init -y npm install @micro-frontend/core # 初始化子应用 cd ../app1 npm init -y npm install @micro-frontend/app 开发规范 // 子应用生命周期规范 interface MicroAppLifecycle { bootstrap(): Promise<void>; mount(props: Record<string, any>): Promise<void>; unmount(): Promise<void>; } // 实现示例 export class MicroApp implements MicroAppLifecycle { async bootstrap(): Promise<void> { // 应用初始化 } async mount(props: Record<string, any>): Promise<void> { // 应用挂载 } async unmount(): Promise<void> { // 应用卸载 } } 结语 📝微前端架构为大型前端应用开发提供了一种可扩展、可维护的解决方案。通过本文,我们学习了:
微前端的核心概念和价值不同的实现方案及其特点应用间通信机制的实现样式隔离和资源加载优化微前端的最佳实践和建议💡 学习建议:
从小规模试点开始,逐步扩大应用范围注重基础设施和工具链建设建立完善的开发规范和文档重视性能优化和用户体验保持技术栈的适度统一如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻
工程化与框架系列(10)--微前端架构由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“工程化与框架系列(10)--微前端架构”
上一篇
AVM环视拼接鱼眼相机