本文章介绍了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
  1. 在主应用中安装qiankun框架
$ yarn add qiankun # 或者 npm i qiankun -S
  1. 在 主应用 中注册微应用

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

                                                      首页                                            child-vue3-one                                            child-vue3-one                                            child-vue2-one                                            child-react-one                                            child-angular-one                                     export default {  name: "App",  components: {},  methods: {    // 跳转页面方法    goHome() {      this.$router.push("/");    },  },};.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;}

index.html:

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

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 实列,为函数,里面有配置项(对象) historyconst router = createRouter({    mode: 'history',    history: createWebHistory(),    routes,});// 3导出路由   然后去 main.ts 注册 router.tsexport default router

vue3子应用

  1. 创建项目
// 选择vue3这个版本vue create child-one
  1. 在 src 目录新增 public-path.js

  2. 解决静态文件跨域

// src/public-path.jsif(window.__POWERED_BY_QIANKUN__) {  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}
  1. 修改路由文件,建议使用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 实列,为函数,里面有配置项(对象) historyconst router = createRouter({    mode: 'history',    base: window.__POWERED_BY_QIANKUN__ " />
  1. 入口文件 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;}
  1. 主应用容器子应用
    qiankun-test/src/views/childOne/index.vue
  

我是子应用 vue3-one

import { start } from "qiankun";export default { name: "childOne", components: {}, mounted() { if (!window.qiankunStarted) { window.qiankunStarted = true; start(); } },};

运行效果如下:

vue2子应用-child-vue2

childVue2One/index.vue

  

我是微应用vue2项目

import { start } from "qiankun";export default { name: "vueChild", components: {}, mounted() { this.$nextTick(() => { if (!window.qiankunStarted) { window.qiankunStarted = true; start(); } }); },};
  1. 微应用配置child-vue2

src下创建public-path.js

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

main.js

// src/main.jsimport 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 " />
vue2错误问题

路由版本不对

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

react子应用

问题
  1. 当修改入口文件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.1ng new child-angular1

版本搞成了9那就好办了

  1. 根据要求配置好主应用的main.js与App.vue文件
  2. 在主应用views创建anguale的容器.vue文件
  3. 配置主应用路由
  4. 然后就是根据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