> 文章列表 > Vue:关于微前端的整合

Vue:关于微前端的整合

Vue:关于微前端的整合

目录

  • 微前端是什么?
    • 背景
    • 核心价值
  • 目前微前端的几种解决方案
    • iframe
    • 阿里乾坤 qiankun (阿里 14.2k)
    • microApp (京东 4k)
    • 无界:(腾讯 2k)
    • 小结
  • microApp基础示例
    • 1. 基座应用
      • 1. 依赖版本
      • 2. main.js引入
      • 3. router/index.js路由设置
      • 4. 各页面的内容
        • 4.1 Layout.vue页面
        • 4.2 my-page.vue页面
        • 4.3 parent1.vue和parent2.vue页面
    • 2. 子应用
      • 1. router/index.js路由设置
      • 2. vue.config.js设置跨域支持
      • 3. main.js引入自定义public-path.js文件
      • 4. public-path.js文件
    • 3. 注意事项
  • 乾坤示例

微前端是什么?

背景

1、微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
2、微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。

核心价值

1、不限制技术栈:主框架不限制接入应用的技术栈,微应用具备完全自主权
2、独立开发、独立部署:微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
3、增量升级(拓展):在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术
4、升级或重构:而微前端是一种非常好的实施渐进式重构的手段和策略
5、独立运行:每个微应用之间状态隔离,运行时状态不共享

目前微前端的几种解决方案

iframe

优点:

1、最稳定的、上手难度最低的。
2、提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决

缺点:

1、url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
2、加载是另一个window窗口,页面缩放时内部窗口内部缩放不同步,以及弹窗无法全局覆盖,和双滚动条问题;
3、通信复杂;要用postMessage,另外发送消息时需要在onload监听事件处理,会出现发送额外的噪声消息的情况只适合简单的页面渲染

阿里乾坤 qiankun (阿里 14.2k)

官网地址
基于 single-spa 的微前端实现库,通过监听 url change 事件,在路由变化时匹配到渲染的子应用并进行渲染,这个思路也是目前实现微前端的主流方式。

特点

1、基于 single-spa 封装,提供了更加开箱即用的 API。
2、技术栈无关,任意技术栈的应用均可 使用/接入,不论是React/Vue/Angular/JQuery 还是其他等框架。
3、HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
4、样式隔离,确保微应用之间样式互相不干扰。
5、JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
6、资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
7、umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。

不足

1、 适配成本比较高,工程化、生命周期、静态资源路径、路由等都要做一系列的适配工作;
2、css 沙箱采用严格隔离会有各种问题,js 沙箱在某些场景下执行性能下降严重;
3、无法同时激活多个子应用,也不支持子应用保活;
4、无法支持 vite 等 esmodule 脚本运行;

microApp (京东 4k)

官网地址
micro-app是京东零售推出的一款微前端框架,它基于类WebComponent进行渲染,从组件化的思维实现微前端。

核心功能在CustomElement基础上进行构建,CustomElement用于创建自定义标签,并提供了元素的渲染、卸载、属性修改等钩子函数,我们通过钩子函数获知微应用的渲染时机,并将自定义标签作为容器,微应用的所有元素和样式作用域都无法逃离容器边界,从而形成一个封闭的环境。

特点

1、JS 沙箱。
2、样式隔离。
3、元素隔离。
4、预加载。
5、资源地址补全。
6、插件系统。
7、数据通信。
8、与技术栈无关
9、支持子应用保活

不足

1、接入成本较 qiankun 有所降低,但是路由依然存在依赖;
2、多应用激活后无法保持各子应用的路由状态,刷新后全部丢失;
3、css 沙箱依然无法绝对的隔离,js 沙箱做全局变量查找缓存,性能有所优化;
4、支持vite运行,但必须使用plugin改造子应用,且 js 代码没办法做沙箱隔离;
5、对于不支持 webcompnent 的浏览器没有做降级处理;

无界:(腾讯 2k)

官网地址
无界微前端方案基于 webcomponent 容器 + iframe 沙箱,能够完善的解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户的核心诉求。

小结

除了Iframe,乾坤microApp无界三个框架都可以实现JS 沙箱,样式隔离,数据通信的功能,并且任意技术栈的应用均可 使用/接入。

结合目前的实际工作情况(vue2,webpack),下面以vue进行demo测试JS 沙箱样式隔离数据通信(子应用保活)的功能。

microApp基础示例

1. 基座应用

1. 依赖版本

npm i @micro-zoe/micro-app --save

