news 2026/8/22 13:35:23

微前端-qiankun

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微前端-qiankun

微前端与 qiankun 学习笔记

一、微前端概述

微前端(Micro Frontends)是一种将前端应用拆分成多个独立、可部署的部分的架构模式,每个部分可以由不同的团队、技术独立开发、测试、部署和维护。这种架构类似于后端的微服务,是为了应对前端项目复杂难维护、技术栈多种多样、多团队协同冲突等问题提出的。

二、核心思想

微前端的核心思想是将大型单体前端应用拆分为多个独立、自治、可独立开发部署的小型子应用(微应用),再通过主应用(基座)统一整合,最终对用户呈现为一个完整、无感知的整体。

三、基本要素

  1. 技术栈无关:主应用不强制限制子应用技术栈,Vue、React、Angular、jQuery 等应用可以在同一基座中共存。
  2. 独立开发部署:子应用可以拥有独立仓库、独立构建流程和独立发布节奏。
  3. 运行时集成:主应用负责路由分发、资源加载、生命周期调度和公共能力注入。
  4. 应用隔离:子应用之间应尽量隔离样式、全局变量、事件监听、定时器和全局状态,避免互相污染。
  5. 通信可控:主应用与子应用之间通过 props、事件总线、状态管理或约定 API 通信,避免随意读写全局对象。

四、qiankun 概述

在中大型后台管理系统迭代中,老项目技术栈老旧、新业务快速迭代、多团队并行开发是常态,qiankun 作为蚂蚁开源微前端方案,凭借 JS/CSS 沙箱、多技术栈兼容、独立部署特性成为行业首选。
qiankun是一个基于single-spa封装的微前端框架,用于帮助开发者构建生产可用的微前端架构。它可以把多个独立开发、独立部署的前端应用聚合到同一个主应用中,并通过路由规则控制子应用的加载、挂载和卸载。
注意:qiankun 子应用需要支持独立运行。如果子应用依赖主应用传入的 props、全局状态、用户信息或鉴权信息,需要提供默认值、降级逻辑或 mock 数据,避免独立启动时报错。

五、qiankun 的核心设计理念

  • 简单接入:qiankun 提供registerMicroAppsstartloadMicroApp等 API,主应用只需要配置子应用名称、入口地址、挂载容器和激活规则,就可以完成基本接入。
  • 技术栈无关:子应用可以使用 Vue、React、Angular、jQuery 等不同技术栈,只要按 qiankun 约定导出生命周期即可接入。
  • 独立开发部署:子应用可以独立开发、独立构建、独立发布,主应用通过入口地址加载子应用资源。
  • 运行时隔离:qiankun 通过 JS 沙箱、样式隔离和生命周期管理,降低子应用之间互相污染的风险。

六、qiankun 的特性

  • 基于 single-spa:在 single-spa 的生命周期调度能力之上,提供更易用的微前端接入方式。
  • HTML Entry:主应用可以通过子应用入口 HTML 自动解析和加载 JS、CSS 等资源,降低接入成本。
  • JS 沙箱:隔离子应用对全局对象的修改,降低全局变量污染风险。
  • 样式隔离:通过样式作用域或 Shadow DOM 等方式减少 CSS 冲突,具体能力与 qiankun 版本和配置有关。
  • 资源预加载:可在浏览器空闲时预加载子应用资源,提高后续访问速度。
  • 独立部署:子应用可以独立构建和发布,主应用通过入口地址加载最新子应用。

七、qiankun 快速上手

一个最小 qiankun 项目通常包含:

qiankun-demo/ ├── main-base/ # 主应用,也叫基座应用 ├── vue2-sub/ # Vue2 子应用 └── vue3-sub/ # Vue3 子应用

基本流程:

  1. 主应用安装 qiankun。
  2. 主应用注册子应用入口、挂载容器和激活规则。
  3. 子应用开启跨域访问。
  4. 子应用导出 bootstrap、mount、unmount 生命周期。
  5. 子应用配置打包格式和资源 publicPath。
  6. 分别启动主应用和子应用,通过主应用路由访问子应用。

八、主应用配置(基座项目)

8.1 安装 qiankun 依赖

cdmain-basenpminstallqiankun@^2--save

8.2 注册子应用(src/main.js)

