qiankun + vite + Vue 3

文章介绍

因为qiankun目前版本对于vite 和vue3支持并不是很友好,所需要配置的坑也很多,以下是我花了一个周找到的解决方法,目前暂时还没有解决的是base配置以后 在生产模式 微应用暂时不能独立运行,有大佬知道如何解决这个微应用在生产模式单独运行的配置如何改的话欢迎评论

微前端介绍

什么是微前端?
微前端是一种多个团队通过独立发布功能的方式,来共同构建现代化 web 应用的技术手段及方法策略。

微前端的特点

  • 技术栈无关  主框架不限制接入应用的技术栈,子应用可自主选择技术栈
  • 独立开发/部署  各个团队之间仓库独立,单独部署,互不依赖
  • 增量升级  当一个应用庞大之后,技术升级或重构相当麻烦,而微应用具备渐进式升级的特性
  • 独立运行时  微应用之间运行时互不依赖,有独立的状态管理
  • 提升效率  应用越庞大,越难以维护,协作效率越低下。微应用可以很好拆分,提升效率

解决问题的理念有了,那要通过怎样的技术去实现呢?

  1. iframe 最早也是最熟悉的解决方案就是通过iframe,因为它可以独立运行另一个项目,这种方案的优势:
  • 非常简单,无需任何改造
  • 完美隔离,JS、CSS 都是独立的运行环境
  • 不限制使用,页面上可以放多个 iframe 来组合业务

当然也是逃不过事务的两面性,有优点就有缺点:

  • 无法保持路由状态,刷新后路由状态就丢失(这点也不是完全不能解决,可以讲路由作为参数拼接在链接后,刷新时去参数进行页面跳转)
  • 完全的隔离导致与子应用的交互变得极其困难
  • iframe 中的弹窗无法突破其本身
  • 整个应用全量资源加载,加载太慢

既然有这么明显的问题,那就会有新的方案被创造出来

  1. 基于 single-spa 路由劫持方案

single-spa 通过劫持路由的方式来做子应用之间的切换,但接入方式需要融合自身的路由,有一定的局限性。

qiankun 孵化自蚂蚁金融科技基于微前端架构的云产品统一接入平台。它对 single-spa 做了一层封装。主要解决了 single-spa 的一些痛点和不足。通过 import-html-entry 包解析 HTML 获取资源路径,然后对资源进行解析、加载。

通过对执行环境的修改,它实现了 JS 沙箱样式隔离 等特性。
接下来我就好好的讲讲qiankun是怎么落地到生产项目的,中间遇到过哪些坑。

qiankun

qiankun官网 qiankun.umijs.org/zh/guide

按照官方文档快速搞起来

主应用

  1. 安装
$ yarn add qiankun # 或者 npm i qiankun -S
  1. 在主应用注册微应用 main.js

放在main.js的尾部

qiankun + vite + Vue 3 配置文档

主应用 (React) - main.tsx

这一块只需要根据qiankun官网进行配置

// 🌟 主应用 (React) - main.tsx 🌟

// 引入必要的模块和样式
import React from 'react';
import ReactDOM from 'react-dom/client';
import { registerMicroApps, start, addGlobalUncaughtErrorHandler } from 'qiankun';
import { StyleProvider } from '@ant-design/cssinjs';
import './index.css';
import './style/lib/tailwind.css';
import { Provider } from 'react-redux';
import { store } from './store';
import Routes from './routes';
import 'https://gradio.s3-us-west-2.amazonaws.com/3.35.2/gradio.js';
import { ss } from './utils/storage';

// 渲染主应用
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <StyleProvider hashPriority="high">
    <Provider store={store}>
      <React.StrictMode>
        <Routes />
      </React.StrictMode>
    </Provider>
  </StyleProvider>
);

// 判断开发模式
const isDevelop = import.meta.env.DEV ? true : false;

// 注册微应用
registerMicroApps([
  {
    name: 'llmwbs',
    entry: isDevelop ? '/chatbotinst/' : '/chatbotinst/',
    container: '#chatBot',
    activeRule: '/chatbot',
    props: {
      slogan: 'Hello Qiankun',
      token: ss.get('token'),
    },
  },
],
{
  beforeLoad: (app: any) => {
    console.log("before load+++++++++++", app.name);
    return Promise.resolve();
  },
  beforeMount: (app: any) => {
    console.log("before mount----------", app.name);
    return Promise.resolve();
  },
  afterMount: (app: any) => {
    console.log("after mount============", app.name);
    return Promise.resolve();
  },
  afterUnmount: (app: any) => {
    console.log("after unmount===+++++----", app.name);
    return Promise.resolve();
  },
});

// 启动 qiankun 应用
start({ sandbox: { experimentalStyleIsolation: true } });

// 添加全局异常捕获
addGlobalUncaughtErrorHandler((handler) => {
  console.log("异常捕获", handler);
});

当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。

如果微应用不是直接跟路由关联的时候,你也可以选择手动加载微应用的方式:

