qiankun 微前端
为啥不用iframe
iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于 他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
iframe的弊端
- url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
- UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中
- 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
- 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
微前端架构具备以下几个核心价值:
-
技术栈无关
主框架不限制接入应用的技术栈,微应用具备完全自主权 -
独立开发、独立部署
微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 -
增量升级 在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
-
独立运行时
每个微应用之间状态隔离,运行时状态不共享
废话不多说 上代码
在搭建qiankun微前端的时候要搭建一个主应用的一个基座
我是以vue为基座 可以嵌入其他技术栈的项目vue react jquery Angular。。。。
qiankun主应用(基座)
1. 我们以qiankun + vue2.0为例创建一个主应用和一个子应用,路由模式均为history模式
vue create qiankun-main
复制代码
// 2. 在主应用qiankun-main
安装qiankun yarn add qiankun 或者 npm install qiankun --save、
复制代码
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { registerMicroApps, start } from 'qiankun' //新增部分,导入qiankun中的两个方法
const apps = [{
name: 'vueApp', //子应用的名称
entry: 'http://172.18.61.27:8083', //子应用的域名
container: '#vue', //承载子应用的容器,在上面App.vue中定义
activeRule: '/vue', // 被激活的子应用的路由
}]
registerMicroApps(apps); //注册子应用
start(); //启动qiankun
new Vue({
router,
render: h => h(App)
}).$mount('#app');
复制代码
src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "../views/home/home.vue";
import About from "../views/about";
Vue.use(VueRouter)
const routes = [{
path: '/',
name: 'Home',
// redirect: '/home',
component: Home,
},
{
path: '/about',
name: 'About',
component: About,
},
]
const router = new VueRouter({
routes,
base: '',
mode: 'history',
})
export default router
复制代码
app.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/vue">VueApp</router-link> <!--新增部分-->
</div>
<router-view />
<div id="vue"></div><!--新增部分,用于承载子应用-->
</div>
</template>
复制代码
vue.config.js
module.exports = {
lintOnSave: false, // 关闭eslint检测
devServer: {
port: 8084, //这里的端口是必须和父应用配置的子应用端口一致
headers: {
//因为qiankun内部请求都是fetch来请求资源,所以子应用必须允许跨域
'Access-Control-Allow-Origin': '*'
},
overlay: {
warning: false,
errors: false
}
},
configureWebpack: {
output: {
//资源打包路径
library: 'vueApp',
libraryTarget: 'umd'
}
}
}
复制代码
子应用(微服务)
vue create qiankun-child
复制代码
min.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
let instance = null;
function render(props = {}) {
const { container } = props;
instance = new Vue({
router,
store,
render: h => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
export async function mount(props) {
render(props);
}
//判断当前运行环境是独立运行的还是在父应用里面进行运行,配置全局的公共资源路径
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
//如果是独立运行window.__POWERED_BY_QIANKUN__=undefined
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
//最后暴露的三个方法是固定的,加载渲染以及销毁
export async function bootstrap() {}
// export async function mount(props){
// render();
// }
export async function unmount() {
instance.$destroy();
}
export async function update(props) {
// console.log('update props', props);
}
复制代码
src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Music from '../views/Home.vue'
import '../public-path'
Vue.use(VueRouter)
const routes = [{
path: '/Music',
name: 'Music',
component: Music
},
{
path: '/Dome',
name: 'Dome',
component: () =>
import ( /* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: window.__POWERED_BY_QIANKUN__ ? '/vue' : '/',
routes
})
export default router
复制代码
app.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/Music">Music</router-link> |
<router-link to="/Dome">About</router-link> |
<router-link to="/about">MVVM</router-link>
</div>
<router-view/>
</div>
</template>
复制代码
vue.cofig.js
module.exports = {
lintOnSave: false,
devServer: {
port: 8083,
headers: {
"Access-Control-Allow-Origin": "*"
}
},
configureWebpack: {
output: {
library: 'vueApp',
libraryTarget: 'umd'
}
}
}
复制代码