当前位置: 首页 > article >正文

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

前端微服务架构实践 🏗️

引言

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

微服务架构概述

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

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

微服务架构实现

微前端容器

// 微前端容器类
class MicroFrontendContainer {private static instance: MicroFrontendContainer;private apps: Map<string, MicroApp>;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<void> {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<void> {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<void> {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<void> {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<AppResources> {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<void> {// 注入样式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<void> {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<void> {if (!app.isMounted()) {return;}// 执行生命周期钩子await app.beforeUnmount();// 移除DOMconst 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<void> {await this.invokeLifecycle('beforeMount');}async afterMount(): Promise<void> {await this.invokeLifecycle('afterMount');}async beforeUnmount(): Promise<void> {await this.invokeLifecycle('beforeUnmount');}async afterUnmount(): Promise<void> {await this.invokeLifecycle('afterUnmount');}// 调用生命周期函数private async invokeLifecycle(name: string): Promise<void> {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<void>;abstract cleanup(): void;
}// iframe沙箱
class IframeSandbox extends Sandbox {private iframe: HTMLIFrameElement | null = null;async mount(container: Element): Promise<void> {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);// 注入资源到iframeawait this.injectResources();}cleanup(): void {this.iframe?.remove();this.iframe = null;}private async injectResources(): Promise<void> {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<void> {// 创建代理对象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;// 保存原始windowconst 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<string, Set<Function>>;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<string, any>;
}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. 应用拆分

    • 基于业务域划分
    • 合理粒度
    • 独立演进
    • 技术栈灵活
  2. 依赖管理

    • 共享依赖
    • 版本控制
    • 构建优化
    • 运行时加载
  3. 通信机制

    • 事件总线
    • 状态共享
    • 数据隔离
    • 安全控制
  4. 部署策略

    • 独立部署
    • 灰度发布
    • 版本控制
    • 回滚机制

总结

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