import { loadMicroApp } from 'qiankun';

loadMicroApp({
  name: 'micro-clouds',
  entry: '//localhost:7000',
  activeRule: '/micro-clouds',
  container: '#subapp2', // 子应用挂载的div
  // 传递给子应用的参数
  props: {
    routerBase: '/micro-clouds',
  }
});

微应用
main.js

import './public-path.js';
import { createApp } from 'vue'

import router from './router'
import './style.css'
import './style/lib/tailwind.css'
import debounceDirective from './utils/directive/throttle'
import { setupAssets, setupScrollbarStyle } from './plugins'

import { createPinia } from 'pinia'
import { loadMicroApp, start } from 'qiankun';
// 入口文件处 : main.ts
import { renderWithQiankun, QiankunProps ,qiankunWindow} from 'vite-plugin-qiankun/dist/helper'
import App from './App.vue'

const pinia = createPinia()
setupAssets()
const app = createApp(App);
app.directive('debounce', debounceDirective);
let instance: any = null;

function render(props: any = {}) {
  // console.log(props);

  const { container } = props;
  // router = createRouter({
  //     history: createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/chatbot/' : '/'),
  //     routes,
  //   });
  instance = app
    .use(router).use(pinia)
    .mount(container ? container.querySelector('#app') : '#app');

}
//这是在webpack  vue2等中采用的配置
// export async function bootstrap() {
//   console.log('[vue] vue app bootstraped');
// }
// export function mount(props) {
// console.log('props: ', props);
// console.log('微应用mount');
// render(props);
// }

// export async function unmount() {
//   instance.unmount();
//   instance._container.innerHTML = '';
//   instance = null;
//   // router = null;
// }
// vite 专属配置
// 判断是否为qiankun环境
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
      app.use(router).use(pinia)
    .mount('#app');
}

  renderWithQiankun({
    async mount(_props) {
      console.log(_props, 'mount');
      render(_props);
    },
    bootstrap() {
      console.log('bootstrap');
    },
    unmount(_props: any) {
      console.log(_props);
      instance.unmount()
      // ss.remove("chatStorage")
      // ss.remove("appSetting")
    },
    update: function (props: QiankunProps): void | Promise<void> {
      console.log(props);
    }
  });


public-path.js

(function () {
  if (window.__POWERED_BY_QIANKUN__) {
    // eslint-disable-next-line
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
    // __webpack_public_path__ = `${process.env.BASE_URL}/`
  }
})()

//通常是下面这个

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

最重要的是vite.config.ts 配置

这里踩了很多坑 找了很多案列和网站才找到的解决方法 

并且解决了生产模式样式

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
const packageName: any = require('./package.json').name;
import qiankun from 'vite-plugin-qiankun';


export default defineConfig({
    //base 代替的是qiankun文档中的publicpath 解决了文件资源等问题
   base: '/chatbotinst/',
  plugins: [
    vue(),
//这里是vite必须要配置的 webpack是不需要配置这个的 
    qiankun(packageName, {
      useDevMode: true
    }) 
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  build: {
//注释掉的这些都是webpack需要配置的 
    // outDir: 'dist',
    // target:'esnext',
    // assetsDir: './src/assets',
    // assetsInlineLimit: 4096,
    chunkSizeWarningLimit: 1500,
    // rollupOptions: {
    //   input: {
    //     main: './src/main.ts',
    //     index: './index.html'
    //   },
    //   output: {
    //     // format: 'umd',
    //     // manualChunks(id) {
    //     //   if (id.includes('node_modules')) {
    //     //     return id.toString().split('node_modules/')[1].split('/')[0].toString();
    //     //   }
    //     // },
    //     entryFileNames: `${packageName}-[name]`,
    //     chunkFileNames: 'chunks/[name].js',
    //     assetFileNames: '[name].[ext]',
    //     inlineDynamicImports: false
    //   }
    // },
//下面这个是vite需要配置的 这几个是重点!!!
    outDir: path.resolve(__dirname, "dist"),
    assetsDir: "static",
    emptyOutDir: false,
    target: "esnext", // default,最低为es2015
    cssCodeSplit: true, // default
    sourcemap: false, // default
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    }
  },
  server: {
    hmr: true,
    // proxy: {
    //   '/api': {
    //     target: 'http://10.142.38.239:19888',
    //     changeOrigin: true,
    //     rewrite: path => path.replace(/^\/api/, '')
    //   }
    // },   
     proxy: {
      '/api': {
        target: 'http://10.211.19.13:8090',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')
      }
    },
    cors: true,
    headers: {
      'Access-Control-Allow-Origin': '*'
    }
  },
});
  // webpack解决方案
     // output : {
      //   library: `${packageName}-[name]`,
      //   libraryTarget: 'umd',
      //   jsonpFunction: `webpackJsonp_${packageName}`,
      //   publicPath:'/chatbotinst/',
      // } 

等问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值