微前端qiankun实战从搭建到部署

目录

一、项目结构

二、配置导入和配置文件

三、主 -> 子 数据、方法

四、部署


一、项目结构

1,主应用:vue3-vite

2,子应用:vue3-vite

二、配置导入和配置文件

1、主应用下载乾坤包:

npm install qiankun

1) 乾坤配置文件:

  文件位置:src > micro > index.ts。可以不在main.ts 里面写,导入即可。
  entry如果是开发环境,就写localhost:5173,但如果是生产环境,就必须是 /hr/ ,所以用三元判断来写。

import { registerMicroApps, start } from "qiankun";
import type { ObjectType, RegistrableApp } from "qiankun";
import { getToken } from '@/utils/auth'
import { reactive } from "vue";

import router from "../router";

const appConfig: RegistrableApp<ObjectType>[] = [
  {
    name: 'hr',
    entry: process.env.NODE_ENV === 'production' ? '/hr/' : 'http://localhost:5173/',
    container: '#subapp-container',
    activeRule: '/hr',
    props: { token: getToken() },
  },
];

export function registerQiankunApps () {

  registerMicroApps(appConfig,
    {
      // 挂载前回调
      beforeLoad: [
        app => {
          console.log('before load', app)
        }
      ],
      // 挂载后回调
      beforeMount: [
        app => {
          console.log('before mount', app)
        }
      ],
      // 卸载后回调
      afterUnmount: [
        app => {
          console.log('after unload', app);
        }
      ]
    }
  );

  router.isReady().then(() => {
    // 确保在 start() 调用中正确配置 excludeAssetFilter
    start({
      sandbox: {
        strictStyleIsolation: false 
      },
      excludeAssetFilter: (assetUrl) => {
        const excludePatterns = [
          /vue-devtools/,
          /vue-inspector/,
          /@id\/virtual:/, 
          /@vite\/client/, 
          /src_main_ts__app\.js/, 
          /\.hot-update\.js$/ 
        ];
        return excludePatterns.some(pattern => pattern.test(assetUrl));
      }
    });
    console.log('Qiankun started after router is ready.');
  }).catch((err) => {
    console.error('Router readiness error:', err);
  });
}

讲解一下appConfig:

具体的官网可以直接看 https://qiankun.umijs.org/zh/api#registermicroappsapps-lifecycles

主要是props,这是主 - >  子 数据,子 - > 主 数据的根本,里面可以传数据,传方法。

子利用props的数据得到主给子的数据,子调用props的方法,给主传数据

2)路由:
  在你的router/index.ts里面加上子应用的路由,component所对应的组件,是你上面乾坤文件中,container所绑定的#subapp-container的组件。

  当然,如果你是后端返回的路由,就不用写了

  {
    path: '/hr',
    name: '人力资源',
    meta: {
      title: '人力资源',
    },
    component: Layout,
  },

3) 绑定id:subapp-container

   官网说绑定入口文件,也就是App.vue,但大部分情况App.vue都用<router-view />,看你想要的子应用效果:

  如果你是想子应用直接覆盖掉父应用页面,你就在App.vue直接:

  <div id="subapp-container">
      <router-view />
  </div>

  如果你是想子应用嵌入到父应用中,如:

   那你就在layout/index.vue里面绑定你的subapp-container,也在这里调用你的qiankun注册微应用的函数。

<template>
  <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
    <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
    <sidebar v-if="!sidebar.hide" class="sidebar-container" />
    <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
      <div :class="{ 'fixed-header': fixedHeader }">
        <navbar @setLayout="setLayout" />
        <tags-view v-if="needTagsView" />
      </div>
      <div id="subapp-container" >
      </div>
      <app-main />
      <settings ref="settingRef" />
    </div>
  </div>
</template>
<script setup>
import { useWindowSize } from '@vueuse/core'
import Sidebar from './components/Sidebar/index.vue'
import { AppMain, Navbar, Settings, TagsView } from './components'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import { onMounted } from 'vue'
import {registerQiankunApps } from '@/micro'

// 这里开始注册微应用
onMounted(() => {
  registerQiankunApps()
})
</script>

2、子应用导入

npm install vite-plugin-qiankun --save-dev

子应用配置文件:

1)main.ts

// import './public-path'
import { createApp, ref, reactive, inject, provide } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import {
  renderWithQiankun,
  qiankunWindow,
  type QiankunProps,
} from "vite-plugin-qiankun/dist/helper";
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'

let app: null | any = null;

// 注意,我这里以函数形式来写,是为了方便每次主应用进入子应用时,重新渲染
const createNewApp = () => {
  app = createApp(App)
  app.use(createPinia())
  app.use(ElementPlus)
  app.use(router)
  return app
}

let appInstance: ReturnType<typeof createNewApp> | null = null // 用于保存当前应用实例
let routerInstance: any = null // 用于保存路由实例,便于彻底销毁

