来源:京东技术
导读
本文将深入浅出地探讨微前端架构模式——MicroApp,从微前端的基本概念、核心优势以及如何在现代web开发中实现它,详解微前端如何使得大型应用能够分解为小型、简单、可独立开发和部署的子应用,同时还能保持各个子应用间的完整性和协调性。此外,本文还将探讨实施微前端时可能遇到的挑战和最佳实践,为开发者提供一条清晰的实施路径,帮助其构建更加灵活和可维护的前端生态系统。
本文将深入浅出地探讨微前端架构模式——MicroApp,从微前端的基本概念、核心优势以及如何在现代web开发中实现它,详解微前端如何使得大型应用能够分解为小型、简单、可独立开发和部署的子应用,同时还能保持各个子应用间的完整性和协调性。此外,本文还将探讨实施微前端时可能遇到的挑战和最佳实践,为开发者提供一条清晰的实施路径,帮助其构建更加灵活和可维护的前端生态系统。
微前端的概念
图 1.(6)基于多页的子应用缺乏管理,规范/标准不统一,无法统一控制视觉呈现、共享功能和依赖,造成重复工作。
4.1 微前端框架选型
1. single-spa是一个将多个单页面应用聚合为一个整体应用的 JavaScript 微前端框架。
2. qiankun 基于 single-spa 封装的微前端框架。
本次项目使用的是umi+react+ts的技术栈,其实比较适合用qiankun,qiankun继承了umi框架,但是这个框架配置起来比较麻烦。
4.1.2 MicroApp优势
图 2.
4.2 场景演示
最外层是基座,基座是微前端应用集成的一个重要平台,同时也肩负着管理公共资源、依赖、规范的责任,主要有以下职责:
(7)多语言管理(最重要的一点)
图 3.
4.3 搭建微前端基座
以react基座为例
1、创建项目
npm i @micro-zoe/micro-app --save
package.json文件里面dependencies里面会多一行代码,看到下面代码则表示项目已经具备micro-app接入能力了。
"@micro-zoe/micro-app": "^1.0.0-alpha.7"
(4)在入口引入micro-app
import microApp from '@micro-zoe/micro-app'microApp.start()
{path: '/yp',name: 'yp',linkHidden: true,linkDisable: true,breadcrumbClose: true,component: '@/pages/yp-app',}
b. 子应用的文件
在pages文件下创建一个yp-app(子应用的文件)
import React from 'react';import config from '@/config';// /** @jsxRuntime classic */// /** @jsx jsxCustomEvent */// import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event';export default (): React.ReactElement => {// 子应用点击了面包屑的回到首页const onDispathChild = (e: any) => {const { isBackHome } = e.detail.data;if (isBackHome) window.location.href = '/';};return (<>>);};
说明:onDataChange方法是子应用和主应用的信息通讯方法,micro-app 在 window 下面挂载了一个全局的对象,只需要去触发它提供的方法,完成主子之间的通信即可,不管是交互逻辑还是数据传递逻辑,就都通了。
c.主应用成功引入子应用(子应用是VUE项目)
图 4.
//config.tslet config = {yp: 'https://xxx.xxx.com:7000',//本地环境子应用的路由前缀};const isEnvPro = process.env.NODE_ENV === 'production';if (isEnvPro) {config = {yp: 'https://xxx.xxx.com',//预发环境环境子应用的路由前缀};}export default config;//以上是config.ts文件的全部-----end//菜单点击事件里面的内容history.push('/yp'); //切换到子应用setTimeout(() => {microApp.router.push({name: 'yp',//和子应用的name要保持一致,为了匹配到对应子应用的路由path: `${config.yp}${item.url}`,}); //跳转子应用的路由,其中config是上面的配置文件,根据不同的环境取对应环境的子应用,item是当前点击的菜单路径信息}, 500);
这里解释下为什么要用setTimeout,首先通过history.push('/yp')切换到子应用,防止切换过去之后短时间内找不到子应用的路由,所以加个延迟能够准确的跳转到子应用对应的路由。
devServer: { headers: { 'Access-Control-Allow-Origin': '*', }},这个有相对应的文档,根据子应用的语言设置不同的跨域信息。
(2)如果是接口跨域。
那么就需要找后端设置允许前端跨域的代码了,以Java为例:
@Override public void init(FilterConfig filterConfig) { this.origins = Lists.newArrayList("http://localhost:8088", "https://xx.xxx.com", "https://xx.aaa.com:8088", "https://xx.bbb.com:7000"); }proxy: (() => { return { // 本地访问预发 '/avoid': { target: 'https://xx.xxx.com', changeOrigin: true, bypass: (req) => { if(req.headers.accept.indexOf('html') !== -1 ) { return '/index' } }, } }})()最初本地代理是路由里面包含'/'就代理到预发上,正常单独访问子应用的链接,可以正常访问本地代理预发的接口,但是放到主应用里面就不可以了,最后给代理改成了整个项目公共部分/avoid,解决了此问题,不一定项目是因为这个,但是可以从代理入手查找问题。
子应用获取来自基座应用的数据,以及基座应用向子应用发送数据,基座应用获取来自子应用的数据,全局数据通讯详细参考https://zeroing.jd.com/docs.html#/zh-cn/data
虽说微前端已经是一个非常成熟的领域了,使用微前端目的就是为了降本提效,但是在现在的这个开源大环境,使用哪种框架,或者自己实现微前端都可以,个人觉得应该考虑如果当前的项目接入微服务之后,变得维护成本更高,那就要考虑是否适合微前端了,并不能为了用而用,微前端并不是适合所有的场景,遇到问题尝试着去考虑多种方案方案解决。