import{createApp}from'vue'importAppfrom'./App.vue'import{registerMicroApps,start}from'qiankun'// 注册两个子应用registerMicroApps([{name:'vue2-sub',// 子应用唯一标识entry:'http://localhost:8081',// 本地开发地址container:'#micro-container',// 挂载DOM容器IDactiveRule:'/app-vue2',// 路由匹配规则,访问该路由加载子应用},{name:'vue3-sub',entry:'http://localhost:8082',container:'#micro-container',activeRule:'/app-vue3',}])// 启动qiankunstart()createApp(App).mount('#app')

8.3 增加子应用挂载容器

主应用注册代码:

// src/main.jsimport{createApp}from'vue';importAppfrom'./App.vue';importrouterfrom'./router';import{registerMicroApps,start}from'qiankun';registerMicroApps([{name:'vue2-sub',entry:'http://localhost:8081',container:'#micro-container',activeRule:'/app-vue2',props:{token:'mock-token',from:'main-app'}},{name:'vue3-sub',entry:'http://localhost:8082',container:'#micro-container',activeRule:'/app-vue3',props:{token:'mock-token',from:'main-app'}}],{beforeLoad:app=>{console.log('[qiankun] before load:',app.name);returnPromise.resolve();},beforeMount:app=>{console.log('[qiankun] before mount:',app.name);returnPromise.resolve();},afterUnmount:app=>{console.log('[qiankun] after unmount:',app.name);returnPromise.resolve();}});start({prefetch:true,sandbox:{experimentalStyleIsolation:true}});constapp=createApp(App);app.use(router);app.mount('#app');

App.vue挂载容器:

<template> <div class="main-wrap"> <!-- 主应用菜单跳转 --> <router-link to="/app-vue2">进入 Vue2 子应用</router-link> | <router-link to="/app-vue3">进入 Vue3 子应用</router-link> <!-- 子应用挂载节点 --> <div id="micro-container"></div> <router-view /> </div> </template>

九、子应用改造

接入 qiankun 的子应用通常需要完成以下改造:

  1. 开启跨域访问,确保主应用可以加载子应用 HTML、JS、CSS 等资源。
  2. 导出bootstrapmountunmount生命周期。
  3. 在独立运行时自行渲染,在 qiankun 环境中等待主应用调用mount
  4. 设置运行时 publicPath,避免异步 chunk、图片、字体等资源路径错误。
  5. 如果子应用使用 history 路由,需要让子应用路由 base 与主应用activeRule保持一致。
  6. Webpack 子应用需要配置 UMD 输出格式。
  7. Vite 子应用需要使用对应的 qiankun 适配方案。
  8. unmount中销毁应用实例、事件监听、定时器、订阅和全局副作用。

Vue2 Webpack 子应用接入代码

Vue2 子应用入口:

import'./public-path';importVuefrom'vue';importAppfrom'./App.vue';importrouterfrom'./router';Vue.config.productionTip=false;letinstance=null;functionrender(props={}){const{container}=props;constmountNode=container?container.querySelector('#app'):document.querySelector('#app');if(!mountNode){thrownewError('[vue2-sub] mount node #app not found');}instance=newVue({router,render:h=>h(App)}).$mount(mountNode);}if(!window.__POWERED_BY_QIANKUN__){render();}exportasyncfunctionbootstrap(){console.log('[vue2-sub] bootstrap');}exportasyncfunctionmount(props){console.log('[vue2-sub] mount',props);render(props);}exportasyncfunctionunmount(){console.log('[vue2-sub] unmount');if(instance){instance.$destroy();if(instance.$el){instance.$el.innerHTML='';}instance=null;}}

Vue2 子应用public/index.html

<divid="app"></div>

Vue CLI / Webpack 子应用通常需要配置 UMD 输出。

constpackageName=require('./package.json').name;module.exports={devServer:{port:8081,headers:{'Access-Control-Allow-Origin':'*'}},configureWebpack:{output:{library:`${packageName}-[name]`,libraryTarget:'umd',chunkLoadingGlobal:`webpackJsonp_${packageName}`}}};

注意:jsonpFunction多见于 Webpack 4,chunkLoadingGlobal多见于 Webpack 5。

子应用被主应用加载时,异步 chunk、图片、字体等资源路径容易错,所以要配置运行时 publicPath。
Vue CLI 子应用可以新增:

// src/public-path.jsif(window.__POWERED_BY_QIANKUN__){// eslint-disable-next-line no-undef__webpack_public_path__=window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}

然后在入口文件最顶部引入(注意必须放在其他业务 import 之前):

import'./public-path';

路由 base:

// RouterimportVuefrom'vue';importVueRouterfrom'vue-router';Vue.use(VueRouter);constrouter=newVueRouter({mode:'history',base:window.__POWERED_BY_QIANKUN__?'/app-vue2':'/',routes:[{path:'/',component:()=>import('./views/Home.vue')}]});exportdefaultrouter;

