微前端在管理系统中的最佳实践

一、业务背景

近期的一个业务涉及对管理系统统进行重构,涉及业务主要是后端监控,包括服务器的CPU,内存、磁盘、QPS、QPM,JVM监控等,同时也包括用户和权限管理模块;前后端未分离,页面总数达到50+,整个项目加载后将近20M,相当庞大,我们要支持的既有之前代码的重构,又有新业务需求,工作量不小

二、待解决的研发痛点

本次技术选型,主要是解决之前开发时遇到的痛点:

  1. 工程越来越复杂,打包越来越慢,构建产出物越来越大
  2. 团队人员多,产品功能复杂,代码冲突多、影响面大
  3. 前后端未分离,或分离不彻底
  4. 界面和逻辑混杂
  5. 发布流程耗时、繁琐

核心目的都是提高用户体验、理顺开发流程、提高工程效率;经过筛选,我们最终选择了微前端的开发方案。

三、微前端简介和实践

微前端简单地说,就是将一个大的前端工程拆分成一个一个的小工程。别小看这些小工程,它们也都是可以独立开发、构建、运行、发布的;整个系统就是由这些小工程协同合作,实现整个系统的展示与交互。我们运用一种新技术,并不是因技术新老,而是因为他们能够真正有效的解决我们当前页面遇到的问题,接下来详细讲解一下微前端框架icestark在我们项目中的应用和最佳实践。

原理简介

微前端分为框架应用和子应用,框架应用内部维护了所有子应用的配置信息,包括路由规则、bundle 地址等,同时劫持了 window.history 相关的几个跳转事件,当捕获到页面跳转事件时,框架会根据跳转的路由获取对应的子应用信息,然后跟之前的子应用信息进行对比,如果是同一个子应用,则什么都不做,如果是不同的子应用,则将前一个子应用的 bundle 卸载,同时加载新的子应用 bundle 资源,加载完成后子应用 bundle 会执行自身的渲染逻辑。一个系统只有一个框架应用,框架应用负责整体的 Layout 以及子应用的管理与注册;子应用通常是一个单页面应用,可能包含一个或多个页面,子应用负责自身相关页面代码。

机构设计图片

整体方案
  1. 项目目录

    
    │───dist  ----------------------项目打包目录
    ├── package-lock.json
    ├── package.json 
    ├── src -------------------------开发目录
    │   ├── common
    │   │   ├── components
    │   ├── consolePro
    │   ├── frameIndex ---------------主应用
    │   ├── homePro
    │   ├── screenPro  ---------------子应用
    │   │   ├── api
    │   │   │   └── index.js
    │   │   ├── components  ----------当前子应用公共组件
    │   │   │   └── Func
    │   │   │       ├── index.jsx
    │   │   │       └── index.scss
    │   │   ├── index.html -----------html
    │   │   ├── index.js  ------------入口js
    │   │   ├── store     ------------store
    │   │      ├── action
    │   │      │   └── index.js
    │   │      ├── action-types.js
    │   │      ├── index.js
    │   │      └── reducer
    │   │          └── index.js
    │   ├── settingPro -------------子应用
    
  2. 主应用

    实际项目中主应用包括整体Layout,Header、Footer、左侧菜单、子应用的注册。比较核心的部分是路由注册机制,我们要处理好本地、预发、生产不同的环境下的子应用注册,这里应该从构建角度统一处理,避免打包时到处手动修改配置

    import React from "react";
    import { AppRouter, AppRoute } from "@ice/stark";
    class MainFrame extends Component {
    
      	getSubAppResource(app){
          let appConfig = {
            dashboard: {
              development: [
                "http://localhost/js/main.js",
                "http://localhost/css/index.css"
              ],
              beta: [
                "http://beta.com/css/index.css",
                "http://beta.com/js/main.js",
              ],
              production: [
                "https://pro.com/css/index.css",
                "https://pro.com/js/main.js",
              ]
            }
          }
          return appConfig[app][process.env.NODE_ENV]
        }
      
        render() {
            return (
                <AppRouter
                    onRouteChange={this.handleRouteChange}
                    onAppLeave={this.handleAppLeave}
                    onAppEnter={this.handleAppEnter}
                >
                    <AppRoute
                        path="/dashboard"
                        basename="/dashboard"
                        hashType={true}
                        title="数据大屏"
                        url={this.getSubAppResource('dashboard')}
                    />
                    <!--其他子应用-->
                </AppRouter>
            );
        }
    }
    
  3. 子应用

    子应用的划分主要依据业务的归类,例如:设置子应用,数据大屏子应用、控制台子应用等,子应用都会在中间模块展示。由于本次是同一团队开发,全部项目都放到一个大的工程里,如果多团队协作,子应用也可以分离出去,子应用目录结构和主应用一致。

  4. 共享模块

    多个应用通用模块可独立出来,防止代码冗余;例如:搜索组件、404页面、公用工具类等

