前言
微前端(Micro-Frontends)它是将“微服务”的概念拓展到了前端领域。它没有定义框架、API,它是一个类似“微服务架构”的概念。
从前端的角度换句话来说,微前端就是将一个大型应用拆分为多个轻量的、功能独立且与技术栈无关的前端应用。 这样每个前端应用可以独立部署、升级、维护以及开发。
使用微前端为我们带来了什么?
1.在技术选择上的灵活
由于与技术栈无关的特性,主应用与微应用都可以灵活的选择不同的技术栈进行开发。
2.并行开发与团队自治
由于拆分为多个子应用,子应用间的开发可以单团队多人(多团队多人)并行开发。多个子应用可以由不同的团队来进行开发与管理,团队对应用的规划与代码的管理更加的自治。
不同的子应用由不同的团队负责,他们能够有效且快速的从用户角度出发,围绕业务功能去做垂直开发(业务的颗粒化),而不是围绕技术去做扩展,这样也会给团队带来更高的 凝聚力 ;
3.项目的增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略。
4.构建速度的提升
由一个大型应用拆分为多个轻量型应用,当对单个项目中的前端代码变少很多,在前端打包构建的时候,构建工具处理的文件量减少,打包速度也得到了提升。
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
微前端技术方案对比
1.路由分发式微前端
将大型项目拆分为多个前端服务,然后通过Nginx配置代理,主应用在域名根目录下,不同的路径代理到不同的前端服务,这是一个很早期的方案。
这种方案,更多的像是用多个前端应用的聚合。他们看上去像是一个完整的应用,其实不然。当从应用A跳转到应用B时,往往会需要刷新一下浏览器,用户体验感较差。
优点:
- 实施简单、快速
缺点:
- 切换应用时浏览器刷新,体验较差。
- 如果各应用间UI不统一,整体的割裂感会比较强。
2.iframe内联嵌入式
使用元素可以很方便的嵌入其他的页面到当前页面中。这是一个很古老的技术,却一直很管用。
优点:
- 子应用之间天然隔离,互不影响。
- 只要每个iframe来自同一个源,就可以使用
postMessageAPI来进行消息的传递。 - 易上手,实现简单。
缺点:
- iframe中的URL状态信息不能同步到主应用,无法使用浏览器的前进后退功能。
- 全局弹框无法很好的居中展示。
- 主应用以子应用上下文完全隔离,内存变量不共享。
- 每一次进入子应用都是一次浏览器上下文重建、资源加载的过程。
3.qiankun.js
qiankun 是一个基于 single-spa 的微前端实现库。他在主应用中注册并启动子应用,在子应用中需要做几个修改才可以正常工作。
-
新增
public-path.js文件,用于修改运行时的publicPath。 -
微应用建议使用
history模式的路由,需要设置路由base,值和它的activeRule是一样的。 -
在入口文件最顶部引入
public-path.js,修改并导出三个生命周期函数。 -
修改构建工具,允许开发环境跨域和
umd打包。
4.micro-app
micro-app是由京东前端团队推出的一款微前端框架,它借鉴了WebComponent的思想,通过js沙箱、样式隔离、元素隔离、路由隔离模拟实现了ShadowDom的隔离特性,并结合CustomElement将微前端封装成一个类WebComponent组件,从而实现微前端的组件化渲染。
5.qiankun.js与micro-app对比
通过对比我们不难发现,micro-app为开发者提供了更完善的功能,接入成本也是较低的。目前没有一个完美的方案来解决前端页面(或者说子系统)接入第三方系统,技术方案选型本就是做一次取舍。
微前端在项目中落地
最终我们选择使用macro-app来落地微前端。
主应用
首先,在主应用中安装相关依赖:
npm i @micro-zoe/micro-app --save
依赖安装完毕后,在项目的入口文件中初始化micro-app :
import microApp from '@micro-zoe/micro-app'
microApp.start()
如果当前项目采用typescript 来进行开发,还需要在src文件夹下增加types.d.ts 文件来拓展Window 的类型:
// types.d.ts
import { MicroApp } from "@micro-zoe/micro-app";
declare global {
interface Window {
microApp: MicroApp;
}
}
否则在使用typescript 进行开发的项目中,从window 上获取microApp属性会出现报错:类型“Window & typeof globalThis”上不存在属性“microApp”。
接下来,我们在主应用中嵌入子应用:
React:
export function MyPage () {
return (
<div>
<h1>子应用👇</h1>
// name:应用名称, url:应用地址
<micro-app name='my-app' url='http://localhost:3000/'></micro-app>
</div>
)
}
Vue:
<template>
<div>
<h1>子应用👇</h1>
<!-- name:应用名称, url:应用地址 -->
<micro-app name='my-app' url='http://localhost:3000/'></micro-app>
</div>
</template>
子应用
在webpack-dev-server的headers中设置跨域支持。
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
}
},
如果构建工具是使用vite ,那么不用单独设置子应用的跨域。