  1. 应用拆分和集成策略
  2. 资源加载和性能优化
  3. 应用通信和状态管理
  4. 部署和运维支持
  5. 开发和协作流程

通过合理的微服务架构设计,可以提高前端应用的可维护性和扩展性。

学习资源

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

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

相关文章:

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

前端微服务架构实践 &#x1f3d7;️ 引言 随着前端应用规模的不断扩大&#xff0c;微服务架构在前端领域的应用越来越广泛。本文将深入探讨前端微服务架构的实现方案、最佳实践和相关工具。 微服务架构概述 前端微服务架构主要包括以下方面&#xff1a; 应用拆分&#xf…...

Windows系统中安装Rust工具链方法

Windows系统中安装Rust工具链方法 在Windows上使用PowerShell的命令来下载rustup-init.exe文件。 此外&#xff0c;安装完成后&#xff0c;需要确保Rust的环境变量生效&#xff0c;可能需要重启终端或手动执行设置路径的命令。然后继续升级pip并安装tiktoken。 总结步骤应该是…...

Postman下载安装及简单入门

一&#xff0e;Postman简介 Postman是一款API测试工具&#xff0c;可以帮助开发、测试人员发送HTTP请求&#xff0c;与各种API进行交互&#xff0c;并分析响应 二&#xff0e;下载与安装 访问Postman官网&#xff08;https://www.postman.com/&#xff09;&#xff0c;下载适…...

vulnhub靶场之loly靶机

前言 挑战攻克该靶机30分钟 靶机&#xff1a;loly靶机&#xff0c;IP地址为192.168.10.11 攻击&#xff1a;kali&#xff0c;IP地址为192.168.10.6 靶机和攻击机都采用VMware虚拟机&#xff0c;都采用桥接网卡模式 文章涉及的靶机及工具&#xff0c;都可以自行访问官网或者项…...

原生微信小程序实现导航漫游(Tour)

效果&#xff1a; 小程序实现导航漫游 1、组件 miniprogram/components/tour/index.wxml <!--wxml--> <view class"guide" wx:if"{{showGuide}}"><view style"{{guideStyle}}" class"guide-box"><view class&quo…...

LLM论文笔记 25: Chain-of-Thought Reasoning without Prompting

Arxiv日期&#xff1a;2024.5.31机构&#xff1a;Google DeepMind 关键词 cot-decoding推理路径pretrain 核心结论 1. LLMs 不需要prompting就可以生成链式推理路径&#xff0c;prompting只是将这些能力显性化的一种手段 2. cot path 往往与更高的model confidence相关&…...

新型XCSSET恶意软件利用增强混淆技术攻击macOS用户

微软威胁情报团队发现了一种新型的XCSSET变种&#xff0c;这是一种复杂的模块化macOS恶意软件&#xff0c;能够感染Xcode项目&#xff0c;并在开发者构建这些项目时执行。 这是自2022年以来的首个已知XCSSET变种&#xff0c;采用了增强的混淆方法、更新的持久化机制以及新的感…...

Redis存数据就像存钱:RDB定期存款 vs AOF实时记账

Redis持久化 ◆ 核心概念1. ◆ 持久化全景图2. ◆ 生产环境黄金法则 ◆ RDB深度优化1. ◆ 生产配置精要2. ◆ 高级触发场景3. ◆ 故障应急方案 ◆ AOF深度解析1. ◆ 7.0版本革命性改进2. ◆ 同步策略深度测试3. ◆ 重写过程优化 ◆ 混合持久化实战1. ◆ 配置示例2. ◆ 数据恢复…...

[C++面试] 关于deque

一、入门 1、deque与vector的区别 deque的迭代器包含以下信息&#xff1a; 当前缓冲区指针&#xff08;current_buffer&#xff09;当前元素在缓冲区内的位置&#xff08;current&#xff09;中控器的位置&#xff08;map&#xff09; 每次移动迭代器时&#xff0c;需检查是…...

施磊老师c++(七)

STL组件 文章目录 STL组件1.整体学习内容2.vector容器3.deque和listdeque--双端队列容器list--链表容器 4.vector,deque,list对比主要内容面经问题 5.详解容器适配器--stack, queue, priority_queue容器适配器stack-栈queue-队列priority_queue-优先级队列总结 6.无序关联容器关…...

八股文——C 语言宏、`volatile`、`static`、动态内存管理、堆与栈的区别

文章目录 1. #&#xff08;字符串化操作符&#xff09;作用&#xff1a;示例&#xff1a; 2. ##&#xff08;符号连接操作符&#xff09;作用&#xff1a;示例1&#xff1a;动态生成变量名 3. volatile 关键字作用&#xff1a;示例&#xff1a; 4. static 关键字作用&#xff1…...

C++初阶——类和对象(三) 构造函数、析构函数

C初阶——类和对象&#xff08;三&#xff09; 上期内容&#xff0c;我们围绕类对象模型的大小计算&#xff0c;成员存储方式&#xff0c;this指针&#xff0c;以及C实现栈和C语言的比较&#xff0c;进一步认识了C的封装特性。本期内容&#xff0c;我们开始介绍类的默认成员函…...

【Function】使用托管身份调用Function App触发器,以增强安全性

推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 1. 背景介绍2. 设置3. 使用Web应用调用Function App触发器(Node.js示例)4. 执行结果此方法允许您使用托管身份(Managed Identity)调…...

x012-MSP430F249智能步进电动百叶窗_proteus_光敏电阻_步进电机_仿真

https://www.dong-blog.fun/post/1997 46 、智能步进电动百叶窗 基本要求&#xff1a; 用一台步进电机控制百叶窗叶片的旋转&#xff08;正转/反转&#xff09; 用 LED 数码管显示旋转角度 设置按键&#xff1a; 手动/自动切换、手动正转和手动反转&#xff0c;停止/启动键 用一…...

牛客周赛85 题解 Java ABCDEFG

A小紫的均势博弈 判断输入的 n 是奇数还是偶数 import java.io.*; import java.math.*; import java.util.*;public class Main {static IoScanner sc new IoScanner();static final int mod(int) (1e97);static void solve() throws IOException {int nsc.nextInt();if(n%2…...

# RAG 框架 # 一文入门 全链路RAG系统构建与优化 —— 架构、策略与实践

本文全面阐述了RAG系统从数据收集、数据清洗&#xff08;包括领域专有名词处理&#xff09;、智能数据分块与QA对生成&#xff0c;到向量化、向量数据库选择与配置&#xff0c;再到检索方式及重排序&#xff0c;直至整合输出、监控反馈和安全保障的全流程。通过这一完整方案&am…...

【Golang】第二弹-----变量、基本数据类型、标识符

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;Golang &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一、变量 1.1基本介绍…...

c#:使用Modbus RTU协议

Modbus是一种广泛应用于工业自动化领域的通信协议&#xff0c;支持多种传输方式&#xff0c;如RTU、TCP等。其中&#xff0c;Modbus RTU是一种基于串行通信的协议&#xff0c;具有高效、可靠的特点。本文将详细介绍Modbus RTU协议的基本原理&#xff0c;并重点解析功能码0x03&a…...

linux系统CentOS 7版本搭建NFS共享存储

一、什么是NFS共享存储方式 NFS共享存储方式 是一种分布式文件系统协议&#xff0c;允许客户端通过网络访问远程服务器上的文件&#xff0c;就像访问本地文件一样。 二、 NFS的基本概念 &#xff08;1&#xff09;服务器端&#xff1a;提供共享存储的机器&#xff0c;负责导…...

Matlab 基于SVPWM的VF三电平逆变器异步电机速度控制

1、内容简介 略 Matlab 167-基于SVPWM的VF三电平逆变器异步电机速度控制 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略...

Android Dagger2 框架依赖图构建模块深度剖析(三)

一、引言 在 Android 开发中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff0c;简称 DI&#xff09;是一种重要的设计模式&#xff0c;它能够降低代码的耦合度&#xff0c;提高代码的可测试性和可维护性。Dagger 2 作为一款高效的依赖注入框架&#xff0c;在编…...

(一)微服务初见之 Spring Cloud 介绍

微服务架构简介 从单体应用架构发展到SOA架构&#xff0c;再到微服务架构&#xff0c;应用架构经历了多年的不断演进。微服务架构不是凭空产生的&#xff0c;而是技术发展的必然结果&#xff0c;分布式云平台的应用环境使得微服务代替单体应用成为互联网大型系统的架构选择。目…...

python--面试题--基础题

join() 和 split() 函数 join() 函数可以将指定的字符添加到字符串中。 a[my, name, shi, wzngz] print(..join(a)) 输出结果&#xff1a;my.name.shi.wzngz split() 函数可以用指定的字符分割字符串 a"my name shi wzngz " print(a.split()) 输出结果&#xff…...

架构思维:软件建模与架构设计的关键要点

文章目录 1. 软件建模的核心概念2. 七种常用UML图及其应用场景类图时序图组件图部署图用例图状态图活动图 3. 软件设计文档的三阶段结构4. 架构设计的关键实践1. 用例图&#xff1a;核心功能模块2. 部署图&#xff1a;架构演进阶段3. 技术挑战与解决方案4. 关键架构图示例5. 架…...

【RNN神经网络】序列模型与RNN神经网络

前言 清库存。正式切入大模型后&#xff0c;打算把基础知识都梳理一遍&#xff0c;然后写了两篇就发现写不动了&#xff0c;后面就捡重要的记录。RNN知识仅此一篇记录&#xff0c;扫盲记录。 【自然语言处理】 &#xff08;Natural Language Processing&#xff0c;NLP&#xf…...

Python文件管理

目录 一、文本文件读写 1、相关函数 2、读写文件 3、使用readline读取一行 4、读写文件的异常处理 5、添加内容 二、文本文件的编码 1、常见的编码 2、Python程序的编码 3、指定编码 三、文件的路径 1、相对路径 2、绝对路径 3、路径的改变 四、文件夹操作 五、…...

vue3 前端路由权限控制与字典数据缓存实践(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 从实战中出发&#xff1a; 1. 基本知识 Vue3 和 Java 通信时如何进行字典数据管理 需要了解字典数据的结构。通常&#x…...

基于javaweb的SpringBoot精美物流管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…...

【极光 Orbit·STC8x】05. GPIO库函数驱动LED流动

【极光 OrbitSTC8】05. GPIO库函数驱动LED流动 七律 逐光流转 八灯列阵若星河&#xff0c;状态为舟渡长波。 寄存器中藏玄机&#xff0c;Switch语句定山河。 循环往复如潮涌&#xff0c;步骤变量掌沉浮。 单片机前展锋芒&#xff0c;代码织就光之舞。 摘要 本文基于STC8H8K6…...

DeepSeek进阶应用(二):结合Kimi制作PPT(双AI协作教程)

&#x1f31f;引言&#xff1a; DeepSeek作为国产AI大模型&#xff0c;以强大的逻辑推理和结构化内容生成能力著称&#xff0c;擅长根据用户需求生成PPT大纲或Markdown文本&#xff1b;Kimi的PPT助手则能解析结构化内容并套用模板快速生成美观的PPT&#xff0c;两者结合实现“内…...