Vue3项目怎么用Qiankun快速搭建可落地的生产级微前端架构?
做Vue3项目如果遇到业务线太多、代码库越来越臃肿、技术栈不能统一升级这些麻烦,那Qiankun绝对是个靠谱的微前端方案,最近刚好帮朋友团队把三个独立的Vue3业务(用户中心、订单系统、数据看板)从iframe迁移到了Qiankun,踩了不少坑但也整理了一套能直接复制的落地流程,今天就用大家容易懂的日常问答,把从0到1搭生产架构的所有关键点讲透。
为什么选Qiankun做Vue3的微前端,不是iframe或别的?
首先聊选型是很多朋友落地前的第一步,毕竟选错了后面返工成本特别高,其实不管是做过Vue2微前端还是刚入门,iframe大家肯定都熟悉,它简单到几行代码就能嵌个页面,但生产环境真的扛不住:比如双滚动条、cookie跨域绕半天、浏览器前进后退逻辑混乱、子应用iframe内部弹窗遮罩只遮自己那块。
那对比其他Vue3微前端框架,比如MicroApp、Wujie呢?MicroApp依赖Web Components,兼容性在低版本浏览器上得额外补,而且社区里Vue3的案例成熟度不如Qiankun;Wujie是腾讯出的,用iframe做底层但做了很多优化,滚动条、弹窗这些问题都解决了,不过上手文档对纯前端新手可能没那么友好,而且有些自定义配置要写得更细。
选Qiankun最核心的原因还是这三点:一是和Vue全家桶兼容性特别好,不管是Vue3的Composition API、Pinia还是Vue Router都能完美适配,不需要大改现有代码;二是社区生态成熟,生产环境踩过的坑网上基本都能找到现成的解决方案,阿里内部也在用,稳定性有保障;三是文档足够清晰,官方文档从基础概念、快速上手、高级配置到生产最佳实践都写得很细,跟着走就能搭起来。
搭生产级Vue3+Qiankun需要哪几个核心部分?
很多教程只讲基础的主应用注册和子应用加载,但生产环境得考虑路由、状态管理、样式隔离、通信、部署这些实际问题,所以完整的架构一般分四个核心部分:主应用基座、子应用容器、公共依赖服务、部署运维方案。
先讲主应用基座,它是整个微前端的入口,负责路由分发、子应用注册、全局公共布局(比如侧边栏、顶部导航、用户登录态管理),主应用可以用Vue3也可以用其他技术栈,但既然我们的子应用都是Vue3,主应用也用Vue3+Pinia+Vue Router4是最省事的。
然后是子应用容器,这里的“容器”不是物理上的容器,而是每个子应用必须遵守的Qiankun接入规则,比如要暴露bootstrap、mount、unmount这三个生命周期钩子,要配置publicPath防止静态资源加载失败,要处理路由的base路径避免和主应用冲突。
接下来是公共依赖服务,这部分是生产环境优化的关键,能大大减少打包体积和加载时间,比如Vue3、Vue Router4、Pinia、Element Plus这些所有子应用都要用的依赖,可以通过externals或者importmap的方式提取出来,只在主应用加载一次,子应用直接复用就行,不过externals会有CDN加载失败的风险,importmap兼容性更好但需要Webpack5或者Vite的插件支持,后面会具体讲。
部署运维方案,生产环境不可能所有应用都部署在同一个服务器同一个端口,所以得解决跨域问题、路由刷新404问题、CDN加速问题,跨域一般用Nginx反向代理就行,路由刷新404可以用Nginx的try_files配置,CDN加速主要是针对提取出来的公共依赖和子应用的静态资源。
主应用基座怎么搭,要注意哪些坑?
主应用基座的搭建分为三个步骤:初始化项目、安装依赖、配置Qiankun,这里我用Vite+Vue3+Vue Router4+Pinia做演示,Webpack的配置逻辑其实差不多,只是插件不一样。
第一步初始化项目,直接用Vite官方的脚手架就行,记得选TypeScript吗?其实生产环境建议用,类型提示能减少很多bug,但今天为了照顾纯前端新手,就用JavaScript讲,后面会提一下TypeScript的适配点。
第二步安装依赖,除了Vue3全家桶之外,还要安装Qiankun的主应用依赖qiankun,如果用Vite的话,还要安装vite-plugin-qiankun,这个插件能帮我们处理一些Vite特有的问题,比如ES模块的加载、静态资源的路径。
第三步配置Qiankun,这里有几个生产环境必须注意的坑: 第一个坑是子应用的注册时机,不能在页面刚加载的时候就把所有子应用都注册了,要等主应用的路由配置好之后再注册,不然会出现子应用路由匹配失败的问题。 第二个坑是全局状态管理的初始化,如果主应用和子应用之间要共享用户登录态、主题这些全局状态,最好在主应用的入口文件main.js里就初始化Pinia,然后通过Qiankun的props传递给子应用,或者用Qiankun自带的initGlobalState方法,不过Pinia的类型提示和响应式更方便,生产环境推荐用Pinia。 第三个坑是公共布局的交互隔离,比如主应用的侧边栏收起展开不能影响子应用的布局,最好用Flex或者Grid布局把公共区域和子应用容器区域分开,子应用容器的宽高设为100%,overflow设为auto,这样就不会出现双滚动条的问题了。 第四个坑是静态资源的路径配置,主应用的publicPath最好设为绝对路径,部署的时候根据Nginx的配置来改,不然子应用加载的时候会找不到主应用的静态资源。
子应用怎么改造,最小化改动现有代码?
子应用的改造是很多朋友最担心的,怕改坏了现有的业务逻辑,其实Qiankun对Vue3子应用的改动特别小,基本上只需要改四个文件:入口文件main.js、路由配置文件router/index.js、打包配置文件vite.config.js(或者webpack.config.js)、公共样式文件。
先讲入口文件main.js的改造,要暴露bootstrap、mount、unmount这三个生命周期钩子,这里要注意的是,不能直接调用app.mount('#app'),要改成接收一个container参数,只挂载到container里的某个DOM节点上,不然子应用卸载的时候会把主应用的DOM也删掉,还有一个Vite特有的坑,就是如果用了Composition API的setup语法糖,要加一个createApp的空壳函数,不然Qiankun会找不到生命周期钩子。
然后是路由配置文件router/index.js的改造,要给每个子应用的路由加一个base路径,base路径就是子应用的路由前缀,比如用户中心的base路径是'/user',订单系统的是'/order',数据看板的是'/dashboard',这个前缀要和主应用注册子应用时配置的activeRule对应上,还有一个坑是路由的history模式,子应用最好用history模式,hash模式的话主应用和子应用的hash会冲突,不过用history模式要注意路由刷新404的问题,后面部署的时候会讲。
接下来是打包配置文件vite.config.js的改造,要配置三个东西:一是使用vite-plugin-qiankun插件,插件的name参数要和主应用注册子应用时配置的name参数完全一致;二是配置base路径,这个路径要和Nginx部署子应用的路径对应上,比如子应用部署在Nginx的'/micro-app/user'目录下,base路径就设为'/micro-app/user/';三是配置server的port和cors,port要和主应用注册子应用时配置的entry对应上,cors要设为true,不然本地开发的时候会跨域。
公共样式文件的改造,要处理样式隔离的问题,Qiankun自带了两种样式隔离方案:一种是严格样式隔离,用shadow DOM,但是兼容性不好,而且有些第三方UI库的样式会失效;另一种是scoped样式隔离,通过动态添加前缀的方式,这个兼容性好,第三方UI库的样式也能生效,生产环境推荐用这个,scoped样式隔离的配置很简单,只需要在主应用注册子应用的时候把sandbox的strictStyleIsolation设为false,experimentalStyleIsolation设为true就行。
主应用和子应用之间怎么通信,有哪些方案?
生产环境主应用和子应用之间的通信场景很多,比如用户登录态变更、主题切换、全局通知、子应用之间的数据传递,Qiankun自带了initGlobalState方法,但生产环境更推荐用Pinia或者EventBus,因为这两种方案的响应式更方便,类型提示更好(如果用TypeScript的话)。
先讲Pinia的方案,这个是最推荐的,因为如果主应用和子应用都是用Vue3+Pinia的话,不需要额外安装依赖,只需要把主应用的Pinia实例通过Qiankun的props传递给子应用就行,具体做法是:在主应用的入口文件main.js里初始化Pinia实例,然后在注册子应用的时候把Pinia实例放在props里;在子应用的mount钩子函数里接收props,然后把主应用的Pinia实例挂载到子应用的Vue实例上,这样主应用和子应用就能共享同一个Pinia store了,不过要注意的是,子应用不能修改主应用的store里的私有属性,最好通过store的actions来修改,这样代码更规范。
然后是EventBus的方案,这个适合主应用和子应用技术栈不一样的情况,或者子应用之间需要频繁通信的情况,具体做法是:在主应用里创建一个全局的EventBus实例,然后通过Qiankun的props传递给每个子应用;子应用可以通过EventBus的on方法监听事件,通过emit方法触发事件,不过EventBus的缺点是事件管理比较混乱,如果事件太多的话容易出现冲突,生产环境要注意给事件加前缀,比如主应用的事件前缀是'main-',用户中心的是'user-',这样就不会冲突了。
Qiankun自带的initGlobalState方法,这个适合简单的通信场景,比如用户登录态变更,具体做法是:在主应用里调用initGlobalState方法初始化全局状态,然后通过props把setGlobalState和onGlobalStateChange传递给子应用;子应用可以通过setGlobalState方法修改全局状态,通过onGlobalStateChange方法监听全局状态的变化,不过这个方法的响应式不如Pinia,而且没有类型提示,生产环境不推荐用复杂的通信场景。
生产环境怎么部署,解决跨域和路由刷新404问题?
生产环境部署一般用Nginx做反向代理,把主应用和子应用都部署在同一个域名下,或者同一个域名的不同目录下,这样就能解决跨域问题了,这里我用同一个域名的不同目录下做演示,比如主应用部署在根目录'/',用户中心部署在'/micro-app/user/',订单系统部署在'/micro-app/order/',数据看板部署在'/micro-app/dashboard/'。
首先讲Nginx的配置,这里有几个关键点: 第一个关键点是解决跨域问题,因为主应用和子应用都部署在同一个域名下,所以不需要配置额外的跨域头,反向代理就行。 第二个关键点是解决路由刷新404问题,不管是主应用还是子应用的history模式,都需要用Nginx的try_files配置,把所有的请求都指向主应用的index.html,然后由主应用的Vue Router来分发路由,子应用的路由刷新404问题其实是由主应用的路由分发来解决的,所以只需要配置主应用的try_files就行。 第三个关键点是配置静态资源的缓存,比如主应用和子应用的静态资源(js、css、图片)可以设置长期缓存,这样能大大减少加载时间,提升用户体验,缓存的时间可以根据静态资源的内容来定,比如带hash的静态资源可以设置一年的缓存,不带hash的可以设置一天的缓存。 第四个关键点是配置gzip压缩,压缩静态资源的体积,能进一步减少加载时间,gzip压缩的配置很简单,只需要在Nginx的http块里配置gzip on就行,然后配置gzip_types,压缩js、css、html、json这些文件。
然后讲主应用和子应用的打包配置,主应用的base路径设为'/',子应用的base路径设为对应的Nginx部署目录,比如用户中心的base路径设为'/micro-app/user/',打包的时候主应用和子应用要分开打包,然后把打包后的文件放到对应的Nginx目录下就行。
踩过的那些生产级坑,怎么提前规避?
前面讲了很多基础配置和落地流程,但生产环境踩的坑才是最关键的,今天就把我帮朋友团队踩过的几个最常见的坑分享给大家,提前规避能省很多时间。
第一个坑是Vite开发环境子应用加载失败,原因是Vite的默认入口是index.html,不是main.js,所以要在vite.config.js里配置build的lib选项,或者用vite-plugin-qiankun插件的transformHtml选项来处理。
第二个坑是第三方UI库的样式失效,原因是用了严格样式隔离shadow DOM,或者scoped样式隔离的前缀没加对,解决办法是用scoped样式隔离,然后给第三方UI库的组件加一个自定义的class前缀,比如Element Plus的组件加class="el-user",然后在子应用的样式里用:deep()选择器来修改样式。
第三个坑是子应用的Vue实例重复挂载,原因是子应用的unmount钩子函数里没有正确销毁Vue实例和路由实例,解决办法是在子应用的unmount钩子函数里调用app.unmount()和router.unmount()(如果是Vue Router4的话),还要把主应用传递过来的container里的DOM节点清空。
第四个坑是公共依赖加载失败,原因是用了externals的方式,CDN加载失败了,解决办法是用importmap的方式,然后在Nginx里配置公共依赖的本地备份,这样CDN加载失败的时候就会自动加载本地备份。
第五个坑是子应用之间的路由冲突,原因是子应用的base路径和主应用的路由路径重复了,解决办法是给主应用的路由路径加一个唯一的前缀,或者给子应用的base路径加一个更明确的前缀,比如主应用的路由路径是'/main/home',子应用的base路径是'/micro/user/home'。
Vue3+Qiankun是目前最成熟、最容易落地的微前端方案之一,只要按照上面的流程走,就能快速搭建一套生产级的微前端架构,不过落地的时候一定要注意生产环境的优化和坑的规避,比如公共依赖提取、样式隔离、通信方案、部署运维这些,最后提醒大家,微前端不是万能的,不是所有项目都适合用微前端,比如小项目、业务线少的项目,用普通的单页应用就行,只有当业务线太多、代码库太臃肿、技术栈不能统一升级的时候,才考虑用微前端。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