Vue3 子应用接入代码

Vue3 子应用入口:

import{createApp}from'vue';importAppfrom'./App.vue';importrouterfrom'./router';letapp=null;letmountNode=null;functionrender(props={}){const{container}=props;mountNode=container?container.querySelector('#app'):document.querySelector('#app');if(!mountNode){thrownewError('[vue3-sub] mount node #app not found');}app=createApp(App);app.use(router);app.mount(mountNode);}if(!window.__POWERED_BY_QIANKUN__){render();}exportasyncfunctionbootstrap(){console.log('[vue3-sub] bootstrap');}exportasyncfunctionmount(props){console.log('[vue3-sub] mount',props);render(props);}exportasyncfunctionunmount(){console.log('[vue3-sub] unmount');if(app){app.unmount();app=null;}if(mountNode){mountNode.innerHTML='';mountNode=null;}}

如果项目使用 Vue CLI 4 / Webpack 4,使用jsonpFunction;如果项目使用 Webpack 5,使用chunkLoadingGlobal
示例:

// vite.config.jsimport{defineConfig}from'vite';importvuefrom'@vitejs/plugin-vue';importqiankunfrom'vite-plugin-qiankun';exportdefaultdefineConfig({plugins:[vue(),qiankun('vue3-sub',{useDevMode:true})],server:{port:8082,cors:true}});

入口文件示例:

import{createApp}from'vue';import{renderWithQiankun,qiankunWindow}from'vite-plugin-qiankun/dist/helper';importAppfrom'./App.vue';letapp=null;functionrender(props={}){const{container}=props;app=createApp(App);app.mount(container?container.querySelector('#app'):'#app');}renderWithQiankun({bootstrap(){console.log('[vite-sub] bootstrap');},mount(props){console.log('[vite-sub] mount',props);render(props);},unmount(){console.log('[vite-sub] unmount');app.unmount();app=null;}});if(!qiankunWindow.__POWERED_BY_QIANKUN__){render();}

路由 base:

// Routerimport{createRouter,createWebHistory}from'vue-router';constrouter=createRouter({history:createWebHistory(window.__POWERED_BY_QIANKUN__?'/app-vue3':'/'),routes:[{path:'/',component:()=>import('./views/Home.vue')}]});exportdefaultrouter;

十、常见问题

1.__POWERED_BY_QIANKUN__是什么?为什么有时是 undefined?

window.__POWERED_BY_QIANKUN__是 qiankun 加载子应用时注入的运行时标识,用来判断当前子应用是否运行在 qiankun 主应用中。

它为undefined通常有几种情况:

  1. 子应用是独立运行的,此时没有被 qiankun 加载,属于正常情况。
  2. 子应用入口代码执行时机不正确,判断发生在 qiankun 注入之前。
  3. TypeScript 项目没有声明该全局变量,导致类型报错。
  4. 子应用构建格式或生命周期导出错误,导致 qiankun 没有正确识别子应用。
  5. Vite 或 Webpack 项目没有按对应接入方式配置。
    TypeScript 类型声明:
// src/types/qiankun.d.tsexport{};declareglobal{interfaceWindow{__POWERED_BY_QIANKUN__?:boolean;__INJECTED_PUBLIC_PATH_BY_QIANKUN__?:string;}}

2. 子应用资源 404 怎么办?

常见原因是子应用被主应用加载后,异步 chunk、图片、字体等资源仍然按照子应用独立运行时的相对路径加载,导致路径错误。

解决方案:

  1. Webpack 子应用配置运行时 publicPath。
  2. Vite 子应用使用对应 qiankun 适配插件。
  3. 静态资源尽量使用绝对路径或 CDN 地址。
  4. 检查子应用部署路径是否和入口地址一致。

Webpack 解决代码:

