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

前端微服务实战:大型应用的拆分与治理

"这个系统已经无法维护了..."周五的架构评审会上,我盯着屏幕上那张错综复杂的依赖关系图发愁。作为一个运行了三年的企业级中后台系统,代码量已经超过 50 万行,构建时间长达 40 分钟,任何修改都可能引发连锁反应。

更让人头疼的是,随着业务的快速发展,不同业务线之间的耦合越来越严重。一个小小的样式修改都可能影响到其他模块的展示。经过团队讨论,我们决定采用微前端架构对系统进行拆分重构。

现状分析

首先梳理了系统目前面临的主要问题:

  • 构建部署效率低下
  • 团队协作成本高
  • 技术栈难以升级
  • 代码复用困难
  • 线上问题难以隔离

就像一座不断扩建的大楼,没有合理的分区和规划,最终变得杂乱无章。我们需要把这座大楼重新规划成一个个独立又互联的空间。

架构设计

经过调研和验证,我们选择了基于 single-spa 的微前端方案:

// 基座应用
import { registerApplication, start } from 'single-spa'// 注册子应用
const registerMicroApp = (name: string, entry: string) => {registerApplication({name,app: async () => {// 动态加载子应用const module = await System.import(entry)return module.default},activeWhen: location => {// 基于路由匹配激活子应用return location.pathname.startsWith(`/${name}`)}})
}// 子应用配置
const microApps = [{name: 'crm',entry: '//localhost:3001/main.js',activeRule: '/crm'},{name: 'erp',entry: '//localhost:3002/main.js',activeRule: '/erp'},{name: 'dashboard',entry: '//localhost:3003/main.js',activeRule: '/dashboard'}
]// 注册所有子应用
microApps.forEach(app => registerMicroApp(app.name, app.entry))// 启动微前端框架
start()

子应用改造

每个子应用需要暴露生命周期钩子:

// 子应用入口
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from './store'// 导出生命周期钩子
export async function bootstrap() {console.log('应用启动中...')
}export async function mount(props) {const { container, globalStore } = propsconst store = createStore(globalStore)ReactDOM.render(<Provider store={store}><App /></Provider>,container)
}export async function unmount(props) {const { container } = propsReactDOM.unmountComponentAtNode(container)
}

通信方案

子应用间的通信是一个关键问题,我们实现了一个事件总线:

// utils/eventBus.ts
class EventBus {private events = new Map<string, Function[]>()// 订阅事件on(event: string, callback: Function) {if (!this.events.has(event)) {this.events.set(event, [])}this.events.get(event).push(callback)// 返回取消订阅函数return () => {const callbacks = this.events.get(event)const index = callbacks.indexOf(callback)callbacks.splice(index, 1)}}// 发布事件emit(event: string, data?: any) {if (!this.events.has(event)) returnthis.events.get(event).forEach(callback => {try {callback(data)} catch (error) {console.error(`事件处理错误: ${event}`, error)}})}
}export const eventBus = new EventBus()

样式隔离

为了避免样式冲突,我们采用了 CSS Modules 和动态前缀:

// webpack.config.js
module.exports = {module: {rules: [{test: /\.css$/,use: ['style-loader',{loader: 'css-loader',options: {modules: {localIdentName: '[name]__[local]___[hash:base64:5]'}}},{loader: 'postcss-loader',options: {plugins: [require('postcss-prefix-selector')({prefix: `[data-app="${process.env.APP_NAME}"]`})]}}]}]}
}

性能优化

微前端架构下的性能优化主要从这几个方面入手:

// 预加载策略
const prefetchApps = async () => {const nextPossibleApps = predictNextApps()nextPossibleApps.forEach(app => {const script = document.createElement('link')script.rel = 'prefetch'script.href = app.entrydocument.head.appendChild(script)})
}// 共享依赖
const sharedDependencies = {react: {singleton: true,requiredVersion: '^17.0.0'},'react-dom': {singleton: true,requiredVersion: '^17.0.0'},'react-router-dom': {singleton: true,requiredVersion: '^5.2.0'}
}

实践效果

经过三个月的改造,我们取得了显著的成效:

  • 构建时间从40 分钟减少到 5 分钟
  • 各团队可以独立开发部署
  • 线上问题可以快速定位和修复
  • 新技术栈的尝试变得容易

最让我印象深刻的是一位同事说:"现在终于可以专注于业务开发,不用担心影响到其他团队了。"

经验总结

微前端架构就像城市规划,需要统筹兼顾又要保持灵活。我们的经验是:

合理分层 - 基座应用要足够稳定清晰边界 - 子应用之间要解耦统一规范 - 公共依赖要严格管理持续优化 - 性能问题要重点关注

写在最后

微前端不是银弹,它更像是一把双刃剑。使用得当可以大幅提升开发效率,但也会带来一定的复杂性。关键是要在架构设计时充分权衡,在实施过程中严格把控。

有什么问题欢迎在评论区讨论,让我们一起探讨微前端架构的最佳实践!

如果觉得有帮助,别忘了点赞关注,我会继续分享更多实战经验~

相关文章:

前端微服务实战:大型应用的拆分与治理

"这个系统已经无法维护了..."周五的架构评审会上,我盯着屏幕上那张错综复杂的依赖关系图发愁。作为一个运行了三年的企业级中后台系统,代码量已经超过 50 万行,构建时间长达 40 分钟,任何修改都可能引发连锁反应。 更让人头疼的是,随着业务的快速发展,不同业务线之间…...

Linux shell的七大功能 --- history

1.直接输入“history” 这个命令可以显示出曾经使用过的命令&#xff08;最近时间的500条&#xff09; history 2.“history”命令也可以搭配其他命令一起使用。 例&#xff1a;history | grep "vim"&#xff0c;找出所有包含“vim”的记录&#xff1b; 也可以搭配…...

C++ webrtc开发(非原生开发,linux上使用libdatachannel库)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、libdatachannel库的下载和build二、开始使用 1.2.引入库3.开始使用 总结 前言 使用c开发webrtc在互联网上留下的资料甚少&#xff0c;经过我一段时间的探…...

C语言刷题

1. 题目描述 根据给出的三角形3条边a:b.c(a.b,c<100.000)&#xff0c;计算三角形的周长和面积。 输入描述: 一行&#xff0c;三角形3条边(能构成三角形)&#xff0c;中间用一个空格隔开. 输出描述: 一行&#xff0c;三角形周长和面积保留两位小数&#xff0c;中问用一个空…...

LabVIEW实现RFID通信

目录 1、RFID通信原理 2、硬件环境部署 3、程序架构 4、前面板设计 5、程序框图设计 6、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利用LabVIEW和常用模块实现物联网系…...

Linux 网络流量控制 - 实现概述

摘要 Linux 提供了一整套丰富的流量控制(traffic control)功能。本文档概述了相应的内核代码设计&#xff0c;描述了其结构&#xff0c;并通过描述一种新的排队策略来说明新元素的添加。 1 引言 最近的Linux内核提供了多种流量控制功能。Alexey Kuznetsov&#xff08;kuznet…...

分布式 令牌桶算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & 令牌桶算法 & 总结》《分布式 & 令牌桶算法 & 问题》 参考文献 《【算法】令牌桶算法》 概述 简介 TBA Token Bucket Algorithm 令牌桶算法是一种流行于网络通信领域的流量控制/频率限制算法。令牌…...

FFMPEG视频转图片

用FFMPEG视频转图片&#xff0c;并且for循环 import os import subprocess# 输入文件夹和输出文件夹路径 input_folder r"I:\xxx" output_base_folder r"D:\xxx\YOLO\data\video" output_subfolder_name "20240609"# 创建输出子文件夹 output…...

docker入门实践---虚拟机环境配置

文章目录 1.检查内核版本2.确定centos7可以上网3.关闭防火墙4.关闭防火墙5.更换阿里云6.安装gcc7.设置镜像仓库&#xff08;阿里云&#xff09;8更新软件包9.安装docket-ce10.启动docker11.普通用户权限设置 1.检查内核版本 2.确定centos7可以上网 3.关闭防火墙 下面的这个表示…...

java要防止重复序列化的问题JSON.toJSONString转义问题

要防止重复序列化的问题JSON.toJSONString(entity) 20241213 10:29 背景&#xff1a; 我在设计业务实现echart图标渲染&#xff0c;业务接口实时性查询耗时很长&#xff0c;为了提高系统可用性和用户体验&#xff0c;采用中间表的方案——即在中间表中存储大JSON。 但是在自测…...

TS的类型守卫、类型约束实践

类型守卫 // 基础类型判断 const arr [30, 50] console.log(typeof arr) // object const set new Set(arr) console.log(typeof set) // object const map new Map() console.log(typeof map) // objectclass Customer {constructor() {}buy(method:string) {console.log(…...

文件转曲,限制PDF文件编辑的最佳方案!

随着数字化进程的推进&#xff0c;PDF文件凭借其多样化的功能和优越的兼容性已经被广泛使用&#xff0c;成为了现代文档交流和存储的重要工具&#xff0c;满足了不同用户和行业的需求。 虽然PDF格式文件的功能很多&#xff0c;常见的比如阅读、编辑、加密、转换、还可用于印刷…...

MySQL系列之数据授权(安全)

导览 前言Q&#xff1a;如何对MySQL数据库进行授权管理一、MySQL的“特权”1. 权限级别2. 权限清单 二、授权操作1. 查看权限2. 分配权限3. 回收权限 结语精彩回放 前言 看过博主上一篇的盆友&#xff0c;可以Get到一个知识点&#xff1a;数据授权&#xff08;eg&#xff1a;g…...

用 Python 实现经典的 2048 游戏:一步步带你打造属于你的小游戏!

用 Python 实现经典的 2048 游戏&#xff1a;一步步带你打造属于你的小游戏&#xff01;&#xff08;结尾附完整代码&#xff09; 简介 2048 是一个简单而又令人上瘾的数字拼图游戏。玩家通过滑动方块使相同数字的方块合并&#xff0c;目标是创造出数字 2048&#xff01;在这篇…...

Vue vs. React:两大前端框架的深度对比与分析(一)

前言 在当今快速发展的前端领域中&#xff0c;Vue和React作为两个备受瞩目的前端框架&#xff0c;已经成为许多开发者的首选。这两个框架凭借其出色的设计和强大的功能&#xff0c;在构建现代化、高效性能的Web应用方面扮演着重要角色。 Vue和React都以其独特的特点吸引了众多开…...

React 进阶深入理解核心概念与高阶实践

在上一节中&#xff0c;我们学习了 React 的基础知识&#xff0c;包括组件、状态管理和基本操作。接下来&#xff0c;我们将进一步探索 React 的高级功能和实战技巧&#xff0c;例如 组件间通信、高阶组件、Context API、React Router 等。这些内容将帮助你构建更复杂、功能更丰…...

Linux shell的七大功能 ---自动补齐、管道机制、别名

1、自动补齐---TAB 输入命令的前几个字符&#xff0c;按下tab键&#xff0c;会自动补齐完整的字符&#xff0c;若有多个命令、文件或目录的前几个字符相同&#xff0c;按下tab将会全部列举出来 2、管道机制---| 例如&#xff1a;ls -- help |more 将有关ls的帮助内容传递给“|…...

XML 在线格式化 - 加菲工具

XML 在线格式化 打开网站 加菲工具 选择“XML 在线格式化” 输入XML&#xff0c;点击左上角的“格式化”按钮 得到格式化后的结果...

java_多态的应用

多态数组 应用实例:现有一个继承结构如下&#xff1a;要求创建 1 个 Person 对象、2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中&#xff0c;并调用每个对象 代码 Person类 package com.hspedu.poly_.polyarr_;import javax.swing.*;/*** author:寰愬悏瓒&#xf…...

Python+OpenCV系列:模版匹配

文章目录 1. 模板匹配基本原理2. cv2.matchTemplate() 函数函数原型&#xff1a; 3. 模板匹配步骤4. 单目标模板匹配示例5. 多目标模板匹配多目标模板匹配示例代码解析&#xff1a; 6. 多模板匹配多模板匹配示例代码解析 7. 总结 模板匹配是一种在图像中寻找模板的位置的方法。…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...