当前位置: 首页 > news >正文

qiankun 微前端接入实战

微前端这个内容在之前就做过分享,但是对于完整的项目实战没有写过,在公司刚好有后台,解决一下之前遗留的登录态和权限的问题。

主应用

1、安装依赖

pnpm i qiankun

2、main.ts

采用 registerMicroApps 来注册子应用

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import 'src/styles/index.scss'
import router from 'src/router/index'
import { registerMicroApps } from 'qiankun'const app = createApp(App)app.use(router)
app.mount('#app')registerMicroApps([{name: 'h5App',entry: '//dev.yvyiai.com:8090/yvyiai-digital-human-h5',  // 确保路径不以斜杠结尾container: '#sub-container',activeRule: '/yvyiai-digital-human-web/h5App'}
])

3、编写路由

这里需要添加子应用的路径匹配(不然子应用带路由的话,主应用会404)

const routes = [{path: '/h5App',component: () => import('src/views/Layout/index.vue'),children: [{path: '/:pathMatch(.*)*',name: 'h5App',component: () => import('src/views/subApp/index.vue'),meta: {title: 'h5App'}}]}
]

4、subApp/index.vue

需要添加一个子应用的渲染容器节点,需要和 registerMicroApps 注册的子应用的 container 节点一致

<template><div id="sub-container"></div>
</template><script setup lang="ts">
import { start } from 'qiankun'
import { onMounted } from 'vue'onMounted(() => {// 启动 qiankun,添加错误处理start({sandbox: {experimentalStyleIsolation: true},prefetch: false, // 禁用预加载避免冲突// 添加全局错误处理globalContext: window})
})
</script>

子应用

1、安装依赖

pnpm i vite-plugin-qiankun -D

2、配置vite.config.ts

  • 如果子应用是webpack的话,可以看qiankun官网,vite需要使用插件。

  • 子应用同时需要支持跨域

  • 配置打包为umd

import qiankun from 'vite-plugin-qiankun'export default defineConfig({// 参数1:子应用名plugin: [qiankun('h5App', { useDevMode: true })],server: {// 开发环境的hosthost: 'dev.yvyiai.com',cors: true,// 添加跨域头部headers: {'Access-Control-Allow-Origin': '*','Access-Control-Allow-Methods':'GET, POST, PUT, DELETE, PATCH, OPTIONS','Access-Control-Allow-Headers':'X-Requested-With, content-type, Authorization'}},build: {lib: {entry: './src/main.ts', // 入口文件name: 'h5App', // 子应用名称fileName: 'h5App', // 打包后的文件名formats: ['umd'] // 打包为 UMD 格式}}
})

3、改造main.ts

webpack的应用改造方法有点不同,比vite简单

import { createApp, type App as AppInstance } from "vue";
import router from './router'
import App from './App.vue'
import {renderWithQiankun,qiankunWindow
} from 'vite-plugin-qiankun/dist/helper'let app: AppInstance | null = null
function render(props: any = {}) {const { container } = propsapp = createApp(App)app.use(router)app.mount(container ? container.querySelector("#app") : "#app");
}if (!qiankunWindow.__POWERED_BY_QIANKUN__) {render()
}renderWithQiankun({mount(props) {render(props)},bootstrap() {},unmount(_props) {if (app) {app.unmount()if (app._container) {app._container.innerHTML = ''}app = null}},update() {}
})

4、路由改造

这个项目的主子应用都配置了base route的,子应用在qiankun环境下,需要把base route换成主应用的base+route path

  • 主应用base route:yvyiai-digital-human-web

  • 主应用对应子应用的出口路由:/h5App

// 子应用router/index.ts
const ROUTER_BASE = 'yvyiai-digital-human-h5'const router = createRouter({history: createWebHistory(!qiankunWindow.__POWERED_BY_QIANKUN__ ? ROUTER_BASE : 'yvyiai-digital-human-web/h5App'),routes
})

对应如下:

  • 子应用独立运行路径: http://dev.yvyiai.com:8090/yvyiai-digital-human-h5/xxx

  • 在主应用下运行路径: http://dev.yvyiai.com:8080/yvyiai-digital-human-web/h5App/xxx

子应用在主应用运行的路径就要以主应用的base为准了,不然会找不到资源的。

开发模式下接口问题

在开发模式下,我们的子应用通常会做proxy代理,但是这就导致我主应用是没有子应用的代理配置的,例如:

  • 子应用单独运行代理请求url: http://dev.yvyiai.com:8090/liveApi/api1

  • 子应用在主应用下运行的请求url: http://http://dev.yvyiai.com:8080/liveApi/api1

这里的 /liveApi 就是子应用在vite配置中做的代理,但是在主应用下看到是没有这个代理的,所以请求会报错。

解决办法:

  1. 在后端对接口处理跨域,不采用代理的方式

  2. 在主应用的vite中也配置同样的代理

但是方法2这种方法会存在一个缺点就是:我的子应用很多,代理也很多,我当前的子应用下面就有快10个代理接口,如果子应用也多,就会导致主应用的配置不好维护。

上面的解决方法只是基础原理

最终方法:

可以采用 CMS 进行后端配置,在运行前去加载代理的应用数据(也就是我的子应用需要提前去CMS系统上注册)。

这种方法对主应用去注册子应用也同样有用,可以通过远程数据配置来动态注册应用,这样基座代码不用每次注册都进行修改。

新建 remote-proxy-loader.js ,用于去加载不同子应用的proxy,去主应用的 vite.config.ts 去使用即可。

const fs = require('fs');
const path = require('path');
const axios = require('axios');// 本地缓存文件路径
const PROXY_CACHE_PATH = path.resolve(__dirname, './proxy-cache.json');/*** 从远程获取代理配置*/
async function fetchRemoteProxyConfig() {try {const response = await axios.get('https://your-config-server.com/proxy-config');return response.data; // 假设返回格式: { subApp1: { ... }, subApp2: { ... } }} catch (error) {console.error('获取远程代理配置失败,使用本地缓存', error);// 尝试读取本地缓存if (fs.existsSync(PROXY_CACHE_PATH)) {return JSON.parse(fs.readFileSync(PROXY_CACHE_PATH, 'utf-8'));}return {}; // 无配置时返回空对象}
}/*** 保存配置到本地缓存*/
function saveProxyCache(config) {fs.writeFileSync(PROXY_CACHE_PATH, JSON.stringify(config, null, 2));
}/*** 获取当前应用的代理配置*/
async function getCurrentAppProxy(appName) {const allConfig = await fetchRemoteProxyConfig();// 保存到本地缓存saveProxyCache(allConfig);// 返回当前应用的配置return allConfig[appName] || {};
}module.exports = { getCurrentAppProxy };

登录态的问题

项目中少不了的就是接口或页面的权限问题,这对项目的安全性也是非常重要的。

1、接口权限

公司的项目采用的是cookie作为登录态校验的,核心思路是利用 cookie 的跨域特性和 qiankun 的通信机制来做控制。

1.1 原理

cookie 具有域(domain)属性,若主应用和子应用配置在同一主域名下(如主应用 app.example.com ,子应用 sub1.example.com ),可通过设置 domain=.example.com 实现 cookie 共享

1.2 实现方案

同域的情况下直接共享:
  1. 登录接口设置 cookie 时指定主域名
// 登录接口响应头设置(后端)
Set-Cookie: token=xxx; domain=.example.com; path=/; HttpOnly; Secure
  1. 主应用登录后,子应用自动获取同域名下的 cookie
同域的情况下的登录态同步:

当主应用与子应用不在同一域时:

  1. 主应用登录后,通过 qiankun 的全局通信机制通知子应用
// 主应用登录成功后
import { initGlobalState } from 'qiankun';const globalState = initGlobalState({token: 'xxx', // 登录后获取的 tokenisLogin: true
});// 主应用监听子应用消息
globalState.onGlobalStateChange((state, prev) => {console.log('主应用监听到状态变化', state, prev);
});
  1. 子应用监听主应用的登录状态
// 子应用中
export function mount(props) {// 监听主应用传递的登录状态props.onGlobalStateChange((state, prev) => {if (state.isLogin) {// 子应用存储 token 到本地或内存localStorage.setItem('token', state.token);}}, true);
}

2、页面权限

页面权限可以在登录的时候,通过动态路由生成权限路由(还是靠CMS去拿)。但只限于主应用的路由,子应用的路由的话,只能通过主子应用通信+接口(接口返回403状态,可以直接返回login页面)解决权限

效果展示

由于没有做样式的特殊处理,导致子应用的样式污染到了主应用。

即使qiankun设置了样式隔离,vite还是会有影响,所以需要手动处理样式(webpack可以做到完美隔离)

在这里插入图片描述


文章转载自:

http://6Jc5RAhy.Lbrwm.cn
http://IeiWFlOk.Lbrwm.cn
http://gBb0Fw0Q.Lbrwm.cn
http://Y7ZMAeXU.Lbrwm.cn
http://AJqBeQrV.Lbrwm.cn
http://odaAEn8C.Lbrwm.cn
http://o4D7X8GI.Lbrwm.cn
http://Y57cR1WW.Lbrwm.cn
http://8F5WIgFq.Lbrwm.cn
http://CLzcR19x.Lbrwm.cn
http://FIsB1rl1.Lbrwm.cn
http://shVIofHH.Lbrwm.cn
http://d846h48U.Lbrwm.cn
http://a0BDYpIk.Lbrwm.cn
http://KegHbTXx.Lbrwm.cn
http://boB4UCOy.Lbrwm.cn
http://0H0QdjtG.Lbrwm.cn
http://OySNIMJI.Lbrwm.cn
http://hIzvQGn2.Lbrwm.cn
http://mBrK6ORn.Lbrwm.cn
http://YKz8m5nI.Lbrwm.cn
http://A2fWtnXT.Lbrwm.cn
http://MXsXBtwq.Lbrwm.cn
http://InvZFWTv.Lbrwm.cn
http://z8BYTMXQ.Lbrwm.cn
http://U2abHLO0.Lbrwm.cn
http://frr7Ccm5.Lbrwm.cn
http://JVFOolKn.Lbrwm.cn
http://Ppo5IZt1.Lbrwm.cn
http://znUPQUo4.Lbrwm.cn
http://www.dtcms.com/a/371179.html

相关文章:

  • AI笔记 - 网络训练 -人脸识别opensphere
  • css 十大常用英文字体
  • Python Day 46
  • 蓓韵安禧DHA温和配方:健康营养守护新篇章
  • disable CASCADE主键失败 ORA-2297 And ORA-2433
  • VSCode下载安装与汉化
  • JWT概念及使用详解
  • LwIP入门实战 — 3 以太网外设 (ETH)
  • PowerBI TopN Others
  • 【完整源码+数据集+部署教程】室内场景分割系统源码和数据集:改进yolo11-DWR
  • 零基础Linux操作基础小白快速掌握Shell脚本--流程控制和循环(二)
  • 笔记本连接显示屏显示不全如何解决
  • 【C++】vector 深度剖析及模拟实现
  • Leetcode hot100 最长连续序列
  • Python错误测试与调试——文档测试
  • AI浪潮下,人类创造力的“危”与“机”
  • ​MyBatis关键源码解析​
  • 使用Spring Boot DevTools快速重启功能
  • 【视网膜分割】AFMIP-Net:一种新型的自适应特征调制和隐式提示网络
  • 使用 n8n 结合通义千问大模型构建业务数据库分析智能体
  • 【完整源码+数据集+部署教程】水培植物病害检测系统源码和数据集:改进yolo11-AKConv
  • 解决 Gitee 中 git push 因邮箱隐私设置导致的失败问题
  • 网络中的PAT:小端口映射的大能量
  • 鸿蒙NEXT主题设置指南:应用级与页面级主题定制详解
  • 贪心算法应用:DNA自组装问题详解
  • GEE:基于自定义的年度时序数据集进行LandTrendr变化检测
  • 电子元器件+模拟电路硬件
  • 源码部署mysql8.0.40
  • STM32----W25QXX
  • 状压 dp --- 数据范围小