微前端qiankun从搭建到部署

1、项目搭建

通过vite构建4个应用,分别为:

basic-vue-app–(vue3基座应用)
micro-vue2-app–(vue2微应用)
micro-vue3-app–(vue3微应用)
micro-react-app–(react微应用)

打开我们的基座项目basic-vue-app 添加项目依赖,载入乾坤的包:

npm install qiankun

编写qiankun配置文件:

(1).搭建微应用的列表,进行注册
(2).启动qiankun
(3).在入口文件引入qiankun配置文件

import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
    {
        name: 'vue3-app', // 必须与微应用注册名字相同
        entry: import.meta.env.MODE === 'development' ? 'http://127.0.0.1:5174' : '/vue3-app/', // 入口路径,开发时为微应用所启本地服务,上线时为微应用线上路径
        container: '#sub-app-container', // 微应用挂载的节点
        activeRule: '/vue3-app', // 当访问路由为 /vue3-app 时加载微应用
        props: {
            msg: "我是来自主应用的值-vue3"  // 主应用向微应用传递参数
        }
    },
    {
        name: 'vue2-app',
        entry: import.meta.env.MODE === 'development' ? 'http://127.0.0.1:5176' : '/micro-vue2-app/',
        container: '#sub-app-container',
        activeRule: '/vue2-app',
        props: {
            msg: "我是来自主应用的值-vue2"
        }
    },
    {
        name: 'react-app',
        entry: import.meta.env.MODE === 'development' ? 'http://127.0.0.1:5175' : '/micro-react-app/',
        container: '#sub-app-container',
        activeRule: '/react-app',
        props: {
            msg: "我是来自主应用的值-react"
        }
    }
])
start()

注册micro-vue2-app微应用:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'

let instance = null;

const initQianKun = () => {
    renderWithQiankun({
        // 当前应用在主应用中的生命周期
        // 文档 https://qiankun.umijs.org/zh/guide/getting-started#
        mount(props) {
            console.log('vue2微应用开始挂载了')
            render(props.container)
            //  可以通过props读取主应用的参数:msg 监听主应用传值
            props.onGlobalStateChange((res) => {
                store.count = res.count
                console.log('来自主应用的count值:' + res.count)
            })
        },
        bootstrap() {
            console.log('-- bootstrap --')
        },
        update() {
            console.log('-- update --')
        },
        unmount() {
          instance.$destroy();
          instance.$el.innerHTML = '';
          instance = null;
            console.log('-- unmount --')
        },
    })
}
const render = (container) => {
    // 如果是在主应用的环境下就挂载主应用的节点,否则挂载到本地
    console.log('主应用的挂载节点' + container)
    const appDom = container ? container.querySelector('#app') : "#app"
    instance = new Vue({
      router,
      store,
      render: (h) => h(App),
    }).$mount(appDom);
}
// 判断当前应用是否在主应用中
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()

注册micro-vue3-app微应用:

import { createApp } from 'vue'
import App from './App.vue'
import { store } from './store'
import router from './router'

import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'

const initQianKun = () => {
    renderWithQiankun({
        // 当前应用在主应用中的生命周期
        // 文档 https://qiankun.umijs.org/zh/guide/getting-started#
        mount(props) {
            console.log('vue3微应用开始挂载了')
            render(props.container)
            // 可以通过props读取主应用的参数:msg
            // 监听主应用传值
            props.onGlobalStateChange((res) => {
                store.count = res.count
                console.log('来自主应用的count值:' + res.count)
            })
        },
        bootstrap() {
            console.log('-- bootstrap --')
        },
        update() {
            console.log('-- update --')
        },
        unmount() {
            console.log('-- unmount --')
        },
    })
}

const render = (container) => {
    // 如果是在主应用的环境下就挂载主应用的节点,否则挂载到本地
    console.log('主应用的挂载节点' + container)
    const appDom = container ? container : "#app"
    createApp(App).use(router).mount(appDom)
}

console.log('qiankunWindow对象')
console.log(qiankunWindow)
console.log(qiankunWindow.__POWERED_BY_QIANKUN__)

// 判断当前应用是否在主应用中
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()

注册micro-react-app微应用:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'

const initQianKun = () => {
  renderWithQiankun({
    // 当前应用在主应用中的生命周期
    // 文档 https://qiankun.umijs.org/zh/guide/getting-started#

    mount(props) {
      render(props.container)
      //  可以通过props读取主应用的参数:msg
      // 监听主应用传值
      props.onGlobalStateChange((res) => {
        console.log(res.count)
      })
    },
    bootstrap() { },
    unmount() { },
  })
}

const render = (container) => {
  // 如果是在主应用的环境下就挂载主应用的节点,否则挂载到本地
  const appDom = container ? container : document.getElementById('root')
  ReactDOM.createRoot(appDom).render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  )
}

// 判断当前应用是否在主应用中
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()

Vite配置:

以micro-vue2-app为例,部署在同一域名二级目录下需要设置base。

import { createVuePlugin } from 'vite-plugin-vue2';
import { defineConfig } from 'vite';
import qiankun from 'vite-plugin-qiankun'

// https://vitejs.dev/config/
export default ({ mode }) => {
  return defineConfig ({
    base: mode === 'development' ? './' : '/micro-vue2-app/',
    resolve: {
      alias: [{ find: '@', replacement: '/src' }],
    },
    server: {
      host: '0.0.0.0',
      port: 5176,
      proxy: {
        '/api': {
          target: 'http://127.0.0.1:8000/api',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
        },
      },
    },
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: `@import "@/assets/style/index.scss";`,
        },
      },
    },
    plugins: [
      createVuePlugin(),
      qiankun('vue2-app', { // 微应用名字,与主应用注册的微应用名字保持一致
        useDevMode: true
      }),
    ],
  });
}

