使用qiankun搭建微前端应用及踩坑

线上演示地址:React App

源码地址:https://github.com/Jiang-K-J/micro-app?tab=readme-ov-file (帮忙点个小星星)

主应用:react 18+

子应用:vite + vue3

子应用:react 18+

安装

  1. 主应用

    $ yarn add qiankun # 或者 npm i qiankun -S

  2. 子应用(如果你的子应用不是vite构建的,你无需安装任何插件)

    npm i vite-plugin-qiankun

搭建

在主应用中注册子应用
复制代码
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'react app', // 子应用的名称
    entry: '//localhost:7100', // 子应用运行的url和port
    container: '#yourContainer', // 用于放置子应用显示的载体
    activeRule: '/sub-react', // 匹配的路由
  },
  {
    name: 'vue app',
   entry: '//localhost:3000',
    container: '#yourContainer',
    activeRule: '/sub-vue',
  },
]);

start();
子应用配置
  • vite子应用

    import { createApp } from 'vue'
    import App from './App.vue'
    import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
    import { router, abstractRouter } from './router';
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'

    let app;
    if (!qiankunWindow.POWERED_BY_QIANKUN) {
    createApp(App).use(router).use(ElementPlus).mount('#app');
    } else {
    renderWithQiankun({
    // 子应用挂载
    mount(props) {
    let routerInstance = null;
    console.log('props', props?.path);
    if (props?.path) {
    routerInstance = abstractRouter;
    } else {
    routerInstance = router;
    }
    app = createApp(App);
    // 使用 provide 将 props 传递给所有后代组件
    app.provide('qiankunProps', props);
    app.use(routerInstance).use(ElementPlus);
    app.mount(props.container.querySelector('#app'));
    if (props?.path) {
    routerInstance.push(props.path)
    }
    },
    // 只有子应用第一次加载会触发
    bootstrap() {
    console.log('vue app bootstrap');
    },
    // 更新
    update() {
    console.log('vue app update');
    },
    // 卸载
    unmount() {
    console.log('vue app unmount');
    app?.unmount();
    }
    });
    }

  • react子应用

    import React from "react";
    import { createRoot } from "react-dom/client";
    import { BrowserRouter, MemoryRouter } from "react-router-dom";
    import { QiankunContext } from "./QiankunContext.jsx";
    import "./index.css";
    import App from "./App";
    import "./public-path"; // webpack子应用需要新增一个这样的文件,下方有说明
    import "./a1.js";

    let root;
    function render(props) {
    const { container,path } = props;
    const RouterWrapper = props?.path ? MemoryRouter : BrowserRouter;
    const dom = container
    ? container.querySelector("#root")
    : document.getElementById("root");
    root = createRoot(dom);
    root.render(
    <RouterWrapper basename="/sub-react" initialEntries={path ? [path] : ["/"]}>
    <QiankunContext.Provider value={props}>
    <App mianProps={props} />
    </QiankunContext.Provider>
    </RouterWrapper>
    );
    }

    // 判断是否在qiankun环境下,非qiankun环境下独立运行
    if (!window.POWERED_BY_QIANKUN) {
    render({});
    }

    // 各个生命周期
    // bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
    export async function bootstrap() {
    console.log("react app bootstraped");
    }

    // 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
    export async function mount(props) {
    console.log("props from main framework", props);
    render(props);
    }

    // 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
    export async function unmount(props) {
    root.unmount();
    }

    basename="/sub-react" 这个和你在主应用注册子应用中的activeRule要保持一直

webpack构建的子应用需要新增下面的文件,并在入口文件中进行导入

src 目录新增 public-path.js

复制代码
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
子应用配置文件修改
  • webpack构建的应用

由于webpack构建的应用一般不会暴露webpack文件,我们这里可以下载 react-app-rewired 这个插件用于修改webpack配置,具体可以百度一下

复制代码
const { name } = require("./package");

module.exports = {
  webpack: (config) => {
    // 设置输出配置
    config.output.library = `${name}-[name]`;
    config.output.libraryTarget = "umd";
    config.output.chunkLoadingGlobal = `webpackJsonp_${name}`;

    return config;
  },
  devServer: (_) => {
    const config = _;

    config.headers = {
      "Access-Control-Allow-Origin": "*",
    };
    config.historyApiFallback = true;
    config.hot = false;
    config.watchContentBase = false;
    config.liveReload = false;

    return config;
  },
};
  • vite构建的应用

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import qiankun from 'vite-plugin-qiankun';
    export default defineConfig({
    base: '/sub-vue', // 和基座中配置的activeRule一致
    server: {
    port: 3000,
    cors: true,
    origin: 'http://localhost:3000' //你的实际运行地址
    },
    plugins: [
    vue(),
    qiankun('sub-vue', { // 配置qiankun插件
    useDevMode: true
    }),
    ]
    })

    这里还需要配置下方那部分内容,具体怎样在vite中配置output,可以百度一下

    复制代码
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd', // 把微应用打包成 umd 库格式
      jsonpFunction: `webpackJsonp_${name}`, // webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal
    },

具体配置可以参考官网文档:项目实践 - qiankun

建议:vite应用中base配置应该和实际线上地址保持一致,这样可以避免很多保持:

复制代码
base: 'http://xxx:3000/sub-vue', // 和基座中配置的activeRule一致

部署

部署主要是nginx配置,没有别的操作

主应用

复制代码
    location / {
      add_header Cache-Control no-cache;
      index index.html;
      try_files $uri /index.html;
    }

子应用

复制代码
# /sub-react 这个需要和activeRule保持一致即可
 location /sub-react {
     # 设置允许的跨域来源
        alias /web/qiankun/rf; # 指向静态文件目录
        index index.html;
        try_files $uri /index.html; # 注意这里的路径,仅需指向子应用的 `index.html`
    }
    
    
    location / {
  
      # 添加跨域头
      add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
      add_header Access-Control-Allow-Headers "Content-Type, Authorization";
  
      if ($request_method = OPTIONS) {
          add_header Access-Control-Allow-Origin *;
          add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
          add_header Access-Control-Allow-Headers "Content-Type, Authorization";
          return 204;
      }
    }

踩坑汇总

相关推荐
编程猪猪侠26 分钟前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞30 分钟前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路1 小时前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失9491 小时前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue8681 小时前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie1 小时前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端
遂心_1 小时前
深入解析前后端分离中的 /api 设计:从路由到代理的完整指南
前端·javascript·api
你听得到111 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构
风清云淡_A1 小时前
【REACT18.x】CRA+TS+ANTD5.X封装自定义的hooks复用业务功能
前端·react.js
@大迁世界1 小时前
第7章 React性能优化核心
前端·javascript·react.js·性能优化·前端框架