目前微前端已经是很成熟的技术了,各大公司都推出了自己的微前端框架,比如蚂蚁的qiankun,京东的micro-app,如果你的子应用不使用vite构建的话,我会更加推荐后者,micro-app使用更加简单,micro-app并没有沿袭single-spa的思路,而是借鉴了WebComponent的思想,是目前市面上接入微前端成本最低的方案。

这次集成的是开源框架GoView,GoView 是一个高效的拖拽式低代码数据可视化开发平台,将图表或页面元素封装为基础组件,无需编写代码即可制作数据大屏,减少心智负担 

 正式开始构建项目:

1,主应用

        主应用使用的是vue-element-template开源后台管理框架,思路都一样,首先在路由中添加一个页面,在目录结构也记得添加

  {
    path: '/chat',
    component: Layout,
    children: [
      {
        path: 'index',
        name: 'chat',
        component: () => import('@/views/chat/index'),
        meta: { title: 'chat', icon: 'chat' }
      }
    ]
  },

        然后再路由出口页面,这里是AppMain,添加要挂载的元素

<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <router-view :key="key" />
    </transition>
    //子应用要挂载的dom
    <div id="container"></div>
  </section>
</template>

        接下来安装qiankun

npm i qiankun

        然后在main.js中注册

import { registerMicroApps, start } from 'qiankun';
//注册子应用,可以注册多个
registerMicroApps([
  {
    name: 'vue-app',//子应用名称
    entry: '//localhost:3000',//子应用端口
    container: '#container',//挂在节点
    activeRule: '/chat',//匹配路径
  },
]);

start();

2,子应用

        下载goView源码:https://gitee.com/dromara/go-view,安装依赖,运行

        它是vite构建的应用,所以需要用到对应的支持插件

npm install vite-plugin-qiankun

        安装完成后,打开vite.config.js,做如下修改,已经备注

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOptions } from './build/constant'
import viteCompression from 'vite-plugin-compression'
import { viteMockServe } from 'vite-plugin-mock'
import monacoEditorPlugin from 'vite-plugin-monaco-editor'
import qiankun from 'vite-plugin-qiankun'//导入依赖

function pathResolve(dir: string) {
  return resolve(process.cwd(), '.', dir)
}

export default defineConfig({
  base: '/',
  // 路径重定向
  resolve: {
    alias: [
      {
        find: /\/#\//,
        replacement: pathResolve('types')
      },
      {
        find: '@',
        replacement: pathResolve('src')
      },
      {
        find: 'vue-i18n',
        replacement: 'vue-i18n/dist/vue-i18n.cjs.js', //解决i8n警告
      }
    ],
    dedupe: ['vue']
  },
  // 全局 css 注册
  css: {
    preprocessorOptions: {
      scss: {
        javascriptEnabled: true,
        additionalData: `@import "src/styles/common/style.scss";`
      }
    }
  },
  plugins: [
    vue(),
    monacoEditorPlugin({
      languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html']
    }),
    viteMockServe({
      mockPath: '/src/api/mock',
      // 开发打包开关
      localEnabled: true,
      // 生产打包开关
      prodEnabled: true,
      // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件
      supportTs: true,
      // 监视文件更改
      watchFiles: true
    }),
    // 压缩
    viteCompression({
      verbose: true,
      disable: false,
      threshold: 10240,
      algorithm: 'gzip',
      ext: '.gz'
    }),
    //添加
    qiankun("vue-app", {
      // 微应用名字,与主应用注册的微应用名字保持一致
      useDevMode: true,
    }),
  ],
  build: {
    target: 'es2015',
    outDir: OUTPUT_DIR,
    // minify: 'terser', // 如果需要用terser混淆,可打开这两行
    // terserOptions: terserOptions,
    rollupOptions: rollupOptions,
    brotliSize: brotliSize,
    chunkSizeWarningLimit: chunkSizeWarningLimit
  },
  //添加
  server: {
    origin: 'http://localhost:3000', //项目baseUrl,解决主应用中出现静态地址404问题
  },
})

        然后打开main.ts

import { createApp } from 'vue'
import App from './App.vue'
import router, { setupRouter } from '@/router'
import i18n from '@/i18n/index'
import { setupStore } from '@/store'
import { setupNaive, setupDirectives, setupCustomComponents, initFunction } from '@/plugins'
import { GoAppProvider } from '@/components/GoAppProvider/index'
import { setHtmlTheme } from '@/utils'

// 引入全局样式
import '@/styles/pages/index.scss'
// 引入动画
import 'animate.css/animate.min.css'
// 引入标尺
import 'vue3-sketch-ruler/lib/style.css'

//导入依赖
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
//添加初始化方法
const initQianKun = () => {
    renderWithQiankun({
        // 当前应用在主应用中的生命周期
        mount(props:any) {
            appInit(props.container)
            //  可以通过props读取主应用的参数:msg
        },
        bootstrap() { },
        unmount() { },
    })
}
//修改appInit,传递参数主应用要挂在的节点名称
async function appInit(container?:any) {
  const goAppProvider = createApp(GoAppProvider)

  const app = createApp(App)

  // 注册全局常用的 naive-ui 组件
  setupNaive(app)

  // 注册全局自定义指令
  setupDirectives(app)

  // 注册全局自定义组件
  setupCustomComponents(app)

  // 挂载状态管理
  setupStore(app)

  // 解决路由守卫,Axios中可使用,Dialog,Message 等全局组件
  goAppProvider.mount('#appProvider', true)

  // 挂载路由
  setupRouter(app)

  // 路由准备就绪后挂载APP实例
  await router.isReady()

  // Store 准备就绪后处理主题色
  setHtmlTheme()

  // 语言注册
  app.use(i18n)
   //此处 判断有没有传,没有就挂载子应用的#app上
  const appDom = container ? container : "#app"
  // 挂载到页面
  app.mount(appDom, true)

  // 挂载到 window
  window['$vue'] = app
}

// 判断当前应用是否在主应用中
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : appInit().then(() => {
  initFunction()
})

这就已经完成了,剩下的就是样式上的问题,改改就可以了

Logo

低代码爱好者的网上家园

更多推荐