if(window.__POWERED_BY_QIANKUN__){// eslint-disable-next-line no-undef__webpack_public_path__=window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}

3. 子应用样式污染怎么办?

样式污染通常来自全局选择器,例如bodyhtml.button.container等。解决方案包括:

  1. 开启 qiankun 样式隔离配置。
  2. 子应用样式增加命名空间。
  3. 避免在子应用中直接修改bodyhtml的全局样式。
  4. UI 组件库主题样式要避免互相覆盖。

主应用配置:

start({sandbox:{experimentalStyleIsolation:true}});

子应用样式命名空间示例:

.vue2-sub-app { .button { color: #f00; } .page-container { padding: 16px; } }

子应用根节点:

<template> <div class="vue2-sub-app"> <router-view /> </div> </template>

4. 子应用切走后仍然有定时器或事件怎么办?

原因通常是unmount中没有清理全局副作用。子应用被卸载时,除了销毁 Vue/React 实例,还要清理事件监听、定时器、订阅、全局状态等。
示例:

lettimer=null;functionhandleResize(){console.log('resize');}exportasyncfunctionmount(props){window.addEventListener('resize',handleResize);timer=setInterval(()=>{console.log('running');},1000);render(props);}exportasyncfunctionunmount(){window.removeEventListener('resize',handleResize);if(timer){clearInterval(timer);timer=null;}instance.$destroy();instance.$el.innerHTML='';instance=null;}

十一、 高频面试题

1. 什么是微前端?解决什么业务痛点?

微前端是把大型单体应用拆分成多个独立子应用,由主应用统一调度;
解决:

  1. 多团队并行开发、技术栈异构(Vue2、Vue3、React通用);
  2. 项目体量过大打包慢、迭代耦合、牵一发动全身;
  3. 老旧项目存量改造,不用一次性全量重构。

2. 微前端常见实现方案有什么区别?

  1. iframe:隔离最强,天然隔离 JS、CSS 和运行环境;缺点是路由同步、通信、性能、弹窗层级、用户体验都比较麻烦。
  2. Web Components:基于浏览器原生组件模型,可结合 Shadow DOM 做样式隔离;缺点是工程生态、团队使用习惯和复杂应用集成成本需要评估。
  3. 运行时加载方案:例如 qiankun,主应用在运行时加载子应用资源,并通过生命周期、沙箱、样式隔离完成应用集成。
  4. 模块联邦方案:例如 Webpack Module Federation / EMP,更偏向构建和运行时模块共享,适合跨应用复用模块或组件。

3. qiankun 核心原理是什么?

  1. HTML Entry:主应用拉取子应用入口 HTML,解析其中的scriptlinkstyle等资源,再由 qiankun 加载并执行子应用。
  2. 生命周期调度:qiankun 基于 single-spa 管理子应用的bootstrapmountunmountupdate
  3. JS 沙箱:通过代理或快照机制隔离子应用对全局对象的修改,降低全局变量污染风险。
  4. 样式隔离:通过样式作用域、动态样式处理或 Shadow DOM 等方式减少 CSS 冲突。
  5. 应用通信:主应用可以通过 props 或全局状态机制向子应用传递数据和方法。

4. qiankun 四个生命周期各自作用

  • bootstrap:子应用初始化,只在首次加载时执行一次,适合做不会频繁变化的初始化工作。
  • mount:子应用被激活时执行,用于创建应用实例并挂载 DOM。
  • unmount:子应用失活时执行,用于销毁实例、解绑事件、清理定时器、取消订阅、清空 DOM。
  • update:主应用手动触发子应用更新时执行,使用频率较低。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/22 13:30:07

3步上手chrome-react-perf:React性能分析Chrome扩展新手入门教程

3步上手chrome-react-perf&#xff1a;React性能分析Chrome扩展新手入门教程 【免费下载链接】chrome-react-perf An Operation Interface for react-addons-perf Package 项目地址: https://gitcode.com/gh_mirrors/ch/chrome-react-perf chrome-react-perf 是一款专为…

作者头像 李华
网站建设 2026/8/22 13:27:06

BDSup2Sub:位图字幕转换工具,一次搞定 SUP、VobSub、DVD-SUP 互转

BDSup2Sub&#xff1a;位图字幕转换工具&#xff0c;一次搞定 SUP、VobSub、DVD-SUP 互转 【免费下载链接】BDSup2Sub Blu-Ray/DVD subtitle editor 项目地址: https://gitcode.com/gh_mirrors/bd/BDSup2Sub 不同平台的字幕格式互不兼容&#xff0c;蓝光 SUP、DVD-SUP、…

作者头像 李华
网站建设 2026/8/22 13:25:32

如何用 DDrawCompat 修复老游戏黑屏与画面撕裂

如何用 DDrawCompat 修复老游戏黑屏与画面撕裂 【免费下载链接】DDrawCompat DirectDraw and Direct3D 1-7 compatibility, performance and visual enhancements for Windows Vista, 7, 8, 10 and 11 项目地址: https://gitcode.com/gh_mirrors/dd/DDrawCompat DDrawCo…

作者头像 李华