"@micro-zoe/micro-app": "^0.8.10",
"vue": "^2.6.11",

2. main.js引入

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 引入element
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// 引入microApp--start
import microApp from '@micro-zoe/micro-app'
microApp.start()
// 引入microApp--endVue.config.productionTip = falseVue.use(ElementUI)
new Vue({router,store,render: h => h(App)
}).$mount('#app')

3. router/index.js路由设置

import Vue from 'vue'
import VueRouter from 'vue-router'import Layout from '../views/Layout.vue'
import MyPage from '../views/my-page.vue'
import Parent1 from '../views/parent1.vue'
import Parent2 from '../views/parent2.vue'Vue.use(VueRouter)const routes = [{path: '/',redirect: '/layout'},{path: '/layout', // 基座项目的父路由name: 'layout',component: Layout,redirect: '/layout/parent1',children: [{path: 'parent1', // 基座项目的子路由1name: 'parent1',component: Parent1},{path: 'parent2', // 基座项目的子路由2name: 'parent2',component: Parent2},{// 👇 非严格匹配,/layout/my-page/* 都指向 MyPage 页面path: 'my-page/:page*', // 微服务的路由name: 'my-page',component: MyPage}]}// {//   path: '/my-page/:page*',//   name: 'my-page',//   component: MyPage// }
]const router = new VueRouter({mode: 'history',base: process.env.BASE_URL,routes
})export default router

4. 各页面的内容

4.1 Layout.vue页面

<template><div><el-menu:default-active="activeIndex"class="el-menu-demo"mode="horizontal"@select="handleSelect"><el-menu-item index="/layout/parent1">parent路由1</el-menu-item><el-menu-item index="/layout/parent2">parent路由2</el-menu-item><el-menu-item index="/layout/my-page/">children1-vue路由</el-menu-item></el-menu><router-view></router-view></div>
</template><script>
export default {name: 'layout',data () {return {activeIndex: '/layout/parent1'}},methods: {handleSelect (key, keyPath) {this.$router.push({ path: key })}},created () {// 刷新路由保持当前状态this.activeIndex = this.$route.path}
}
</script><style scoped>
</style>

4.2 my-page.vue页面

<template><div><h1>父应用页面----子应用</h1><!--name(必传):应用名称url(必传):应用地址,会被自动补全为http://localhost:3000/index.htmlbaseroute(可选):基座应用分配给子应用的基础路由,就是上面的 `/my-page`--><micro-appname="app1"url="http://localhost:3000/"baseroute="/my-page"></micro-app></div>
</template><script>
export default {name: 'my-page'
}
</script><style scoped>
</style>

4.3 parent1.vue和parent2.vue页面

<template><div>parent【1】</div>
</template><script>
export default {name: 'parent1'
}
</script><style scoped>
</style>

2. 子应用

1. router/index.js路由设置

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'Vue.use(VueRouter)const routes = [{path: '/',name: 'Home',component: Home},{path: '/about',name: 'About',// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visited.component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')}
]const router = new VueRouter({mode: 'history',// 👇👇👇👇👇 __MICRO_APP_BASE_ROUTE__ 为micro-app传入的基础路由.子应用可以通过window.__MICRO_APP_BASE_ROUTE__获取基座下发的baseroutebase: window.__MICRO_APP_BASE_ROUTE__ || process.env.BASE_URL,routes
})export default router

2. vue.config.js设置跨域支持

module.exports = {devServer: {port: 3000,headers: {'Access-Control-Allow-Origin': '*'}}
}

3. main.js引入自定义public-path.js文件

// main.js
import './public-path'
import Vue from 'vue'
import App from './App.vue'
import router from './router'Vue.config.productionTip = falseconst app = new Vue({router,render: (h) => h(App)
}).$mount('#app')// 监听卸载操作
window.addEventListener('unmount', function () {app.$destroy()
})

4. public-path.js文件

// public-path.js
// __MICRO_APP_ENVIRONMENT__和__MICRO_APP_PUBLIC_PATH__是由micro-app注入的全局变量
if (window.__MICRO_APP_ENVIRONMENT__) {// eslint-disable-next-line__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
}

3. 注意事项

  1. name(my-page.vue)必须以字母开头,且不可以带有除中划线和下划线外的特殊符号
  2. url只是html地址,子应用的页面渲染还是基于浏览器地址的
  3. baseroute的作用请查看官网路由配置
  4. 子应用必须支持跨域访问,跨域配置参考这里
  5. 官网地址

乾坤示例

参考链接:https://blog.csdn.net/weixin_43193877/article/details/125717755