首页IT科技微前端解决什么问题(微前端架构-qiankun在vue3的应用)

微前端解决什么问题(微前端架构-qiankun在vue3的应用)

时间2025-05-05 16:32:08分类IT科技浏览3412
导读:本文章介绍了qiankun在vue3的应用,其中子应用有vue2、vue3、react、angular...

本文章介绍了qiankun在vue3的应用          ,其中子应用有vue2          、vue3                、react      、angular

介绍

qiankun 是一个基于 single-spa 的微前端实现库                ,旨在帮助大家能更简单          、无痛的构建一个生产可用微前端架构系统           。

其他几款([single-spa]               、[micro-app]      、[百度emp]])

使用 iframe 整合系统时      ,假设我们有系统 A, 当我们想把系统 B 引入 A 系统时          ,只需要 B 系统提供一个 url 给 A 系统引用即可               ,这里我们把 A 系统叫做父应用      ,把 B 系统叫做子应用                。同样的     ,微前端也延续了这个概念               ,微前端在使用起来基本和使用 iframe 一样平滑     。

结构

主应用(父)           ,微应用(子)

案例

一     、主应用

主应用不限技术栈     ,只需要提供一个容器 DOM               ,然后注册微应用并 start 即可     。 创建主应用项目 -vue3 npm install @vue/cli -g vue create qiankun-tast 在主应用中安装qiankun框架 $ yarn add qiankun # 或者 npm i qiankun -S 在 主应用 中注册微应用

main.js:

import { createApp } from vue import App from ./App.vue import router from ./router/index import ElementPlus from element-plus import element-plus/dist/index.css import zone.js; import { registerMicroApps } 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: "vueChildOne", entry: "//localhost:3001", container: "#child-vue3-one-content", activeRule: "/child-one", }, { name: "vueChildTwo", entry: "//localhost:3002", container: "#child-vue3-two-content", activeRule: "/child-two", }, { name: "vue2Child", entry: "//localhost:3003", container: "#child-vue2-one-content", activeRule: "/child-vue2-one", }, { name: "reactApp1", entry: "//localhost:4001", container: "#child-react-one-content", activeRule: "/child-react-one", }, { name: "angularApp1", entry: "//localhost:4200", container: "#child-angular-one-content", activeRule: "/child-angular-one", }, ]); // setDefaultMountApp(/child-one) // 启动 qiankun // start(); createApp(App).use(ElementPlus).use(router).mount(#app-base)

App.vue

<template> <div class="common-layout"> <el-container> <el-aside width="200px"> <el-menu> <el-menu-item index="1"> <el-icon><icon-menu /></el-icon> <span @click="goHome">首页</span> </el-menu-item> <el-menu-item index="2"> <el-icon><icon-menu /></el-icon> <span @click="$router.push(/child-one)">child-vue3-one</span> </el-menu-item> <el-menu-item index="3"> <el-icon><document /></el-icon> <span @click="$router.push(/child-two)">child-vue3-one</span> </el-menu-item> <el-menu-item index="4"> <el-icon><document /></el-icon> <span @click="$router.push(/child-vue2-one)">child-vue2-one</span> </el-menu-item> <el-menu-item index="5"> <el-icon><document /></el-icon> <span @click="$router.push(/child-react-one)">child-react-one</span> </el-menu-item> <el-menu-item index="6"> <el-icon><document /></el-icon> <span @click="$router.push(/child-angular-one)">child-angular-one</span> </el-menu-item> </el-menu> </el-aside> <el-main> <router-view></router-view></el-main> </el-container> </div> </template> <script> export default { name: "App", components: {}, methods: { // 跳转页面方法 goHome() { this.$router.push("/"); }, }, }; </script> <style> .bens { width: 100%; display: flex; justify-content: center; position: absolute; top: 15px; left: 0; z-index: 9999999; } #app-base { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>

index.html:

// 将id:app 改为 app-base 自定义就行,只要与main.js对应起来               ,切不与微应用重复 <div id="app-base"></div>

router.js

import { createRouter, createWebHistory } from "vue-router"; // 2. 配置路由 const routes = [ { path: "/", name: "home", component: () => import("@/views/home/index.vue"), }, { path: "/child-one", component: () => import("@/views/childOne/index.vue"), }, { path: "/child-two", component: () => import("@/views/childTwo/index.vue"), }, { path: "/child-vue2-one", component: () => import("@/views/childVue2One/index.vue"), }, { path: "/child-react-one", component: () => import("@/views/childReactOne/index.vue"), }, { path: "/child-angular-one", component: () => import("@/views/childAgOne/index.vue"), }, ]; // 1.返回一个 router 实列                ,为函数,里面有配置项(对象) history const router = createRouter({ mode: history, history: createWebHistory(), routes, }); // 3导出路由 然后去 main.ts 注册 router.ts export default router

vue3子应用

创建项目 // 选择vue3这个版本 vue create child-one

在 src 目录新增 public-path.js

解决静态文件跨域

// src/public-path.js if(window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } 修改路由文件          ,建议使用history 模式的路由                ,并设置路由 base      ,值和它的 activeRule 是一样的                。 import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"; // 2. 配置路由 const routes = [ { path: /, component: () => import(@/views/home/index.vue), }, { path: /about, component: () => import(@/views/about/index.vue), }, ]; // 1.返回一个 router 实列          ,为函数               ,里面有配置项(对象) history const router = createRouter({ mode: history, base: window.__POWERED_BY_QIANKUN__ ? "/child-one" : "/", history: createWebHashHistory(/child-one), routes, }); // 3导出路由 然后去 main.ts 注册 router.ts export default router 入口文件 main.js 修改      ,为了避免根 id #app 与其他的 DOM 冲突     ,需要限制查找范围          。并导出三个生命周期函数     。 import { createApp } from vue import App from ./App.vue import router from ./router/index import ./public-path // createApp(App).mount(#app) let instance = null; function render(props = {}) { if (instance) return; const { container } = props; console.log(container); instance = createApp(App) .use(router) .mount(container ? container.querySelector("#app-child-one") : "#app-child-one"); } // 独立运行时 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

; } 主应用容器子应用

qiankun-test/src/views/childOne/index.vue <template> <h2>我是子应用 vue3-one</h2> <div id="child-vue3-one-content"></div> </template> <script> import { start } from "qiankun"; export default { name: "childOne", components: {}, mounted() { if (!window.qiankunStarted) { window.qiankunStarted = true; start(); } }, }; </script> <style> </style> 运行效果如下:

vue2子应用-child-vue2

childVue2One/index.vue

<template> <h2>我是微应用vue2项目</h2> <div id="child-vue2-one-content"></div> </template> <script> import { start } from "qiankun"; export default { name: "vueChild", components: {}, mounted() { this.$nextTick(() => { if (!window.qiankunStarted) { window.qiankunStarted = true; start(); } }); }, }; </script> <style> </style> 微应用配置child-vue2

src下创建public-path.js

if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ }

