qiankun微前端 主应用vue3+vite、子应用vue3+vite

qiankun微前端 主应用vue3+vite、子应用vue3+vite

项目目录结构
主应用

创建主应用:
安装qiankun
配置qiankun
挂载 qiankun
添加子应用展示容器

子应用

创建子应用
安装插件
配置 qiankun


qiankun 官网

项目目录结构

qiankun-base 主应用 vue3 + vite
qiankun-project-1 子应用 vue3 + vite
qiankun-project-2 子应用 vue3 + vite
图片[1] - qiankun微前端 主应用vue3+vite、子应用vue3+vite - 宋马
图片[2] - qiankun微前端 主应用vue3+vite、子应用vue3+vite - 宋马

主应用

创建主应用:

创建vue3 + vite 项目:

npm create vue@latest

安装 Element-Plus 组件库

安装配置方法请看Element-Plus官网:https://cn.element-plus.org/zh-CN/

安装qiankun

npm install qiankun -S

配置qiankun

src 目录中创建 qiankun文件夹,并创建index.jsconfig.js文件:
config.js 文件中配置子应用路由,示例代码如下:

export default {
            
    subApps: [
        {
            
            name: 'vue1', // 子应用名称,必须跟子应用 package.json 中的 name 一致
            entry: 'http://localhost:3001/vue1', // 子应用入口,本地环境下指定端口
            container: '#vue1', // 挂载子应用的 DOM
            activeRule: '/vue1', // 路由匹配规则
            props: {
            }, // 主应用与子应用通信传值
        },
        {
            
            name: 'vue2', // 子应用名称,必须跟子应用 package.json 中的 name 一致
            entry: 'http://localhost:3002/vue2', // 子应用入口,本地环境下指定端口
            container: '#vue2', // 挂载子应用的 DOM
            activeRule: '/vue2', // 路由匹配规则
            props: {
            }, // 主应用与子应用通信传值
        }
    ]
}

index.js 文件中注册子应用,并启动微服务,示例代码如下:

import {
             registerMicroApps, start } from 'qiankun'
import config from './config.js' // 引入的时候必须加 .js 要不然会报错

const {
             subApps } = config

// 注册子应用
export function registerApps() {
            
    try {
            
        registerMicroApps(subApps, {
            
            beforeLoad: [
                async app => {
            
                    // console.log('before load', app)
                }
            ],
            beforeMount: [
                async app => {
            
                    // console.log('before mount', app)
                }
            ],
            afterUnmount: [
                async app => {
            
                    // console.log('before unmount', app)
                }
            ]
        })
    } catch (err) {
            
        console.warn('qiankun 报错信息', err);
    }
}

// 启动
export function qiankunStart() {
            
    registerApps()
    // 启动微服务
    start({
            
        sandbox: {
            
            experimentalStyleIsolation: true, // 样式隔离
        },
    })
}

挂载 qiankun

main.js文件中挂载qiankun,示例代码如下:

// 引入qiankun配置
import {
             qiankunStart } from '@/qiankun/index.js'

// 启动qiankun
qiankunStart()

添加子应用展示容器

App.vue或者别的页面添加子应用展示容器,示例代码如下:

<!-- 菜单-->
<el-menu-item index="/vue1">
              <span>项目1</span>
            </el-menu-item>
            <el-menu-item index="/vue2">
              <span>项目2</span>
            </el-menu-item>

<!--容器-->
<!-- 子应用容器 -->
          <div id="vue1"></div>
          <div id="vue2"></div>

App.vue代码如下:

