微前端实践
背景介绍
(一)什么是微前端
微前端提供了一种技术:可以将多个独立的Web应用聚合到一起,提供统一的访问入口。一个微前端应用给用户的感观就是一个完整的应用,但是在技术角度上是由一个个独立的应用组合通过某种方式组合而成的。
下图为micro-app的介绍图,微前端可以将不同技术独立部署的应用,用同一个入口进行访问。
(二)特点
目前的微前端框架一般都具有以下三个特点:
- 技术栈无关:主框架不限制接入应用的技术栈,子应用具备完全自主权。
- 独立性强:独立开发、独立部署,子应用仓库独立。
- 状态隔离:运行时每个子应用之间状态隔离。
(三)为什么出现微前端
2016年:Thoughtworks公司提出了微前端这个概念。
2018年:第一个微前端工具single-spa在github上开源。
2019年:基于single-spa的qiankun问世。
2021年:京东的micro-app发布初始版本。
2022年:腾讯的wujie-micro发布初始版本。
微服务的主要思路是:
- 将应用分解为小的、互相连接的微服务,一个微服务完成某个特定功能。
- 每个微服务都有自己的业务逻辑和适配器,不同的微服务,可以使用不同的技术去实现。
- 使用统一的网关进行调用。
微服务的主要思路是化繁为简,通过更加细致的划分,使得服务内部更加内聚,服务之间耦合性降低,有利于项目的团队开发和后期维护。把微服务的概念应用到前端,前端微服务/微前端服务就诞生了,简称其为微前端。
微前端框架
single-spa
介绍:single-spa是第一个微前端框架,核心就是定义了一套协议。协议包含主应用的配置信息和子应用的生命周期,通过这套协议,主应用可以方便的知道在什么情况下激活哪个子应用。通过路由检测触发渲染,把子应用挂载到相应的dom下。
优点:独立部署、技术栈无关、增量升级、维护部署测试简单
缺点:文档比较乱,上手难度高。功能过于基础,对项目改造成本高。缺少对js和css的隔离。无通信机制、不支持沙箱、样式冲突、无法预加载。
qiankun
介绍:蚂蚁金融孵化的项目,已在蚂蚁内部服务了超过 2000+ 线上应用。qiankun是基于single-spa提出的微前端框架, 提供了更加开箱即用的API。
优点:拥有single-spa的所有优点,并且有通信机制、支持沙箱、样式隔离
官网:https://qiankun.umijs.org/zh
micro-app
介绍:京东出品,一款基于WebComponent进行渲染的微前端框架。micro-app 不需要像 single-spa 和 qiankun 一样要求子应用修改渲染逻辑并暴露出方法,也不需要修改 Webpack 配置,是目前市面上接入微前端成本最低的方案。2021年7月发布初始版本,2023年10月发布1.0正式版本。
优点:使用简单、零依赖、兼容所有框架。
官网:https://micro-zoe.github.io/micro-app
wujie-micro
介绍:腾讯出品,基于 WebComponent 容器 + iframe 沙箱 的微前端框架。2022年7月发布初始版本,2022年11月发布1.0版本。
总结:方案很好,但框架刚出来,有很多坑。
官网:https://wujie-micro.github.io/doc/
总结:其他国内外的微服务框架还有很多,但基于语言和文档完善性考虑,这几个框架更适合入门实践。
qiankun实践
主应用
// 安装qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
// main.js
import { registerMicroApps, start } from 'qiankun'; // 引入依赖
registerMicroApps([ // 注册子应用
{
name: 'react app', // 和子应用的app名称最好一致
entry: '//localhost:7100', // 子应用地址
container: '#yourContainer', // 页面展示的加载容器
activeRule: '/yourActiveRule', // 激活路径
},
{
name: 'vue app',
entry: { scripts: ['//localhost:7100/main.js'] },
container: '#yourContainer2',
activeRule: '/yourActiveRule2',
},
]);
start(); // 启动qiankun
// vue.config.js
module.exports = {
devServer: {
port: 8000, // 启动端口
headers: {
// 重点1: 允许跨域访问子应用页面
'Access-Control-Allow-Origin': '*',
},
},
};
微应用
// 新建public-path.js文件
// 修改main.js文件
import './public-path'; import Vue from 'vue'; import VueRouter from 'vue-router'; // 需要先安装vue-router import App from './App.vue'; import routes from './router'; // 需要建router.js文件,自己定义路由 Vue.config.productionTip = false; let router = null; let instance = null; function render(props = {}) { const { container } = props; router = new VueRouter({ base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/', // app-vue要改为微应用的项目名 mode: 'history', // mode一定要配置 routes, }); instance = new Vue({ router, render: (h) => h(App), }).$mount(container ? container.querySelector('#app') : '#app'); } // 独立运行时 if (!window.__POWERED_BY_QIANKUN__) { render(); } export async function bootstrap() { console.log('[vue] vue app bootstraped'); } export async function mount(props) {
// 主应用如果传数据给微应用,可以在这个方法中处理 console.log('[vue] props from main framework', props); render(props); } export async function unmount() { instance.$destroy(); instance.$el.innerHTML = ''; instance = null; router = null; }
// 修改vue.config.js文件
micro-app实践
主应用
// 安装micro-app npm i @micro-zoe/micro-app --save
// 修改Main.jsimport microApp from '@micro-zoe/micro-app'
microApp.start()
子应用
// 新建my-page.vue export function MyPage () { return ( <div> <h1>子应用👇</h1> // name:应用名称, url:应用地址 <micro-app name='my-app' url='http://localhost:3000/'></micro-app> </div> ) } // 修改vue.config.js devServer: { headers: { 'Access-Control-Allow-Origin': '*', } },
相比qiankun,micro-app要配置的内容就少很多了。