您当前的位置: 首页 > 技术文章 > 前端开发

qiankun 使用方法及基座子应用搭建实践

作者: 时间:2023-12-03阅读数:人阅读

1、介绍

Qiankun 是一个基于single-spa 的微前端实现库,旨在帮助大家能更简单,无痛的构建一个 生产可用微前端架构系统。 孵化自蚂蚁金融科技基于微前端架构的云产品统一接入平台,经过一批线上应用的充分检验及 打磨后,将其微前端内核抽离出来并开源。目前 qiankun 已在蚂蚁内部服务了超过 200+ 线 上应用,在易用性及完备性上,是值得信赖的。

2、核心设计理念

微前端的核心目标是将巨石应用拆解成若干可自治的松耦合微应用,而qiankun 的诸多设计均 是秉持这一原则。如:html entry, 沙箱,应用间通信等。确保微应用真正具备独立开发,独 立运行的能力;使得微应用的接入像使用iframe一样简单。

2.1 技术特性

技术栈无关,可支持多种技术框架;

独立开发,独立部署,独立运行;

基于single-spa 封装,提供了更加开箱即用的API;

HTML Entry 接入方式: import-html-entry 去加载对应html 文件;

样式隔离,JS 沙箱:确保微应用之间样式互相不干扰,确保微应用之间 全局变量/事件不冲 突;

资源预加载:在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度;

3、qiankun实战

3.1 架构搭建

qiankun 是基于基座模式的,所以它必然有一个基座应用(主应用),来管理各个子应用的加 载和卸载。我们以一个基于Vue的管理系统为例,来看如何搭建一个微前端项目。

3.2 基座搭建

  • qiankun安装:npm i qiankun -S
  • 搭建好一个常规的Vue应用,并编写好以上三个区域对应的组件,此时的根组件结构 大概如下
<template>
<div class="container">
<div class="app-header">
<prime-header></prime-header>
</div>
<div class="app-menu">
<prime-menu></prime-menu>
</div>
<div class="app-content">
<div id="container"></div>
</div>
<div class="help-taggle">
<prime-help></prime-menu>
</div>
</div>
</template>
  • 创建一个文件registerMicroApps,来定义各个子应用的入口:
// 导入注入应用,初始化数据的方法
import { registerMicroApps, initGlobalState } from "qiankun";
// 定义注入子应用的数组
export const registerList = [
    {
    name: "vue-child-app",
    //package.json 中的名字,唯一不可重复,qiankun 基于此变量进行缓存
    entry: "http://XXXX", // 子应用服务地址
    container: "#container", // 注入主应用的Id
    activeRule: "/portal/****", // 触发子应用路由
    },
]
// 导出注入子应用的方法,哪里使用,哪里调用
export function registerMicroAppsData() {
// 定义全局数据
const state = {
    changeMainData: true,
    userInfo: localStorage.getItem("**"),
};
// 初始化全局数据
const actions = initGlobalState(state);
// 全局数据发生改变时触发的方法
actions.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
// console.log("主应用22" + state, prev);
});
// 设置初始化数据
actions.setGlobalState(state);
actions.offGlobalStateChange();
// 注入子应用
registerMicroApps(registerList);
}
  • 创建子应用入口文件并启用qiankun
import { start } from "qiankun";
if (!window.qiankunStarted) {
    window.qiankunStarted = true;
    // 启动qiankun,并开启预加载
    start({ prefetch: true });
}
  • 路由配置history模式
const router = new VueRouter({
    mode: 'history',
    routes
});
  • 路由注入
  • {
        path: "/portal/", // 子应用路由前面统一标识
        component: Layout,
        hidden: true,
        children: [
        {
        path: "*", // paasPortal下所有的路径都适用
        //导入子应用的入口文件
        component: () => import("@/views/PortalContainer.vue"),
        name: "portal",
        title: "portal",
        meta: { title: "portal", icon: "", affix: false },
        // affix 属性与tagView 标签功能相关,true一直固定,false 可以关闭
            },
        ],
    },

    3.3 基座搭建完成

基座应用已经搭建好了。以history模式为例,根据 qiankun 和 single-spa 的实现原理, 当我们点击菜单的时候,我们可能会通过以下两种方式修改地址栏的地址:

window.history.pushState({}, '', '/portal/***');
window.location.href = 'https://blog.csdn.net/portal/***';