main.js

// src/main.js import Vue from vue import App from ./App import router from ./router import "./public-path"; Vue.config.productionTip = false // 定义一个Vue实例 let instance = null // 渲染方法 function render(props = {}) { const { container } = props instance = new Vue({ router, render: (h) => h(App) }).$mount(container ? container.querySelector(#app): #app) } // 独立运行时 if(!window.__POWERED_BY_QIANKUN__) { render() } //暴露主应用生命周期钩子 /** * bootstrap : 在微应用初始化的时候调用一次               ,之后的生命周期里不再调用 */ export async function bootstrap() { console.log(vue2-app bootstraped); } /** * mount : 在应用每次进入时调用 */ export async function mount(props) { console.log(vue2-app mount, props); render(props); } /** * unmount :应用每次 切出/卸载 均会调用 */ export async function unmount() { console.log("vue2-app unmount") instance.$destroy(); instance.$el.innerHTML = ; instance = null; }

vue.config.js

module.exports = { lintOnSave: false, devServer: { port: "3003", headers: { "Access-Control-Allow-Origin": "*", //所有人都可以访问我的服务器 }, }, configureWebpack: { output: { // library: `${name}-[name]`, library: `vueChildOne`, libraryTarget: "umd", // 把微应用打包成 umd 库格式 // jsonpFunction: `webpackJsonp_${name}`, }, }, };

router.js

import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"; // 2. 配置路由 const routes = [ { path: /, component: () => import(@/views/home/index.vue), }, { path: /about, component: () => import(@/views/about/index.vue), }, ]; // 1.返回一个 router 实列           ,为函数     ,里面有配置项(对象) history const router = createRouter({ mode: history, base: window.__POWERED_BY_QIANKUN__ ? "/child-one" : "/", history: createWebHashHistory(/child-one), routes, }); // 3导出路由 然后去 main.ts 注册 router.ts export default router vue2错误问题

路由版本不对

下载指定版本在3*的就行

react子应用

问题 当修改入口文件index.tsx之后               ,主要是添加了qiankun的生命周期之后           ,报错

– You need to export lifecycle functions in reactApp1 entry

明明我已经写了生命周期但是没有生效                。

问题出在:官方问题使用的js语法,我使用的是ts语法          。

解决:用react-app-rewired方案复写webpack就可以了。作用:通过react-app-rewired插件,react-app-rewired的作用就是在不eject的情况下,覆盖create-react-app的配置.

angular子应用

angular由于在国内用的不多所以我是按照官方教程完成的               ,当然中间出了很多狗血的错误

官方:以 Angular-cli 9 生成的 angular 9 项目为例                ,其他版本的 angular 后续会逐渐补充                。

这句话就是一个坑,首先我自己原有的angular版本是12          ,用 ng 命令安装的项目就是最新的了               。这个导致我安装官方操作一直没有成功                ,不断报错。------我放弃了      ,做个乖孩子          ,用angular9

由于不能降低电脑全局版本               ,于是我在本项目中安装了一个angular-cli9

npm install @angular/cli@9.0.1 ng new child-angular1

版本搞成了9那就好办了

根据要求配置好主应用的main.js与App.vue文件 在主应用views创建anguale的容器.vue文件 配置主应用路由 然后就是根据qiankun的文档配置文件了

注意:在qiankun的文档中第二步,child-angular-one这个是和主应用配置路由一致

设置 history 模式路由的 base      ,src/app/app-routing.module.ts 文件: import { NgModule } from @angular/core; import { Routes, RouterModule } from @angular/router; import { APP_BASE_HREF } from @angular/common; const routes: Routes = []; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], // @ts-ignore // child-angular-one 必须和主路由向对应 providers: [{ provide: APP_BASE_HREF, useValue: window.__POWERED_BY_QIANKUN__ ? /child-angular-one : / }] }) export class AppRoutingModule { }

gitee地址:qiankun-vue3

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
文章采集器app(用typecho自动采集文章插件,轻松打造高质量内容)