本地分别启动主应用和子应用:

以micro-vue2-app为例:激活路由为/vue2-app则加载vue2子应用挂载在基座应用指定容器内,子应用路由正常切换。

在这里插入图片描述

2、运维部署

本地window机器安装nginx:

https://nginx.org/en/download.html 下载nginx安装包解压到指定目录,启动nginx:
在这里插入图片描述

hosts文件配置本地ip映射域名:

C:\Windows\System32\drivers\etc下增加:

127.0.0.1 demofe.noahgroup.com

nginx的conf目录下新建conf.d目录,以域名为文件名新建文件:

在这里插入图片描述

nginx配置文件做如下更改,设置根目录为基座应用build后的dist文件夹:

在这里插入图片描述

重启nginx:

在这里插入图片描述

npm run build基座应用,浏览器输入域名:

在这里插入图片描述

分别打包micro-vue2-app,micro-vue3-app,micro-react-app,因为是部署在同一个域名下,有两种方案:

(1)、将打包后的dist文件分别copy到基座应用dist目录下,以子应用的enter为文件名命名:

在这里插入图片描述

(2)、nginx通过alias配置将子应用映射到相应的子目录,请注意将主应用和子应用的部署路径替换为实际的路径,以vue3-app为例:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

重启nginx,浏览器查看,以micro-vue2-app为例,点击“进入Vue2-App应用的Home页” 进入到vue2微应用/home路由下:

在这里插入图片描述

以上就是将qiankun微前端基座应用和微应用部署在同一个域名下,主应用和微应用都可独立部署,如若分别部署在不同的域名下,将微应用入口entey改为独立部署的地址。

3、在qiankun中如何区分子应用挂载还是独立部署?

子应用独立运行时,直接挂载应用

function render(props = {}, routers = router) {
  const { container } = props;
  instance = new Vue({
    router: routers,
    store,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

作为子应用运行时

export async function bootstrap() {
  console.log('[vue] vue app bootstraped');
}

export async function mount(props) {
  const newGetComputedStyle = window.getComputedStyle;
  window.getComputedStyle = function (el, pseudoElt) {
    if (el === document) return { overflow: 'auto' };
    if (el instanceof HTMLElement) {
      return newGetComputedStyle(el, pseudoElt);
    }
    return {};
  };

  render(props, uamsRouter);
}

export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = '';
  instance = null;
}

4、遇到问题

(1)、Vite中不能导出qiankun生命周期函数

  • vite 构建的 js 内容必须在 type=module 的 script 脚本里;
  • qiankun 的源码依赖之一 import-html-entry 则不支持 type=module 这个属性
  • qiankun 是通过 eval 来执行这些 js 的内容,而 vite 里面 import/export 没有被转码, 所以直接接入会报错:不允许在非type=module 的 script 里面使用 import
方案一:

因为vite使用的rollup,所以我们使用可以使用rollup插件 rollup/plugin-html,然后修改vite.config.js中build的配置,把vite默认输出的target模式修改一下,将module改为esnext。有如下缺点:

  • 可以实现生产环境接入,开发环境不行;
  • vite没有动态publicPath的支持;所以 Vite.config 中 base 配置需要写死
  • vite code-splitting(代码分割)功能并不支持iife和umd两种格式,导致路由无法懒加载;
  • 图片资源只会被打包成 base64,无论图片大小
    https://github.com/umijs/qiankun/issues/1268
方案二:(推荐)

vite-plugin-qiankun插件,https://github.com/tengmaoqing/vite-plugin-qiankun

  • 保留 vite 构建 es 模块的优势
  • 一键配置,不影响已有的 vite 配置
  • 支持 vite 开发环境
    修改vite.config.ts配置和main.ts中导出生命周期钩子如上。
### 乾坤微前端框架与React结合使用教程 #### 创建React子应用 为了创建一个可以作为微前端使用的React子应用,推荐使用`create-react-app`来初始化项目环境[^1]。这一步骤简化了许多配置工作,使得开发者能够专注于业务逻辑的开发。 ```bash npx create-react-app my-microfrontend-app cd my-microfrontend-app npm start ``` #### 配置生命周期函数 为了让React应用成为qiankun兼容的应用程序,需要定义特定的生命週期钩子——`bootstrap`, `mount`, 和 `unmount`。这些方法允许主应用程序控制子应用的行为,在加载、渲染和卸载阶段执行必要的操作[^3]。 ```javascript import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; const render = (props) => { const container = document.getElementById('root'); const root = ReactDOM.createRoot(container); root.render(<App />); }; // 初始化时调用 export async function bootstrap() { console.log('React app bootstrapped'); } // 加载组件并将其挂接到DOM树上 export async function mount(props) { render(props); } // 卸载组件前清理资源 export async function unmount() { const container = document.getElementById('root'); const root = ReactDOM.createRoot(container); root.unmount(); } ``` #### 注册子应用至QianKun Shell Application 最后一步是在壳应用中注册这个新创建的React子应用。通过向shell application传递相应的参数完成这一过程,包括名称、入口URL和其他选项[^4]。 ```javascript import { registerMicroApps, start } from 'qiankun'; registerMicroApps([ { name: 'my-react-subapp', entry: '//localhost:3000', // 子应用的服务地址 container: '#subapp-container', activeRule: '/react' } ]); start(); // 启动qiankun ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值