目录

工程化与框架系列35-前端微服务架构实践

工程化与框架系列(35)–前端微服务架构实践

前端微服务架构实践 🏗️

引言

随着前端应用规模的不断扩大,微服务架构在前端领域的应用越来越广泛。本文将深入探讨前端微服务架构的实现方案、最佳实践和相关工具。

微服务架构概述

前端微服务架构主要包括以下方面:

  • 应用拆分 :基于业务域的应用拆分策略
  • 独立部署 :各个微应用的独立开发、构建和部署
  • 运行时集成 :微应用的加载、通信和生命周期管理
  • 共享资源 :公共依赖、组件库、工具函数等的共享策略
  • 统一管理 :路由、状态、权限等的统一管理方案

微服务架构实现

微前端容器

// 微前端容器类 class MicroFrontendContainer { private static instance: MicroFrontendContainer; private apps: Map; private config: ContainerConfig; private constructor() { this.apps = new Map(); this.config = { sandbox: true, prefetch: true, isolation: ‘iframe’, timeout: 3000 }; } // 获取单例实例 static getInstance(): MicroFrontendContainer { if (!MicroFrontendContainer.instance) { MicroFrontendContainer.instance = new MicroFrontendContainer(); } return MicroFrontendContainer.instance; } // 注册微应用 registerApp(appConfig: MicroAppConfig): void { const app = new MicroApp(appConfig); this.apps.set(appConfig.name, app); // 预加载配置 if (this.config.prefetch) { this.prefetchApp(app); } } // 启动微应用 async startApp(name: string): Promise { const app = this.apps.get(name); if (!app) { throw new Error(App ${name} not found); } try { // 加载微应用资源 await this.loadApp(app); // 创建沙箱环境 const sandbox = this.createSandbox(app); // 挂载微应用 await this.mountApp(app, sandbox); // 初始化通信 this.initCommunication(app); } catch (error) { console.error(Failed to start app ${name}:, error); throw error; } } // 停止微应用 async stopApp(name: string): Promise { const app = this.apps.get(name); if (!app) { throw new Error(App ${name} not found); } try { // 卸载微应用 await this.unmountApp(app); // 清理沙箱 this.cleanupSandbox(app); // 清理资源 this.cleanupResources(app); } catch (error) { console.error(Failed to stop app ${name}:, error); throw error; } } // 预加载微应用 private async prefetchApp(app: MicroApp): Promise { try { const resources = await this.loadResources(app.config.entry); app.setResources(resources); } catch (error) { console.warn(Failed to prefetch app ${app.config.name}:, error); } } // 加载微应用资源 private async loadApp(app: MicroApp): Promise { if (app.isLoaded()) { return; } const resources = app.getResources() || await this.loadResources(app.config.entry); await this.injectResources(resources); app.setLoaded(true); } // 加载资源 private async loadResources(entry: string): Promise { const response = await fetch(entry); const html = await response.text(); return { scripts: this.extractScripts(html), styles: this.extractStyles(html), templates: this.extractTemplates(html) }; } // 注入资源 private async injectResources(resources: AppResources): Promise { // 注入样式 await Promise.all( resources.styles.map(style => this.loadStyle(style)) ); // 注入脚本 await Promise.all( resources.scripts.map(script => this.loadScript(script)) ); } // 创建沙箱环境 private createSandbox(app: MicroApp): Sandbox { if (this.config.isolation === ‘iframe’) { return new IframeSandbox(app); } else { return new JsSandbox(app); } } // 挂载微应用 private async mountApp( app: MicroApp, sandbox: Sandbox ): Promise { const mountPoint = document.querySelector(app.config.container); if (!mountPoint) { throw new Error( Mount point ${app.config.container} not found ); } // 执行生命周期钩子 await app.beforeMount(); // 在沙箱中执行挂载 await sandbox.mount(mountPoint); // 更新应用状态 app.setMounted(true); // 执行生命周期钩子 await app.afterMount(); } // 卸载微应用 private async unmountApp(app: MicroApp): Promise { if (!app.isMounted()) { return; } // 执行生命周期钩子 await app.beforeUnmount(); // 移除DOM const container = document.querySelector(app.config.container); if (container) { container.innerHTML = ‘’; } // 更新应用状态 app.setMounted(false); // 执行生命周期钩子 await app.afterUnmount(); } // 清理沙箱 private cleanupSandbox(app: MicroApp): void { const sandbox = app.getSandbox(); if (sandbox) { sandbox.cleanup(); } } // 清理资源 private cleanupResources(app: MicroApp): void { const resources = app.getResources(); if (resources) { // 移除样式 resources.styles.forEach(style => { const element = document.querySelector( link[href="${style}"] ); element?.remove(); }); // 移除脚本 resources.scripts.forEach(script => { const element = document.querySelector( script[src="${script}"] ); element?.remove(); }); } } // 初始化应用间通信 private initCommunication(app: MicroApp): void { const eventBus = EventBus.getInstance(); // 注册应用通信处理器 app.setMessageHandler(message => { eventBus.emit(${app.config.name}:message, message); }); // 监听其他应用消息 this.apps.forEach(otherApp => { if (otherApp !== app) { eventBus.on( ${otherApp.config.name}:message, message => { app.postMessage(message); } ); } }); } } // 微应用类 class MicroApp { private loaded: boolean = false; private mounted: boolean = false; private resources: AppResources | null = null; private sandbox: Sandbox | null = null; private messageHandler: MessageHandler | null = null; constructor(public config: MicroAppConfig) {} // 生命周期钩子 async beforeMount(): Promise { await this.invokeLifecycle(‘beforeMount’); } async afterMount(): Promise { await this.invokeLifecycle(‘afterMount’); } async beforeUnmount(): Promise { await this.invokeLifecycle(‘beforeUnmount’); } async afterUnmount(): Promise { await this.invokeLifecycle(‘afterUnmount’); } // 调用生命周期函数 private async invokeLifecycle(name: string): Promise { const lifecycle = (window as any)[ ${this.config.name}:${name} ]; if (typeof lifecycle === ‘function’) { await lifecycle(); } } // 状态管理 isLoaded(): boolean { return this.loaded; } setLoaded(loaded: boolean): void { this.loaded = loaded; } isMounted(): boolean { return this.mounted; } setMounted(mounted: boolean): void { this.mounted = mounted; } // 资源管理 getResources(): AppResources | null { return this.resources; } setResources(resources: AppResources): void { this.resources = resources; } // 沙箱管理 getSandbox(): Sandbox | null { return this.sandbox; } setSandbox(sandbox: Sandbox): void { this.sandbox = sandbox; } // 消息通信 setMessageHandler(handler: MessageHandler): void { this.messageHandler = handler; } postMessage(message: any): void { this.messageHandler?.(message); } } // 沙箱基类 abstract class Sandbox { constructor(protected app: MicroApp) {} abstract mount(container: Element): Promise; abstract cleanup(): void; } // iframe沙箱 class IframeSandbox extends Sandbox { private iframe: HTMLIFrameElement | null = null; async mount(container: Element): Promise { this.iframe = document.createElement(‘iframe’); this.iframe.src = ‘about:blank’; this.iframe.style.width = ‘100%’; this.iframe.style.height = ‘100%’; this.iframe.style.border = ’none’; container.appendChild(this.iframe); // 注入资源到iframe await this.injectResources(); } cleanup(): void { this.iframe?.remove(); this.iframe = null; } private async injectResources(): Promise { if (!this.iframe) return; const resources = this.app.getResources(); if (!resources) return; const doc = this.iframe.contentDocument; if (!doc) return; // 注入样式 resources.styles.forEach(style => { const link = doc.createElement(’link’); link.rel = ‘stylesheet’; link.href = style; doc.head.appendChild(link); }); // 注入脚本 for (const script of resources.scripts) { await new Promise((resolve, reject) => { const scriptElement = doc.createElement(‘script’); scriptElement.src = script; scriptElement.onload = resolve; scriptElement.onerror = reject; doc.head.appendChild(scriptElement); }); } } } // JS沙箱 class JsSandbox extends Sandbox { private proxy: Window | null = null; async mount(container: Element): Promise { // 创建代理对象 this.proxy = new Proxy(window, { get: (target, property) => { // 处理特殊属性 if (this.isProtected(property)) { return target[property as keyof Window]; } // 返回沙箱中的值 return (this.app as any)[property]; }, set: (target, property, value) => { // 禁止修改保护属性 if (this.isProtected(property)) { return false; } // 设置值到沙箱 (this.app as any)[property] = value; return true; } }); // 在沙箱环境中执行代码 this.executeInSandbox(() => { const resources = this.app.getResources(); if (!resources) return; // 执行脚本 resources.scripts.forEach(script => { const scriptElement = document.createElement(‘script’); scriptElement.src = script; container.appendChild(scriptElement); }); }); } cleanup(): void { this.proxy = null; } private executeInSandbox(code: Function): void { if (!this.proxy) return; // 保存原始window const originalWindow = window; // 替换为代理对象 (window as any) = this.proxy; try { // 执行代码 code(); } finally { // 恢复原始window (window as any) = originalWindow; } } private isProtected(property: string | symbol): boolean { // 保护的全局属性列表 const protectedProps = [ ‘window’, ‘document’, ’location’, ‘history’ ]; return protectedProps.includes(property.toString()); } } // 事件总线 class EventBus { private static instance: EventBus; private handlers: Map>; private constructor() { this.handlers = new Map(); } static getInstance(): EventBus { if (!EventBus.instance) { EventBus.instance = new EventBus(); } return EventBus.instance; } on(event: string, handler: Function): void { if (!this.handlers.has(event)) { this.handlers.set(event, new Set()); } this.handlers.get(event)?.add(handler); } off(event: string, handler: Function): void { this.handlers.get(event)?.delete(handler); } emit(event: string, data?: any): void { this.handlers.get(event)?.forEach(handler => { handler(data); }); } } // 接口定义 interface ContainerConfig { sandbox: boolean; prefetch: boolean; isolation: ‘iframe’ | ‘js’; timeout: number; } interface MicroAppConfig { name: string; entry: string; container: string; props?: Record; } interface AppResources { scripts: string[]; styles: string[]; templates: string[]; } type MessageHandler = (message: any) => void; // 使用示例 const container = MicroFrontendContainer.getInstance(); // 注册微应用 container.registerApp({ name: ‘app1’, entry: ‘http://localhost:3001’, container: ‘#app1’ }); container.registerApp({ name: ‘app2’, entry: ‘http://localhost:3002’, container: ‘#app2’ }); // 启动微应用 await container.startApp(‘app1’); // 停止微应用 await container.stopApp(‘app1’);

最佳实践与建议

  1. 应用拆分
  • 基于业务域划分
  • 合理粒度
  • 独立演进
  • 技术栈灵活
  1. 依赖管理
  • 共享依赖
  • 版本控制
  • 构建优化
  • 运行时加载
  1. 通信机制
  • 事件总线
  • 状态共享
  • 数据隔离
  • 安全控制
  1. 部署策略
  • 独立部署
  • 灰度发布
  • 版本控制
  • 回滚机制

总结

前端微服务架构需要考虑以下方面:

  1. 应用拆分和集成策略
  2. 资源加载和性能优化
  3. 应用通信和状态管理
  4. 部署和运维支持
  5. 开发和协作流程 通过合理的微服务架构设计,可以提高前端应用的可维护性和扩展性。

学习资源

  1. 微前端架构设计
  2. 模块联邦实践
  3. 沙箱隔离方案
  4. 性能优化指南
  5. 部署运维实践

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇 终身学习,共同成长。 咱们下一期见 💻