微前端(qiankun)
什么是微前端微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。、微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。微前端架构具备以下几个核心价值:技术栈无关主框架不限制接入应
什么是微前端
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。、
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
微前端架构具备以下几个核心价值:
- 技术栈无关
主框架不限制接入应用的技术栈,微应用具备完全自主权 - 独立开发、独立部署
微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 - 增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略 - 独立运行时
每个微应用之间状态隔离,运行时状态不共享
qiankun - 一套完整的微前端解决方案
特性
- 基于 single-spa 封装,提供了更加开箱即用的 API。
- 技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
- HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
- 样式隔离,确保微应用之间样式互相不干扰。
- JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
- 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
搭建微前端项目
主应用
主应用与技术栈无关,我们可以使用Vue、React、Angular、JQuery甚至ES5语法进行搭建。主应用的目的如下:
- 注册微应用;
- 为每个微应用提供dom容器;
- 启动主应用;
下面我是以vue为主应用一步一步进行讲解,先使用vue-cli3构建项目。
1.安装qiankun
$ npm install qiankun
2.注册微应用
在入口文件main.js中添加如下代码:
import { registerMicroApps, start, setDefaultMountApp } from 'qiankun'
//注册应用
registerMicroApps([
{
name: "vue2App",
props: { age: 10 }, //给子应用传数据
entry: "//localhost:3001", //默认会加载这个html,解析里面的js,动态执行(子应用必须支持跨域)里面,是用fetch去请求的数据
container: "#out-main", //挂载到主应用的哪个元素下
activeRule: "/vue2", //当我劫持到路由地址为/vue2时,我就把http://localhost:3000这个应用挂载到#app-main的元素下
},
{
name: "vue3App",
entry: "//localhost:3002",
// entry: { scripts: ["//localhost:7100/main.js"] },
container: "#out-main",
activeRule: "/vue3",
},
]);
//step3 设置默认进入微应用
//setDefaultMountApp('/vue3')
//开启
start();
微应用
微应用不用额外安装qiankun即可接入主应用,大致分为下面几个步骤:
- 入口js文件平级目录下增加public-path.js文件;
- 入口js文件中引入public-path.js,修改并导出qiankun定义的三个钩子函数:bootstrap、mount、unmount;
- 使用history路由,并且路由base值要和activeRule匹配规则保持一致;
- 修改webpack配置,允许开发环境跨域及umd打包;
下面我们以vue cli3作为技术栈构建微应用
在src下增加public-path.js
qiankun 将会在微应用 bootstrap 之前注入一个运行时的 publicPath 变量,你需要做的是在微应用的 entry js 的顶部添加如下代码
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
关于运行时 publicPath 的技术细节,可以参考 webpack 文档。
runtime publicPath 主要解决的是微应用动态载入的 脚本、样式、图片 等地址不正确的问题。
修改入口文件main.js
let instance = null;
function render(props = {}) {
const { container } = props;
window.props = props;
//会把这个应用(也就是这个界面),插入到主应用的container的元素中去
instance = new Vue({
router,
render: (h) => h(App),
}).$mount(container ? container.querySelector("#app") : "#app"); //这里是挂载到自己的html中,主应用会拿到这个挂载的html,将其插入到主应用中
}
// 独立运行时
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;
}
路由配置
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
/* Layout */
export const routes = [
{
path: "/",
redirect: "/list",
},
{
path: "/list",
component: () => import("@/views/protocol/index"),
},
];
const router = new VueRouter({
base: "vue2",
mode: "history",
routes,
});
export default router;
配置webpack 在vue.config.js
module.exports = {
lintOnSave: false,
devServer: {
port: "3001",
headers: {
"Access-Control-Allow-Origin": "*", //所有人都可以访问我的服务器
},
},
configureWebpack: {
output: {
// library: `${name}-[name]`,
library: `vue2App`,
libraryTarget: "umd", // 把微应用打包成 umd 库格式
// jsonpFunction: `webpackJsonp_${name}`,
},
},
};
下面我们以vue3作为技术栈构建微应用
在src下增加public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
修改入口文件main.js
let instance = null;
function render(props = {}) {
if (instance) return;
const { container } = props;
instance = createApp(App)
.use(store)
.use(router)
.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 = null;
}
路由配置
import { createRouter, createWebHistory } from "vue-router";
const routes = [
{
path: "/",
redirect: "/home",
},
{
path: "/home",
component: () => import("../views/Home.vue"),
},
];
const router = createRouter({
history: createWebHistory("/vue3"),
routes,
});
export default router;
配置webpack 在vue.config.js
// const { name } = require("./package");
module.exports = {
lintOnSave: false,
devServer: {
port: "3002",
headers: {
"Access-Control-Allow-Origin": "*", //所有人都可以访问我的服务器
},
},
configureWebpack: {
output: {
// library: `${name}-[name]`,
library: `vue3App`,
libraryTarget: "umd", // 把微应用打包成 umd 库格式
// jsonpFunction: `webpackJsonp_${name}`,
},
},
};
更多推荐
所有评论(0)