构建优化
  1. 整体方案

    提取公共Webpack配置文件common.js,框架和子应用都有自己的配置文件,一方面继承公共配置,另一方面配置自己的启动端口和publicpath等差异化属性。另外npm script需要针对每个应用和各个环境定制,例如主框架本地启动:npm run start;主框架预发环境构建:npm run build-beta;主框架生产环境构建:npm run build-pro;其他子应用也一样,核心目的是通过不同的命令构建适配不同环境的代码,避免发布时手动到处修改代码适配各个环境。

  2. 构建优化

    • node_modules共享:多个子应用共享node_modules,较少体积,提高效率

    • pre-build cdn + bundless:通过DllPlugin提前打包公共类库并发布到cdn,通过script引入,剩余要构建的只包含业务代码,优化过程中可通过webpack-bundle-analyzer插件分析bundle的结构,我们最终每个子应用构建后大小在200kb左右。

作用域控制

多个子应用css和js可能相互影响,我们可通过以下方式避免:

  1. CSS 隔离

    • 尽量少使用基础组件(防止子应用有不同版本造成冲突)

    • 尽量使用独有的 class,可以添加统一的前缀或者开启 CSS Module

  2. js隔离

    • 全局性的变量、函数需要添加统一前缀,避免重复

    • 各个应用的开发团队之间,确定一些开发公约

  3. 最后如果是接入已有代码且评估影响较大,还是建议回退到iframe方式接入,减少冲突和影响

前后端分离
  1. 未分离的痛点

    • 本地开发:强依赖后端,需要启动后端项目才能运行前端,后端环境搭建复杂。
    • 发布:两端耦合,一端发布必须连带另一端。
    • 代码管理:某个分支到底是处理前端问题还是后端问题?如果是主要处理前端问题但又必须携带后端代码,导致git仓库臃肿。
  2. 怎样分离

    • 开发分离: 使用Mock;后端支持cros;使用devServer的proxy实现接口代理。
    • 发布分离:我们要实现全部分离,包括html、js、css、图片等所有静态资源,发布项目下包括主框架和各个子应用,可以分别分布,互不影响。
  3. 延伸

    • 前端发布也是整个前端工程化的重要组成部分,我们的目标是:a、高效发布(预发问题调试非常需要频繁改动代码后立即编译、发布、多终端观察效果) b、可随时回滚任意版本 c、线上发布需审批 d、节省资源 e、可支持独立域名 f、高并发。如果使用公司发布平台发布一个应用,预发环境至少一台2C2G,线上环境双机房至少两台4C4G,这样的成本,想想都心疼,我们的最佳实践是基于 OSS + Domain Proxy 的自研前端发布系统,配合发布脚本可以在预发环境一键构建并发布多个项目,Domain Proxy服务器4C4G单台可达3万tps,彻底解决前端发布难题,非常适合微前端应用发布。

四、总结

以上就是我们使用微前端的最佳实践,最终我们追求的目标是:

  1. 更好的用户体验
  2. 前后端彻底分离解耦,包括开发阶段 + 发布阶段
  3. 方便多人甚至多团队协作
  4. 界面和逻辑分离
  5. 提高构建速度,较小构建产物
  6. 可快速独立部署

由于本人水平有限,希望大家多提意见建议,共同探讨微前端最佳实践,推动微前端项目的落地。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值