微前端解决方案之MicroApp
目录
什么是微前端
简介
好处特性
技术栈自由化
组织架构解耦
工程效能提升
系统可靠性增强
运维成本优化
用户体验升级
商业价值转化
简介
基本使用
主应用
安装
核心代码
子应用A
子应用B
应用通讯
主发子
子发主
什么是微前端
大家可能还是不认识微前端或者它的好处,下面我介绍微前端以及它的好处。
简介
微前端的概念是由ThoughtWorks在2016年提出的,它借鉴了微服务的架构理念,核心在于将一个庞大的前端应用拆分成多个独立灵活的小型应用,每个应用都可以独立开发、独立运行、独立部署,再将这些小型应用融合为一个完整的应用,或者将原本运行已久、没有关联的几个应用融合为一个应用。微前端既可以将多个项目融合为一,又可以减少项目之间的耦合,提升项目扩展性,相比一整块的前端仓库,微前端架构下的前端仓库倾向于更小更灵活。
好处特性
技术栈自由化
核心价值:突破技术栈锁定(Technology Lock-in)
-
异构技术共存:允许 Vue/React/Angular 等不同框架同时运行
-
渐进式升级:老系统可保留原有技术栈(如 jQuery),新模块使用现代框架
-
最佳实践案例:蚂蚁金融云同时运行 15+ 不同技术栈的子应用
典型场景:
-
企业级应用中同时存在遗留系统和现代模块
-
跨团队协作时各团队保留技术选型自主权
组织架构解耦
核心价值:实现康威定律的逆向应用
-
垂直领域划分:按业务功能划分独立团队(商品/订单/用户团队)
-
自治开发:每个子应用独立 Git 仓库、CI/CD 流水线
-
数据统计:京东零售前端团队通过微前端架构将发布效率提升 300%
团队协作优势:
-
减少代码库冲突(Code Collision)
-
降低跨团队沟通成本(从每周 10+ 会议降至 2-3 次)
-
独立发布节奏(团队 A 每日发布,团队 B 双周发布)
工程效能提升
核心价值:突破单体应用瓶颈
-
构建优化:子应用独立构建(构建时间从 15 分钟降至 2 分钟内)
-
按需加载:首屏资源体积减少 40%-60%
-
热更新效率:局部更新替代全量刷新(开发环境保存响应速度提升 70%)
性能数据对比:
指标 | 单体应用 | 微前端架构 |
---|---|---|
构建时间 | 8min | 1.5min |
首屏加载 | 2.8s | 1.2s |
热更新速度 | 3.2s | 0.8s |
系统可靠性增强
核心价值:构建故障隔离屏障
-
沙箱机制:子应用 JS/CSS 隔离(内存泄漏率降低 90%)
-
熔断策略:问题子应用自动降级(系统可用性从 99.5% 提升至 99.95%)
-
灰度发布:按子应用维度灰度(故障影响范围缩小 80%)
容灾案例:
某电商平台大促期间,支付子应用异常时,通过快速卸载问题模块保障主流程可用
运维成本优化
核心价值:实现精准运维
-
独立部署:子应用平均部署频率提升 5 倍
-
资源复用:共享组件库使用率从 30% 提升至 85%
-
监控粒度:可定位到具体子应用的性能瓶颈(定位效率提升 60%)
成本对比:
成本类型 | 传统架构 | 微前端架构 |
---|---|---|
部署失败率 | 12% | 3% |
回滚耗时 | 15min | 2min |
监控告警精度 | 模块级 | 函数级 |
用户体验升级
核心价值:打造无缝交互体验
-
路由保持:切换子应用时保留滚动条位置/表单状态
-
渐进加载:核心功能优先渲染(FCP 时间缩短 40%)
-
过渡动画:子应用切换时展示加载动画(用户感知等待时间减少 50%)
体验指标提升:
-
页面跳出率降低 25%
-
用户操作完成率提升 18%
-
平均会话时长增加 22%
商业价值转化
核心价值:加速业务创新
-
快速试错:新功能 AB 测试成本降低 70%
-
模块复用:跨产品线功能共享(开发成本减少 60%)
-
敏捷响应:需求交付周期从 2 周缩短至 3 天
典型案例:
某金融产品通过微前端架构,将信用卡申请模块快速复用到 5 个新业务线,带来 3000 万新增用户
简介
micro-app
是借鉴了 Web Component
的思想,通过 Custom Element
结合自定义的 Shadow Dom
,将微前端封装成一个类 Web Component
组件,从而实现微前端的组件化渲染。并且由于自定义 Shadow Dom
的隔离特性,micro-app
不需要像 single-spa
和 qiankun
一样要求子应用修改渲染逻辑并暴露出方法,也不需要修改 Webpack
配置,是目前市面上接入微前端成本最低的方案。
micro-app 官网
基本使用
微前端如同微服务一般,是有很多个子项目跟一个主项目,其技术栈都是不限的。只需要在主应用中使用 micro-app 即可。
那么现在我就简单举一个完整的例子:
- 主应用技术栈:Vue3、VueRouter4、Vite
- 子应用A技术栈:Vue3、VueRouter4、Vite
- 子应用B技术栈:React19、react-router-dom、Vite
主应用
下面是主应用的核心内容:
安装
首先需要安装micro-app。
npm安装方式:
npm i @micro-zoe/micro-app --save
yarn安装方式:
yarn add @micro-zoe/micro-app --save
pnpm安装方式:
pnpm i @micro-zoe/micro-app --save
核心代码
1.首先需要在mian.js中进行配置下面代码。
import microApp from '@micro-zoe/micro-app'
microApp.start()
2.接着是需要给每个子应用开一个单独的路由文件出来。(我这里有两个子应用,所以我需要准备两个子应用的路由文件)
创建这样两个文件:
// src/views/vue-page.vue
<template>
<div>
<micro-app name="vue-page" url="http://localhost:5173" baseroute="/vue-page" iframe></micro-app>
</div>
</template>
<script setup></script>
<style scoped></style>
// src/views/react-page.vue
<template>
<div>
<micro-app name="react-page" url="http://localhost:5174" baseroute="/react-page" iframe></micro-app>
</div>
</template>
<script setup></script>
<style scoped></style>
说明:
这里面两个页面都用到了一个micro-app组件,而且配置都是一样的,这里对组件的参数进行解释:
- name:每个
name
都对应一个应用,当多个应用同时渲染时,name不可以重复。当name
的值发生变化时,会卸载当前应用并重新渲染。 - url:url必须指向子应用的index.html,如:http://localhost:3000/ 或 http://localhost:3000/index.html
- baseroute:设置子应用的基础路由。在微前端环境下,子应用可以从window.__MICRO_APP_BASE_ROUTE__上获取baseroute的值,用于设置基础路由。
- iframe:默认开启with沙箱,如果with沙箱无法正常运行,可以尝试切换到iframe沙箱,比如vite。
在创建完成后,需要使用vue-router来配置一下路径。vue-router初始化文件如下:
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
component: () => import('../views/home.vue')
},
{
path: '/vue-page/:page*',
name: 'vue-page',
component: () => import('../views/vue-page.vue')
},
{
path: '/react-page/:page*',
name: 'react-page',
component: () => import('../views/react-page.vue')
}
]
})
export default router
最后在main.js 中进行配置即可了。
子应用A
这个应用业务正常写,只需要修改一部分的代码。
1.修改mian.js
// main.js
import { createApp } from 'vue'
import * as VueRouter from 'vue-router'
import routes from './router'
import App from './App.vue'
let app = null
let router = null
let history = null
// 👇 将渲染操作放入 mount 函数,子应用初始化时会自动执行
window.mount = () => {
history = VueRouter.createWebHistory()
router = VueRouter.createRouter({
history,
routes,
})
app = createApp(App)
app.use(router)
app.mount('#app')
}
// 👇 将卸载操作放入 unmount 函数,就是上面步骤2中的卸载函数
window.unmount = () => {
app.unmount()
history.destroy()
app = null
router = null
history = null
}
// 如果不在微前端环境,则直接执行mount渲染
if (!window.__MICRO_APP_ENVIRONMENT__) {
window.mount()
}
子应用B
// index.js
import React from "react"
import ReactDOM from "react-dom"
import App from './App'
// 👇 将渲染操作放入 mount 函数,子应用初始化时会自动执行
window.mount = () => {
ReactDOM.render(<App />, document.getElementById("root"))
}
// 👇 将卸载操作放入 unmount 函数,就是上面步骤2中的卸载函数
window.unmount = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("root"))
}
// 如果不在微前端环境,则直接执行mount渲染
if (!window.__MICRO_APP_ENVIRONMENT__) {
window.mount()
}
配置完这些,就完成了。只需要启动主应用,使用router跳转
应用通讯
主发子
// 主应用代码
<template>
<micro-app
:data="microAppData"
></micro-app>
</template>
<script setup>
const microAppData = {
userInfo: {
name: 'John',
role: 'admin'
}
}
</script>
// 子应用代码
if (window.__MICRO_APP_ENVIRONMENT__) {
window.microApp.addDataListener((data) => {
console.log('收到主应用数据:', data)
})
}
子发主
// 子应用代码
window.microApp.dispatch({ message: '来自子应用的数据' })