function render(props: QiankunProps = {}) {
  const { container } = props;
  appInstance = createNewApp();

  const targetContainer = container ? container.querySelector("#app") : document.getElementById("app");
  if (targetContainer) {
    appInstance.mount(targetContainer);
  }
}

function initApp() {
  if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
    console.log("%c 独立渲染", "color: red; font-size: 20px;");
    render();
    return;
  }
  renderWithQiankun({

    async mount(props) {
      await render(props);
      console.log("%c qiankun 渲染", "color: red; font-size: 20px;");
    },
    bootstrap() {
      console.log("bootstrap");
    },
    async unmount(props) {
      console.log("unmount");
      // 在卸载时,彻底销毁应用实例和内部状态
      if (appInstance) {
        appInstance.unmount(); // 卸载应用
        appInstance = null; 
      }
      // 清理路由状态
      if (routerInstance) {
        routerInstance = null;
      }
      // 强制清理挂载点内部的 HTML
      const container = props.container ? props.container.querySelector("#app") : document.getElementById("app");
      if (container) {
        container.innerHTML = '';
      }
      app.unmount();
      app._container = "";
      app = null;
    },
    update(props) {
      console.log("update");
    },
  });
}

initApp();

2)在 src 目录新增 public-path.js,main里面导入,这是为了防止子应用的静态资源404,当然,这是子应用是webpack项目的写法。

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

    但是我这个vite的子应用,需要在vite.config.ts中:
    设置serve的origin就行了。

3)vite.config


import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import qiankun from "vite-plugin-qiankun";
import { viteMockServe } from 'vite-plugin-mock';

export default defineConfig(({ mode, command }) => {
  const env = loadEnv(mode, process.cwd())

  return {
    plugins: [
      vue(),
      qiankun('graduation', {
        useDevMode: true
      }),
      // viteMockServe({
      //   mockPath: "mock",
      //   enabled: command === "serve",
      // }),
    ],
    base: '/graduation/',
    server: {
      port: 5175,
      cors: true,
      origin : 'http://localhost:5175',
      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'
      },
      proxy: {
        '/dev-api': {
          target: 'http://172.16.13.11:8080',
          changeOrigin: true,
          rewrite: (p) => p.replace(/^\/dev-api/, '')
        }
      }
    },
    build: {
      assetsDir: 'static',
      rollupOptions: {
        output: {
        }
      }
    },
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url))
      },
    },
  }
})

   注意,base与主应用的entry要一致,我这里子应用的路由是hash,只需一致就行了,如果你的是history,设置 history: createWebHistory('/子应用/')。history更方便于主子应用的通信的,使用route就可以实现主子跳转了。

   好了,到这里,就已经可以了,如果你只想试一下qiankun,下面这个适合你,很简单就可以实现微前端:
https://blog.youkuaiyun.com/m0_61747600/article/details/148068342

三、主 -> 子 数据、方法

    我这里时模仿了这位的文章里面的方法,直接看他的就行:
    [微前端][vue3 + vite + qiankun] 使用详解

    大概就是主应用props传数据,子应用在mount用全局变量接收
 

四、部署

    我这里是主,子应用都在同一个服务器上,在主应用的dist文件下,新建文件夹用于存放子应用:随后在child/hr/中,存放子应用的dist

   修改nginx的配置文件:


        location  /hr {
           alias 这里是你存放子应用的dist的文件地址;
           index index.html index.htm;
           try_files $uri $uri/ /index.html;
        }

 示例:

        location / {
            root   F:\hy-cloud-front\dist;
            try_files $uri $uri/ /index.html;
            index  index.html index.htm;
        }
       
        location  /hr {
           alias F:\hy-cloud-front\dist\child\hr\dist;
           index index.html index.htm;
           try_files $uri $uri/ /index.html;
        }

  

   注意前面qiankun的entry和子应用在生产环境的base,在生产环境下,就不能是localhost了。 

   最后,在nginx目录下:

nginx -s reload

  这样就部署好了

  注意,部署时,子应用在vite.config设置的base与entry一致。

  这样你直接进入 你的 http//ip:port/ 就是你的主应用,直接进入你的http//ip:port/hr 就是你的子应用。这样,主、子就分别单独独立运行了。

   当然,你也可以另起一个port来单独运行你的子应用,设置如下:

server {
    listen       81;
    server_name  172.16.13.11;
    
    
    # 这样子 你 http://ip:port/ 进来
    location / {
        alias F:/hy-cloud-front/dist/child/hr/dist/;
        try_files $uri $uri/ /index.html;
        index  index.html index.htm;
    }
    
    # 这样子 就算你 http://ip:port/hr 也一样能进来
    location /hr {
        alias F:/hy-cloud-front/dist/child/hr/dist/;
        try_files $uri $uri/ /index.html;
        index  index.html index.htm;
    }

    location /dev-api/ {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://backend/;
    }
   
    # 避免actuator暴露
    if ($uri ~ "/actuator") {
        return 403;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值