qiankun 结合 vue3, 小白快速上手体验

一、主应用改造

首先需要维护一份微应用列表,里面包含了微应用的名称、入口和生效规则,若需要给子应用传递内容,可以在 props 传入对应的内容

javascript 复制代码
// app.js
const apps = [
  {
    name: 'micro-vue-app3',
    entry: '//localhost:3013',
    container: '#micro-vue-app3',
    activeRule: '/micro-vue3-app3',
    props: {},
  },
]

export default apps

有了微应用数据后,我们就开始注册微应用

javascript 复制代码
// micro.js

import { registerMicroApps, addGlobalUncaughtErrorHandler, start } from "qiankun"

import apps from "./app"

/** 注册微应用 */
registerMicroApps(apps, {
	// 微应用加载前
	beforeLoad: (app) => {
		console.log("before-load", app.name)
		return Promise.resolve()
	},
	beforeMount: (app) => {
		console.log("before mount", app)
		return Promise.resolve()
	},
	afterMount: (app) => {
		console.log("after mount", app.name)
		return Promise.resolve()
	}
})

addGlobalUncaughtErrorHandler((event: Event | string) => {
	console.error(event)
	const { message: msg } = event as any
	if (msg && msg.includes("died in status LOADING_SOURCE_CODE")) {
		console.error("微应用加载失败,请检查应用是否可运行")
	}
})

export default start

接下来,我们在项目的入口文件中启动微前端。

js 复制代码
import { createApp } from 'vue'
import router from './router'
import startQiankun from './micro'
import App from './App.vue'

// start()
startQiankun({
  sandbox: {
    experimentalStyleIsolation: true, // 样式隔离
  },
})

const app = createApp(App)
app.use(router)

app.mount('#app')

二、子应用改造

vue3 项目创建方式分为 vue-cli 创建和 vite 创建,vue-cli 底层是 webpack,两种方式创建的项目的改造内容不太一样,接下来便为各位介绍一下改造点。

vue-cli 创建 vue3 子应用

vue.config.js 配置,需要将输出文件格式改成 umd 库格式

javascript 复制代码
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package.json')
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 3013,
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd', // 把微应用打包成 umd 库格式
    },
  },
})

创建 public-path.ts文件,动态设置 webpack publicPath 防止资源报错

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

main.js需要区分独立运行还是子应用运行

javascript 复制代码
import './public-path'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

let instance = null

function render(props = {}) {
  const { container } = props
  instance = createApp(App)
  instance.use(router)
  instance.use(store)
  instance.mount(container ? container.querySelector('#app') : '#app')
}

// 非乾坤环境
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}
export async function bootstrap() {
  console.log('初次注册================')
  console.log('[vue] vue app bootstraped')
}

export async function mount(props) {
  console.log('挂载子应用==============vue3-app')
  console.log(props)
  render(props)
  instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange
  instance.config.globalProperties.$setGlobalState = props.setGlobalState
}

export async function unmount() {
  console.log('子应用卸载==========')
  instance.unmount()
  instance._container.innerHTML = ''
  instance = null
}

vite 创建 vue3 子应用

vite 若要用在 qiankun 微前端,需要安装 vite-plugin-qiankun 插件支持,并修改 vite.confit.ts配置:

javascript 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    qiankun('vite-vue3-app3', {
      useDevMode: true,
    }),
  ],
  server: {
    port: 7001,
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
})

main.ts文件中,需要引入 renderWithQiankunqiankunWindow

javascript 复制代码
// @ts-nocheck
import { createApp } from 'vue'
import router from './router'
import App from './App.vue'
import actions from './shared/action'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'

let app

function render(props) {
  if (props) {
    // 注入 actions 实例
    actions.setActions(props)
  }
  const { container } = props
  app = createApp(App)
  app.use(router)
  app.mount(container ? container.querySelector('#app') : '#app')
}

const initQianKun = () => {
  renderWithQiankun({
    /**
     * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
     */
    mount(props) {
      console.log('vite 应用挂载', props)
      const { container } = props
      render(props)
    },
    /**
     * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
     * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
     */
    bootstrap() {
      console.log('vite-vue3 初始化')
    },
    /**
     * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
     */
    unmount() {
      console.log('vite-vue3 卸载')
      app.unmount()
    },
  })
}

qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()

router路由的 window 对象也需要用 qiankunWindow 去替换:

typescript 复制代码
import { createRouter, RouteRecordRaw, createWebHistory } from 'vue-router'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
import HelloWorld from '../components/HelloWorld.vue'
import Text from '../components/Text.vue'

const routes: Array<RouteRecordRaw> = [{ path: '/', name: 'Home', component: HelloWorld, children: [{ path: 'text', name: 'Text', component: Text }] }]
const base = qiankunWindow.__POWERED_BY_QIANKUN__ ? '/vite-vue3-app3' : '/'

const router = createRouter({
  history: createWebHistory(base),
  routes,
})

export default router

三、Actions 通信

qiankun 内部提供了 initGlobalState 方法用于注册 MicroAppStateActions 实例用于通信,该实例有三个方法,分别是:

  • setGlobalState:设置 globalState - 设置新的值时,内部将执行 浅检查,如果检查到 globalState 发生改变则触发通知,通知到所有的 观察者 函数。
  • onGlobalStateChange:注册 观察者 函数 - 响应 globalState 变化,在 globalState 发生改变时触发该 观察者 函数。
  • offGlobalStateChange:取消 观察者 函数 - 该实例不再响应 globalState 变化。
js 复制代码
import { initGlobalState, MicroAppStateActions } from 'qiankun'

const initialState = {}
const actions = initGlobalState(initialState)

const actions = actions.setGlobalState({
  userInfo: { name: '改变用户', ssga: '2515' },
  age: ++currentAge.value,
})

// onGlobalStateChange 第二个参数为 true,表示立即执行一次观察者函数
actions.onGlobalStateChange((state) => {
  console.log(state, 'state')
  const { userInfo, age } = state
  currUserInfo.value = userInfo
  currentAge.value = age
}, true)

四、总结

本文介绍了 vue3 接入 qiankun 的方法,希望有助于个人初次上手了解。也有些人认为 vue3 结合 vite 的话,使用无界的方法会更好,有时间也会去看看如何使用,欢迎各位友好交流讨论!

相关推荐
左手吻左脸。3 分钟前
Vue 全栈面试题大全(2026 最新版最详细)
前端·javascript·vue.js
Aphasia3115 分钟前
手写KeepAlive组件
前端·react.js·面试
两个西柚呀9 分钟前
js中的同步和异步,三种处理异步任务的方式
前端·javascript
pe7er36 分钟前
软件设计不要“既要又要”
前端·后端·架构
kyriewen1 小时前
从Webpack到Vite:我们迁移了一个10万行代码的项目,总结了这7个坑
前端·webpack·vite
IT_陈寒1 小时前
Java Stream并行流的坑:我花了3小时才找到的线程安全问题
前端·人工智能·后端
小新1101 小时前
最简单但完整的 Vue 响应式示例(一个简单的计数器按钮)
前端·javascript·vue.js
川冰ICE1 小时前
JavaScript进阶④|Symbol与元编程,对象的隐藏身份
开发语言·javascript·ecmascript
水煮白菜王1 小时前
开源 AI 桌宠 Clawd on Desk:让 Claude Code 的状态从终端‘蹦‘到桌面
javascript·人工智能·开源
吃口巧乐兹2 小时前
异步异常处理:AggregateException 的拆解与最佳实践
javascript