qiankun搭建主应用与子应用

qiankun搭建主应用与子应用

微前端方案

iframe

子应用通过iframe嵌套到父应用之中

缺点:
1:url不同步,刷新页面后,iframe中的路由会丢失
2:全局上下文完全隔离,内存变量不共享
3:ui不同步(eg: iframe的只能在当前嵌套内容区展示)
4:加载慢

qiankun

基座与子应用概念

基座(主应用):主要负责集成所有的子应用,提供一个入口能够访问你所需要的子应用的展示,一般不写复杂逻辑
子应用:根据不同的业务划分的模块,每个子应用都打包成umd模块的形式供基座来加载

基座实现

  • 概念:只是一个容器,用于提供子应用的存放与共享内存变量等
  • 创建项目 npx create-react-app base

步骤:

1:安装qiankun : cnpm i qiankun
2:修改入口文件 index.js || index.ts
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { registerMicroApps, start } from 'qiankun'; // 0:引入qiankun

import { BrowserRouter, HashRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <HashRouter>
   <App />
  </HashRouter>
);

// 1:要加载的子应用列表
const apps = [
  {
    name:'sub-react', // 子应用名称
    entry: '//localhost: 3001', // 默认会加载这个路径的htlm,解析里面的js
    activeRule: '/sub-react', // 匹配的路由
    container: '#sub-app' // 加载的容器 (渲染路由那边 App.jsx)
  }
]

// 2:注册子应用 + qiankun的生命周期
registerMicroApps(apps, {
  beforeLoad: [async app => {
    console.log('beforeLoad', app.name);
  }],
  beforeMount: [async app => {
    console.log('beforeMount', app.name);
  }],
  afterMount: [async app => {
    console.log('afterMount', app.name);
  }]
});

// 3:启动服务
start();
3:定义挂载子应用区域 App.jsx
import React, { Component,useEffect } from 'react';
import routers from './router';    // 路由文件
import { Routes,Route,Link } from 'react-router-dom';    // 路由插件

export default class App extends Component {

 render(){
   return (
     <div>
      {/* 基座内容区 */}
      <Routes>
        {
          routers.map((item, index) => (
            <Route path={item.path} key={index} element={<item.components />}></Route>
          ))
        }
      </Routes>
      {/* 加载子应用内容区域 */}
      <div id="sub-app"></div>
     </div>
   )
 }
}

子应用1实现 sub-react项目

index.tsx

1:根据props下传递的container,判断是否为qiankun环境下运行
2:需要根据基座中配置加载子应用 匹配路由规则 写入对应的 basename值
3:判断是否在qiankun环境下,非qiankun环境下独立运行
4:qiankun生命周期函数使用 => 基座点击菜单进入子应用时候触发 mount函数
5: 使用加载引入 public-path.js => 用于qiankun防止加载资源报错
6:改造webpack配置( cnpm i react-app-rewired ) config-overrides.js + 修改package.json文件指令

import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom'
import './public-path.js'

let root: any;
function render(props: any) {
  const { container } = props // 1:container有这个代表运行再qiankun环境下的
  const dom = container ? container.querySelector('#root') : document.getElementById('root')
  root = createRoot(dom)
  root.render(
    // 2:basename 这边对应着 基座入口文件index.tsx 下的 apps加载子应用的匹配规则
    <BrowserRouter basename='/sub-react'> 
      <App/>
    </BrowserRouter>
  )
}

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

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

// 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
export async function mount(props: any) {
  console.log('sub-react', props)
  props.onGlobalStateChange((state, prev) => {
    // state: 变更后的状态; prev 变更前的状态
    console.log(state, prev);
    // 将这个state存储到我们子应用store
  });
  props.setGlobalState({ count: 2 });
  render(props);
}

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

public-path.js

if (window.__POWERED_BY_QIANKUN__) {
  // 动态设置 webpack publicPath,防止资源加载出错
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

package.json

  • 原本的 "start": "react-scripts start", 替换为这个格式如下 "start": "react-app-rewired start",
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  },

config-overrides.js ( webpack打包配置 作用:把项目打包为umd模块,用于qiankun读取当前项目暴露的生命周期函数 )

  • cnpm i react-app-rewired 与 修改package.json指令
// 在根目录下新增config-overrides.js文件并新增如下配置
const { name } = require("./package");

module.exports = {
  webpack: (config) => {
    config.output.library = `${name}-[name]`;
    // 项目打包为umd模块,方便qiankun读取项目暴露出来的生命周期函数等 => index.tsx之中的  export async function mount等
    config.output.libraryTarget = "umd"; 
    config.output.chunkLoadingGlobal = `webpackJsonp_${name}`;
    return config;
  }
};

注意点

当前子项目运行在 3001  => 需要修改基座之中 index.tsx之中的 apps变量的entry 
eg:
const apps = [
  {
    name:'sub-react', // 子应用名称
    entry: '//localhost: 3001', // 默认会加载这个路径的htlm,解析里面的js
    activeRule: '/sub-react', // 匹配的路由
    container: '#sub-app' // 加载的容器 (渲染路由那边 App.jsx)
  }
]

子应用2实现 vue-app项目 ( 使用vite打包的 )

  • cnpm i vite-plugin-qiankun => vue使用qiankun的插件(用于暴露)

入口文件 main.js

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
import router from './router'
let app: any;
// 判断是否为qiankun 环境下
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
  createApp(App).use(router).mount('#app');
} else { // qiankun环境下的
  renderWithQiankun({
    mount(props) {
      app = createApp(App);
      app.use(router).mount(props.container.querySelector('#app'));
    },
    bootstrap() {
      console.log('vue app bootstrap');
    },
    update() {
      console.log('vue app update');
    },
    unmount() {
      console.log('vue app unmount');
      app?.unmount();
    }
  });
}

vite.config.ts

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: 3002,
    cors: true,
    origin: 'http://localhost:3002'
  },
  plugins: [
    vue(),
    qiankun('sub-vue', { // 配置qiankun插件
      useDevMode: true
    })
  ]
})

子应用3实现 umi-app项目 (umi4)

  • cnpm i @umijs/plugins

配置 .umirc.ts

export default {
  base: '/sub-umi', // 匹配基座的 加载子应用路由 index.tsx => apps中的activeRule
  npmClient: 'npm',
  plugins: ['@umijs/plugins/dist/qiankun'],
  qiankun: {
    slave: {},
  },
  headScripts: [
    { src: 'https://unpkg.com/axios@1.1.2/dist/axios.min.js', ignore: true },
  ],
};

umi下展示qiankun的生命周期 src / app.ts

export const qiankun = {
  async mount(props: any) {
    console.log(props)
  },
  async bootstrap() {
    console.log('umi app bootstraped');
  },
  async afterMount(props: any) {
    console.log('umi app afterMount', props);
  },
};
  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值