当前位置: 首页 > article >正文

使用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
  1. 子应用(如果你的子应用不是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;
      }
    }

踩坑汇总


http://www.kler.cn/a/468185.html

相关文章:

  • 51单片机(二)中断系统与外部中断实验
  • PINN模型详解
  • 【开源】创建自动签到系统—QD框架
  • 计算机网络——数据链路层-流量控制和可靠传输
  • 云打印之菜鸟打印组件交互协议
  • 深入理解 Java 接口的回调机制
  • 高频 SQL 50 题(基础版)_1068. 产品销售分析 I
  • NLP-transformer学习:(8)trainer 使用方法
  • 抖音评论地区分布可视化期末项目
  • 【微服务】【Sentinel】认识Sentinel
  • JODConverter结合LibreOffice如何转换ppt pptx成图片
  • 谷粒商城-高级篇-Sentinel-分布式系统的流量防卫兵
  • Arduino 小白的 DIY 空气质量检测仪(5)- OLED显示模块、按钮模块
  • 微信小程序校园自助点餐系统实战:从设计到实现
  • CSS系列(50)-- View Transitions详解 系列总结
  • 应用Docker快速实现 JMeter + InfluxDB + Grafana 监控方案
  • 虚拟机图像界面打不开了
  • NLP初识
  • leetcode中简单题的算法思想
  • 计算机网络•自顶向下方法:网络安全、RSA算法
  • react报错解决
  • 1、pycharm、python下载与安装
  • 服务器信息整理:用途、操作系统安装日期、设备序列化、IP、MAC地址、BIOS时间、系统
  • 什么是Kafka的重平衡机制?
  • 小红书怎么看ip所属地?小红书ip属地为什么可以变
  • 基于Spring Boot的健康饮食管理系统