这两种方式都会触发 hashChange 事件,而 qiankun 借助 single-spa 所绑定的监听事件,会侦 测到地址变化,从而执行 single-spa 的 reroute 函数;随后 qiankun 通过 import-html-entry 提供的能力,去下载 /portal/***对应的html文件,并从中解析出所依赖的脚本和 样式文件。 qiankun 会将其封装在一个沙箱中,执行这些脚本并添加样式表,从而渲染出子应 用。经过这些步骤,应用 /portal/*** 就会像一个原生的组件一样被渲染到基座应 用的占位节点内。 当点击其他菜单时,同样会触发 hashChange 事件, single-spa 会重新执行 reroute ,卸载原 子应用,加载新的子应用。

 3.4 子应用搭建

  • 我们希望子应用可以像原生组件一样直接渲染到基座应用的 content 内容区域,那么按照 single-spa 应用入口协议,我们必须在子应用main.js内暴露出三个必要的生命周期钩子函 数:
let instance = null;
// 在 src 目录新增 public-path.js :
function render(props = {}) {
    const { container } = props;
    router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? "/portal/***/" : "/",
    mode: "history",
    routes
});
instance = new Vue({
    router,
    store,
    render: (h) => h(App)
}).$mount(container ? container.querySelector("#app") : "#app");
}
// 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,
// 不会再重复触发 bootstrap
export async function bootstrap() {
console.log("[vue] vue app bootstraped");
}
// 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
export async function mount(props) {
    console.log("[vue] props from main framework", props);
    console.log("通过主应用props传过来的值", props.text123);
    // 监听数据 写在vue原型链上,方便全局调用
    Vue.prototype.$onGlobalStateChange = props.onGlobalStateChange;
    Vue.prototype.$setGlobalState = props.setGlobalState;
    Vue.prototype.$onGlobalStateChange((state, prev) => {
    console.log("通过主应用initGlobalState传过来的值", state, prev);
});
// 设置数据,需要更改全局数据中的一个方法才能触发onGlobalStateChange方法
Vue.prototype.$setGlobalState({
    changeMainData: true;// 此属性为在全局设置的一个无效属性,可拿到全局数据
});
Vue.prototype.$text123 = props.text123;
Vue.prototype.$adminToken = props.adminToken;
    render(props);
}
export async function unmount() {
    // 实例销毁,与路由同时设置为空
    instance.$destroy();
    instance.$el.innerHTML = "";
    instance = null;
    router = null;
}
  • 在 src 目录新增 public-path.js :
if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
  • 打包配置修改( vue.config.js ):
// umd格式的应用会向外暴露指定的生命周期钩子函数,便于single-spa解析。
//jsonpFunction配置是webpack打包之后保存在window中的key,
// 只需保证各个子应用不一致即可。
const { name } = require('./package');
module.exports = {
    devServer: {
    headers: {
    'Access-Control-Allow-Origin': '*', // 跨域配置
    },
},
configureWebpack: {
    output: {
    library: `${name}-[name]`,
    libraryTarget: 'umd', // 把微应用打包成 umd 库格式
    jsonpFunction: `webpackJsonp_${name}`,
},
},
};
  • 路由配置
router = new VueRouter({
    // 路由前面统一添加path和基座中注入子应用的activeRule 相对应
    base: window.__POWERED_BY_QIANKUN__ ? "/portal/***/" : "/",
    mode: "history",
    routes
});
  • 完成以上配置后,分别启动基座应用和子应用。当访问基座应用并点击概况菜单时,地址栏的 url会发生变化, qiankun 就会自动去子应用所在的服务下载html文件,并解析出脚本和样式 进行渲染,于是这个子应用就会展示在图中的 content 内容区域了。 qiankun 搭建完成。

4、总结

4.1 常见问题(详情如上述)

  • 全局传值问题
  • 注入应用名称问题
  • 路由触发规则

4.1 参考官网

本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:licqi@yunshuaiweb.com

加载中~
如果您对我们的成果表示认同并且觉得对你有所帮助可以给我们捐赠。您的帮助是对我们最大的支持和动力!
捐赠我们
扫码支持 扫码支持
扫码捐赠,你说多少就多少
2
5
10
20
50
自定义
您当前余额:元
支付宝
微信
余额

打开支付宝扫一扫,即可进行扫码捐赠哦

打开微信扫一扫,即可进行扫码捐赠哦

打开QQ钱包扫一扫,即可进行扫码捐赠哦