阿里微前端qiankun框架基本介绍与应用配置,包含基座与子应用间通信

搭建配置qiankun

qiankun官网

什么是微前端

微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
优点:

  • 与技术栈无关
  • 独立开发、独立部署,部署完成后主框架自动同步更新
  • 增量升级,兼容老项目
  • 每个微应用之间状态隔离

方案

  • iframe:通过iframe标签嵌入父应用
    url不同步,刷新页面时路由丢失;全局上下文隔离;window对象不一致;加载速度慢

  • single-spa:单页面应用,url改变时进行匹配
    没有实现js隔离和css隔离;需求修改大量配置

  • qiankun:基于single-spa封装,提供API;和技术栈无关;使用方便;实现了js隔离和css隔离;资源预加载,浏览器空闲时间预加载未打开的资源应用

基座

  1. 安装qiankun pnpm i qiankun
  2. main.js中进行改造
//main.js
import './assets/main.scss'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { registerMicroApps, start } from 'qiankun'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')

registerMicroApps(
  [
    {
      name: 'vue-app-1', // 必须与微应用注册名字相同
      entry: 'http://localhost:9001', // 入口路径,开发时为微应用所启本地服务,上线时为微应用线上路径
      container: '#sub-app', // 微应用挂载的节点
      activeRule: '/vue-app-1', // 当访问路由为 /micro-vue 时加载微应用
      props: {
        msg: '我是来自主应用的值-vue' // 主应用向微应用传递参数
      },
      pathPrefix: '/vue-app-1' // 使用 pathPrefix 自动添加前缀
    }
    //   {
    //     name: 'react-app',
    //     entry: 'http://127.0.0.1:5175',
    //     container: '#react-app-container',
    //     activeRule: '/micro-react',
    //     props: {
    //       msg: '我是来自主应用的值-react',
    //     },
    //   },
  ]
  //   {
  //     // 生命周期钩子函数
  //     beforeLoad: (app) => {
  //       console.log('beforeLoad', app)
  //     },
  //     beforeMount: (app) => {
  //       console.log('beforeMount ', app)
  //     },
  //     afterMount: (app) => {
  //       console.log('afterMount', app)
  //     },
  //     beforeUnmount: (app) => {
  //       console.log('beforeUnmount ', app)
  //     },
  //     afterUnmount: (app) => {
  //       console.log('afterUnmount', app)
  //     },
  //   }
)

//step3 设置默认进入微应用
//setDefaultMountApp('/vue3')

start() //启动微应用
  1. 在App.vue或其他位置挂载容器
<!-- 子应用渲染区域 -->
<div id="sub-app"></div>

子应用

安装插件 pnpm i vite-plugin-qiankun

  1. 修改vite.config.js内容
import { fileURLToPath, URL } from 'node:url'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
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(),
    AutoImport({
      resolvers: [ElementPlusResolver()]
    }),
    Components({
      resolvers: [ElementPlusResolver()]
    }),
    qiankun('vue-app-1', {
      // 微应用名字,与主应用注册的微应用名字保持一致
      useDevMode: true
    })
  ],
  // 需要和基座中配置的activeRule一致
  base: '/vue-app-1',
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  //建议设定固定的端口号,方便基座使用
  server: {
    open: true,
    port: 9001,
    cors: true
  }
})
  1. 修改main.js内容
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 导入路由配置
import {
  renderWithQiankun,
  qiankunWindow
} from 'vite-plugin-qiankun/dist/helper'
import { createPinia } from 'pinia'
const app = createApp(App)

app.use(router) // 使用 Vue Router
app.use(createPinia())
// 清理容器
function clearContainer(container) {
  while (container.firstChild) {
    container.removeChild(container.firstChild)
  }
}

const render = (props = {}) => {
  const { container } = props
  const appElement =
    container?.querySelector('#app') || document.getElementById('app')

  // 确保容器为空
  if (appElement) {
    clearContainer(appElement)
  }

  createApp(App).use(router).mount(appElement)
}

const initQianKun = () => {
  renderWithQiankun({
    bootstrap() {
      console.log('微应用:bootstrap')
    },
    mount(props) {
      // 获取主应用传入数据
      console.log('微应用:mount', props)
      render(props)
    },
    unmount(props) {
      console.log('微应用:unmount', props)
    },
    update(props) {
      console.log('微应用:update', props)
    }
  })
}

// 判断是否使用 qiankun ,保证项目可以独立运行
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()

主应用与子应用通信

  1. 使用initGlobalState进行通信
    基座在src中新建个action.js文件
// 此action文件为定义微应用之间全局状态
// 引入qiankun的应用间通信方法initGlobalState
import { initGlobalState } from 'qiankun'

const initialState = {
  //这里可以写初始化数据
  // x:1
  project_id: 'woq'
}

const actions = initGlobalState(initialState) //初始化state

export default actions

基座在main.js中引入action.js文件

import actions from '@/action.js'

registerMicroApps(
  [
    {
      name: 'vue-app-1',
      entry: '//localhost:9001',
      container: '#sub-app',
      activeRule: '/vue-app-1',
      props: {
        data: 'child子应用',
        mainAppRouter: history,
        router,
        //这里添加
        actions
      },
      pathPrefix: '/vue-app-1' // 使用 pathPrefix 自动添加前缀
    }
  ]
)

子应用也在src中新建一个action.js文件

function emptyAction() {
  // 警告:提示当前使用的是空 Action
  console.warn('Current execute action is empty!')
}

// 我们首先设置一个用于通信的Actions类

class Actions {
  actions = {
    onGlobalStateChange: emptyAction,
    setGlobalState: emptyAction
  }
  constructor() {}
  // 默认值为空Action

  // 设置actions
  setActions(actions) {
    this.actions = actions
  }

  // 映射
  onGlobalStateChange(...args) {
    return this.actions.onGlobalStateChange(...args)
  }
  // 映射
  setGlobalState(...args) {
    return this.actions.setGlobalState(...args)
  }
}

const actions = new Actions()
export default actions

子应用在main.js文件中的mounted函数中挂载actions

actions.setActions(props)

子应用就可以在页面中使用基座传来的数据了

import actions from '../../action'
const projectId = ref('')
onMounted(() => {
  actions.onGlobalStateChange((state) => {
    projectId.value = state.project_id
    console.log(state)
  }, true) //onGlobalStateChange的第二个参数设置为true,则会立即触发一次观察者函数
  console.log('-------------------------')
  console.log(projectId.value)
})

基座如果要在页面中更改值也很简单,直接调用actions的setGlobalState方法即可

actions.setGlobalState({
  userInfo: res.body
})

如果要在基座的某个页面中使用子应用

参考官网

  1. 基座的router/index.js中这样写
//其中user-center为子应用的路由
{
  path: '/user-center/:pathMatch(.*)*',
  component: () => import('@/views/LayoutContainer/LayoutContainer.vue')
}

  1. 对应的LayoutContainer文件中写启动子应用
    注意:就要对应删调main.js中的start()方法
import { start } from 'qiankun'
onMounted(() => {
  //启动子应用
  if (!window.qiankunStarted) {
    window.qiankunStarted = true
    start()
  }
})

然后在该页面中需要的地方引入子应用

<!-- 子应用 -->
<div id="sub-app"></div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值