<template>
  <div class="common-layout">
    <el-container>
      <el-aside width="260px">
        <div class="logo-container">
          <div class="logo">
            <span class="logo-icon">Q</span>
            <span class="logo-text">Qiankun Admin</span>
          </div>
        </div>
        <el-menu
          :router="true"
          :default-openeds="['1', '2']"
          :unique-opened="true"
          background-color="#001529"
          text-color="#a6adb4"
          active-text-color="#ffffff"
        >
          <!-- 基座(主应用)中可以放自己的路由 -->
          <el-sub-menu index="1">
            <template #title>
              <span>主应用</span>
            </template>
            <el-menu-item index="/">
              <span>首页</span>
            </el-menu-item>
            <el-menu-item index="/about">
              <span>关于我们</span>
            </el-menu-item>
          </el-sub-menu>

          <!-- 基座中也可以放自己的子应用 -->
          <el-sub-menu index="1">
            <template #title>
              <span>微应用</span>
            </template>
            <el-menu-item index="/vue1">
              <span>项目1</span>
            </el-menu-item>
            <el-menu-item index="/vue2">
              <span>项目2</span>
            </el-menu-item>
          </el-sub-menu>
        </el-menu>
      </el-aside>
      <el-container>
        <el-header>
          <h1 class="page-title">
            <span class="clip-cuPnlM">qiankun 微前端</span>
          </h1>
        </el-header>
        <el-main>
          <!-- 主应用容器 -->
          <RouterView />

          <!-- 子应用容器 -->
          <div id="vue1"></div>
          <div id="vue2"></div>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script setup>
import {
               RouterLink, RouterView } from "vue-router";
</script>

