一、介绍
1.背景
qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。
qiankun 孵化自蚂蚁金融科技基于微前端架构的云产品统一接入平台,在经过一批线上应用的充分检验及打磨后,我们将其微前端内核抽取出来并开源,希望能同时帮助社区有类似需求的系统更方便的构建自己的微前端系统,同时也希望通过社区的帮助将 qiankun 打磨的更加成熟完善。
目前 qiankun 已在蚂蚁内部服务了超过 2000+ 线上应用,在易用性及完备性上,绝对是值得信赖的。
2.什么是微前端
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
微前端架构具备以下几个核心价值:
技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权
独立开发、独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
独立运行时 每个微应用之间状态隔离,运行时状态不共享
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
特性
📦 **基于 **single-spa 封装,提供了更加开箱即用的 API。
📱 技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
💪 HTML** Entry 接入方式**,让你接入微应用像使用 iframe 一样简单。
🛡 样式隔离,确保微应用之间样式互相不干扰。
🧳 JS** 沙箱**,确保微应用之间 全局变量/事件 不冲突。
⚡️ 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
🔌 umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。
3.开发前的准备工作
微前端框架搭建--qiankun
主应用不限技术栈,只需要提供一个容器 DOM,然后注册微应用并 start 即可, 微应用分为有 webpack 构建和无 webpack 构建项目,有 webpack 的微应用。
4.构建主项目
第一步、创建vue3的项目与正常创建项目无异,在这里不做过多描述
vue create vue3-demo-fa
第二部、将创建好的vue3项目作为主应用,在根目录先安装qiankung在主应用安装qiankun
yarn add qiankun # 或者 npm i qiankun -S
第三步、修改src目录下面的main.js
/*
* @Author: zhengping
* @Date: 2022-10-18 16:28:02
* @Description:
*/
import { createApp } from 'vue'
import App from './App.vue'
import vueRouter from 'vue-router'
import router from "./router"
import { registerMicroApps, start } from "qiankun"
let app = createApp(App);
app.use(vueRouter)
app.use(router)
app.mount('#app')
// 在主应用中注册子应用
registerMicroApps([
{
name: "vue-app", //微应用的名称,有多个微应用的话,必须保证唯一
entry: "//localhost:8088", // 本地运行后子应用的访问地址
container: '#childDemo', // 微应用插入的位置
activeRule: '/vue-child', // 微应用访问入口
props:{}//传给微应用的数据
}]
);
// 启动 要等主页面加载完毕才能启动,即nextTick之后启动
start();
第四步、在src目录下面的App.vue,提供微应用展示的DOM
<!--
* @Author: 西门吹雪
* @Date: 2022-10-18 16:28:02
* @Description:
-->
<template>
<div>
<div id="childDemo"></div>
<!-- 微应用的容器 -->
<router-view />
</div>
</template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
到此为止主应用配置完成
5.构建微应用
第一步、在主应用examples目录下创建一个vue3的项目,创建流程正常创建vue3项目无异,在这里不做过多描述;
vue create vue3-demo-child
第二步、在新创建的vue项目的src文件中创建名为public-path.js 的js文件,如图所示:
public-path.js文件代码如下:
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
第三步、入口文件 main.js 文件代码修改如下:
import './public-path';
import { createApp } from 'vue'
import App from './App.vue'
import routes from './router'
import { createRouter, createWebHistory } from 'vue-router';
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
let router = null;
let instance = null;
let history = null;
function render(props = {}) {
const { container } = props;
let arr = routes.options.routes;
console.log(arr)
history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/vue-child' : '/');
router = createRouter({
history,
routes: routes.options.routes,
});
instance = createApp(App);
instance.use(router);
instance.use(store);
instance.use(ElementPlus);
instance.mount(container ? container.querySelector('#app') : '#app');
}
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
console.log('%c%s', 'color: green;', '微应用初始化vue3.0 app bootstraped');
}
function storeTest(props) {
props.onGlobalStateChange &&
props.onGlobalStateChange(
(value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
true,
);
props.setGlobalState &&
props.setGlobalState({
ignore: props.name,
user: {
name: props.name,
},
});
}
export async function mount(props) {
storeTest(props);
render(props);
instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;
instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}
export async function unmount() {
instance.unmount();
instance._container.innerHTML = '';
instance = null;
router = null;
history.destroy();
}
第四步、打包配置文件(vue.config.js)代码修改成:
const { name } = require('./package');
module.exports = {
devServer: {
port: 8088, // 启动项目时的端口号
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
chunkLoadingGlobal: `webpackJsonp_${name}`,
},
},
};
三、总结
微前端的核心目标是将巨石应用拆解成若干可以自治的松耦合微应用,而 qiankun 的诸多设计均是秉持这一原则,如 HTML entry、沙箱、应用间通信等。这样才能确保微应用真正具备 独立开发、独立运行 的能力。
技术经验
有待提升
写下经验
......
记录遇到的阻塞点
......
版权归原作者 ~西门吹雪 所有, 如有侵权,请联系我们删除。