简介
qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统
官网:https://qiankun.umijs.org/zh/guide
背景:
vue2.0 , vue-cli 5.0
安装乾坤
$ yarn add qiankun # 或者 npm i qiankun -S
main.js设置注册子应用
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'sub-vue',
entry: '//172.16.20.177:8081',
container: '#container',
activeRule: '/app-vue/',
props:{id:1}
},
]);
start();
配置vue.config.js
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package');
module.exports = defineConfig({
transpileDependencies: true,
publicPath:'/',
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}`,
libraryTarget: 'umd'
},
},
})
vue2.0 , vue-cli5.0 ,webpack5.0
src下面设置一个public-path.js
if (window.__POWERED_BY_QIANKUN__) {
// 这里不能擅自改为window不然微前端报错说找不到子应用入口
/* global __webpack_public_path__:writable */
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
vue.config.js
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package');
module.exports = defineConfig({
transpileDependencies: true,
publicPath: '/',
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
lintOnSave: false,
configureWebpack: {
output: {
library: `vueApp`,
libraryTarget: 'umd',
globalObject: 'window'
},
},
})
main.js
import './public-path';
import Vue from 'vue'
import App from './App.vue'
import routes from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import VueRouter from 'vue-router';
Vue.config.productionTip = false
Vue.use(ElementUI);
let router = null;
let instance = null;
console.log(window.__POWERED_BY_QIANKUN__, 'window.__POWERED_BY_QIANKUN__')
function render(props = {}) {
const { container } = props;
router = new VueRouter({
// base: '/app-vue/',
//.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
mode: 'hash',
routes,
});
instance = new Vue({
router,
// store,
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;
}
router/index.js
由于main.js 中new router了所以这里将原来的new router 改为输出路由数组
由于pushstate里面设置了前缀,所以路由子应用这里不设置前缀也可以直接访问
{
path: '/',
name: 'home',
component: HomeView
},
问题:用pushstate后回到主应用未带前缀的页面子应用的前缀也会跟着一起,除非刷新页面第一次
sandbox - boolean | { strictStyleIsolation?: boolean, experimentalStyleIsolation?: boolean } - 可选,是否开启沙箱,默认为 true。 experimentalStyleIsolation是在子应用的样式前面加上特定的一个hash属性,类似于scope但是不能防止全局在主应用的样式影响。
{ strictStyleIsolation: true } 时表示开启严格的样式隔离模式。这种模式下 qiankun 会为每个微应用的容器包裹上一个 shadow dom 节点,从而确保微应用的样式不会对全局造成影响。但是这个属性有兼容性,有时候需要特殊处理(react)。
看了官网对沙箱的叙述,总的来说有这个功能,但是效果不是很好,后续还在优化。看了很多文章也说乾坤沙箱能不用就不用。。。。
1.主应用传递参数给子应用
RegistrableApp里面props方法,可以在子应用微前端生命周期钩子中都可以获取到该参数name
registerMicroApps(
[
{
name: 'app1',
entry: '//localhost:8080',
container: '#container',
activeRule: '/react',
props: {
name: 'kuitos',
},
},
],
{
beforeLoad: (app) => console.log('before load', app.name),
beforeMount: [(app) => console.log('before mount', app.name)],
},
);
2.loadMicroApp 手动加载微应用方法
该方法也有props参数可以传递数据给子应用
3.initGlobalState(state) 定义全局状态
在主应用中使用,在子应用中通过props获取数据
使用主应用和子应用都使用hash模式的时候
主应用中:注册子应用的时候activeRule需要加上 # (history模式的时候activeRule: /app-vue,不用加#)
方法一:能正常访问子应用的其他配置
路由需要特意加上相对应的前缀
hash模式的时候router中的base不用设置,publicPath变量也使用默认值
方法二:使用hash模式 不加前缀
vue-router 的 hash 模式下不支持设置路由的 base,需要额外新建一个空的路由页面,将其他所有路由都作为它的 children:
{
path: "/",
component: NestedMenu,
meta: { title: "子页面测试", noCache: true },
children: [
{
path: "/testPage",
component: () => import("../views/TestPage.vue"),
meta: { title: "子页面测试", noCache: true },
// name: 'test',
hidden: true, // 不显示该路由到菜单上
},
{
path: '/',
name: 'home',
component: HomeView
},
{
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/AboutView.vue')
},
],
}
全局变量
window.POWERED_BY_QIANKUN 判断是否是微前端主应用进入
每当离开子应用,点击主应用页面的时候,会调用this.$destroy()方法销毁子应用内容
原因:有可能项目没有引入public-path.js
解决方法:https://qiankun.umijs.org/zh/faq#%E4%B8%BA%E4%BB%80%E4%B9%88%E5%BE%AE%E5%BA%94%E7%94%A8%E5%8A%A0%E8%BD%BD%E7%9A%84%E8%B5%84%E6%BA%90%E4%BC%9A-404
vue.config.js 添加即可解决
chainWebpack: (config) => {
config.module.rule('fonts').use('url-loader').loader('url-loader').options({}).end();
config.module.rule('images').use('url-loader').loader('url-loader').options({}).end();
},
乾坤会将主应用公共引入的css和其他vue中的样式转化为style 在主应用中head里面直接引入,就很容易造成子应用也同时使用该样式后被覆盖
这是在子应用设置了这个class,但是原则上子应用应该没有这个样式,不应该样式生效,但是由于主应用的原因颜色变成了蓝色,违背了两个项目互不干扰的原则。
快照模式:将项目的window属性先缓存,再需要用到的时候获取最新的数据替换修改
缺点:window属性过多的时候,耗费内存
proxy单例 :使用了proxy有兼容性问题
proxy多例:使用了proxy有兼容性问题