<style>
html,
body {
              
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

.common-layout {
              
  height: 100vh;
  overflow: hidden;
}

.common-layout .el-container {
              
  height: 100%;
}

.el-container {
              
  display: flex;
  flex-direction: row;
}

.el-container > .el-container {
              
  flex-direction: column;
  flex: 1;
}

.el-aside {
              
  background-color: #001529;
  box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
  height: 100%;
  display: flex;
  flex-direction: column;
}

.logo-container {
              
  height: 64px;
  padding: 16px;
  box-sizing: border-box;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  flex-shrink: 0;
}

.logo {
              
  display: flex;
  align-items: center;
  height: 100%;
}

.logo-icon {
              
  width: 32px;
  height: 32px;
  background: linear-gradient(120deg, #0095ff, #f4f468);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 20px;
  font-weight: bold;
  margin-right: 12px;
}

.logo-text {
              
  color: white;
  font-size: 18px;
  font-weight: 600;
  white-space: nowrap;
  opacity: 1;
  transition: opacity 0.2s;
}

.el-menu {
              
  border-right: none;
  background-color: #001529;
  flex: 1;
}

.el-menu--popup {
              
  background-color: #001529 !important;
  padding: 4px 0 !important;
}

.el-menu--popup .el-menu-item {
              
  color: #a6adb4 !important;
  background-color: #001529 !important;
}

.el-menu--popup .el-menu-item:hover,
.el-menu--popup .el-menu-item.is-active {
              
  color: white !important;
  background-color: #1890ff !important;
}

.el-sub-menu.is-opened > .el-sub-menu__title {
              
  color: white !important;
}

.el-sub-menu.is-opened > .el-menu--inline {
              
  background-color: #000c17 !important;
}

.el-menu-item {
              
  height: 50px;
  line-height: 50px;
  font-size: 14px;
  padding: 0 20px !important;
  margin: 4px 0;
  transition: all 0.3s ease;
}

.el-menu-item:hover {
              
  background-color: #1890ff !important;
  color: white !important;
}

.el-menu-item.is-active {
              
  background-color: #1890ff !important;
  color: white !important;
}

.el-menu-item i,
.el-sub-menu__title i {
              
  transition: color 0.3s ease;
}

.el-sub-menu__title,
.el-menu-item {
              
  position: relative;
  overflow: hidden;
}

.el-sub-menu__title::after,
.el-menu-item::after {
              
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: #1890ff;
  transform: scaleX(0);
  transition: transform 0.3s ease;
}

.el-menu-item.is-active::after,
.el-sub-menu.is-active > .el-sub-menu__title::after {
              
  transform: scaleX(1);
}

.el-menu--inline {
              
  transition: background-color 0.3s ease;
}

.el-sub-menu.is-opened > .el-sub-menu__title i {
              
  transform: rotate(0);
  transition: transform 0.3s ease;
}

.el-menu-item i {
              
  margin-right: 10px;
  font-size: 18px;
}

.el-sub-menu {
              
  border-radius: 2px;
}

.el-sub-menu__title {
              
  color: #a6adb4 !important;
  height: 50px !important;
  line-height: 50px !important;
  padding: 0 20px !important;
  margin: 4px 0;
}

.el-sub-menu__title:hover {
              
  color: white !important;
  background-color: #1890ff !important;
}

.el-sub-menu__title i {
              
  margin-right: 10px;
  font-size: 18px;
  color: inherit;
}

.el-menu--inline {
              
  background-color: #000c17 !important;
  padding: 4px 0;
}

.el-menu--inline .el-menu-item {
              
  height: 40px !important;
  line-height: 40px !important;
  padding-left: 48px !important;
  min-width: auto !important;
}

.el-menu--inline .el-menu-item i {
              
  font-size: 14px;
}

.el-sub-menu.is-active .el-sub-menu__title {
              
  color: white !important;
  background-color: #1890ff !important;
}

.el-header {
              
  background-color: #fff;
  border-bottom: 1px solid #e6e6e6;
  padding: 0 20px;
  display: flex;
  align-items: center;
  height: 60px !important;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  flex-shrink: 0;
}

.page-title {
              
  margin: 0;
}

.page-title > span {
              
  font-size: 32px;
  background: -webkit-linear-gradient(120deg, #0095ff 30%, #f4f468);
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
  background-clip: text;
  font-weight: 600;
  letter-spacing: 0.5px;
}

.el-main {
              
  background-color: #f5f7fa;
  padding: 20px;
  flex: 1;
  overflow-y: auto;
  box-sizing: border-box;
  height: 0;
}

#vue1,
#vue2 {
              
  background-color: #fff;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}

#vue2 {
              
  margin-bottom: 0;
}
</style>

PS:到这里主应用已经配置完毕

子应用

创建子应用

子应用创建方法跟创建主应用一样。

安装插件

vite-plugin-qiankun:是一个专为 Vite 设计的插件,用于无缝集成 ​Qiankun 微前端框架,帮助开发者将 Vite 构建的子应用快速接入 Qiankun 主应用。

npm install vite-plugin-qiankun

配置 qiankun

vite.config.js 页面中配置如下:
图片[3] - qiankun微前端 主应用vue3+vite、子应用vue3+vite - 宋马
代码如下:

import {
             fileURLToPath, URL } from 'node:url'
import {
             defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from "vite-plugin-qiankun"

// https://vite.dev/config/
export default defineConfig({
            
  base: 'http://localhost:3001',
  build: {
            
    target: 'esnext',
    minify: 'esbuild',
  },
  plugins: [
    vue(),
    qiankun("vue1", {
            
      useDevMode: true,
    }),
  ],
  resolve: {
            
    alias: {
            
      '@': fileURLToPath(new URL('./src', import.meta.url))
    },
  },
  server: {
            
    port: 3001,
    cors: true,
    origin: 'http://localhost:3001',
    headers: {
            
      'Access-Control-Allow-Origin': '*'
    }
  }
})

PS:一定要允许跨域

main.js 文件配置如下:

import {
             createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'

import {
            
    renderWithQiankun,
    qiankunWindow,
} from "vite-plugin-qiankun/dist/helper";

// const app = createApp(App)
// app.use(router)
// app.mount('#app')

function render(props = {
             }) {
            
    const {
             container } = props;
    const app = createApp(App);
    app.use(router);
    container
        ? app.mount(container.querySelector("#app"))
        : app.mount("#app");
}

function initApp() {
            
    if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
            
        console.log("%c 独立渲染", "color: #ff0000; font-size: 40px;");
        render();
        return;
    }
    renderWithQiankun({
            
        mount(props) {
            
            console.log("%c qiankun 渲染", "color: #ff0000; font-size: 40px;");
            render(props);
        },
        bootstrap() {
             },
        unmount(props) {
             },
        update(props) {
             },
    });
}

initApp();

vite-plugin-vue-devtools 调试工具和 qiankun 不要同时使用,会报奇奇怪怪的错误

PS:这样 qiankun 微前端 vue3 + vite 项目配置完毕,本人测试能正常运行。
项目还未打包上线所以目前还不知道做哪些打包配置,后期持续学习补充笔记。要是有了解的大佬可以留言指点指点,非常感谢。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容