微前端
微前端就是 将不同的功能按照不同的维度拆分成多个子应用。通过主应用来去加载这些子应用。(就是将一个项目中每个大模块分为几个小的应用,并且每个应用都能独立运行,然后整合到一起)
微前端的核心在于拆,拆完后在合!
当前比较完整的微前端体系 Single-SPA 和 quankun
两者总结:子应用可以独立构建,运行时动态加载,主子应用完全解耦,技术栈无关靠的是协议接入(子应用必须导出bootstrap、mount、unmount方法)
问题
有大佬会问:这不是iframe吗?
最大的问题–》如果使用iframe,iframe中的模块切换路由时用户刷新页面iframe引入的页面就会回到首页问题
SingleSPA
Single-spa 是一个将多个单页面应用聚合为一个整体应用的 JavaScript 微前端框架。 使用 single-spa 进行前端架构设计可以带来很多好处
缺陷:
不够灵活、不能动态加载js文件
样式不隔离、没有js沙箱机制(沙箱,即sandbox,顾名思义,就是让你的程序跑在一个隔离的环境下,不对外界的其他程序造成影响)
了解更多 > single-spa
qiankun
qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。
了解更多 > qiankun
快速体验
注意:此体验全部运用vue开发,vue-cil 搭建
准备
-
创建项目
qiankun-base // 基座
qiankun-child1 // 微应用1
qiankun-child2 // 微应用2 -
在基座中安装qiankun
npm i qiankun -S 或 yarn add qiankun
项目创建成功后根据相应文件修改即可
开发
基座修改
App.vue
<div id="app">
<el-menu :router="true" mode="horizontal" default-active="/">
<!-- 基座中可以放自己的路由 -->
<el-menu-item index="/">Home</el-menu-item>
<!-- 也可以引用其他子应用 -->
<el-menu-item index="/vuechild1">vue child1应用</el-menu-item>
<el-menu-item index="/vuechild2">vue child2应用</el-menu-item>
</el-menu>
<p>基座展示的内容↓</p>
<router-view />
<hr />
<p>子应用展示的内容↓</p>
<div id="vue-child1"></div>
<div id="vue-child2"></div>
</div>
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI)
// 基座
// 引入qiankun
import {
registerMicroApps, start } from 'qiankun';
// 定义所引应用配置集合
const apps = [
// 第一个子应用
{
// 必选,微应用的名称,微应用之间必须确保唯一
name: 'vueAppChild1',
// 必选,微应用的入口;默认会加载这个里面的html 解析里面的js 动态执行(前提是该子应用必须支持跨域)内部采用 fetch 请求
entry: '//localhost:8081',
// 必选,微应用的容器节点的选择器或者 Element 实例(就是子应用要在基座中显示在哪里)
container: '#vue-child1',
// 必选,微应用的激活规则。(何时显示该子应用)
activeRule: '/vuechild1',
},
// 第二个子应用
{
name: 'vueAppChild2',
entry: '//localhost:8082',
container: '#vue-child2',
activeRule: '/vuechild2',
}
]
/**
* 注册该子应用集
* registerMicroApps参数:
* apps - Array<RegistrableApp> - 必选,微应用的一些注册信息
* lifeCycles - LifeCycles - 可选,全局的微应用生命周期钩子
*/
registerMicroApps(apps);
/**
* 启动 qiankun。
* start(opts?) opts - Options 可选
*/
start();
new Vue({
router,
render: h => h(App)
}).$mount('#app')
子应用一修改
-
main.js
import Vue from 'vue' import App from './App.vue' import router from './router' // 子应用1 // 加载子应用中的 入口实例 这里时vue let instance = null; function render(props) { instance = new Vue({ router, render: h => h(App), }).$mount("#app")// 这里是挂载到自己的html中,基座会拿到这个挂载后的html,将其插入到基座中qiankun配置的container对应的DOM } // 当基座引用此子应用时修改webpack的publicPath配置,动态添加publicPath if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } // 让此微应用独立运行 if (!window.__POWERED_BY_QIANKUN__) { render(); } // 子应用入口必须暴露出三个方法(必须是promise的) // 子应用初始化时 // props 基座传给子应用的值(应用之间通信) export async function bootstrap(props) { }; // 子应用编译时 export async function mount(props) { render(props); }; // 子应用卸载时 export async function unmount(props) { // 销毁当前vue instance.$destroy(); };
-
创建vue.config.js文件,并配置
module.exports = { // 配置该子应用接受跨域 devServer: { port: 8081, headers: { 'Access-Control-Allow-Origin': '*' } }, // 修改webpack配置 configureWebpack: { output: { library: 'vueApp', // 打包为library库 libraryTarget: 'umd' // library 类型为 umd } } }
子应用二修改
与子 应用一 修改相似
运行结果
可能会遇到的问题
application ‘vueAppChild1’ died in status NOT_MOUNTED: [qiankun]: Target container with #vue-child1 not existed after vueAppChild1 mounted!
原因
我觉的是子应用的挂载元素名与基座挂载名冲突了
我的解决
修改基座或其他应用的挂载元素即可!!
我这边修改的是子应用一、子应用二的挂载名,基座不用动
public > index.html
main.js
到这里就结束了,后续还会更新 vue 系列相关,还请持续关注!
感谢阅读,若有错误可以在下方评论区留言哦!!!