微模块-前端业务模块化探索,拆解巨石应用的又一利器

7,593次阅读
没有评论

共计 4008 个字符,预计需要花费 11 分钟才能阅读完成。

大家好,我是 Eluxjs 的作者,Eluxjs是一套基于“微模块 ”和“ 模型驱动”的跨平台、跨框架『同构方案』,欢迎了解 …

文前声明,以下推断和结论纯属个人探索,鉴于本人知识水平所限,谬误在所难免,恳请各位大佬不吝赐教 …

什么是前端“微模块”?

Elux 中的『微模块』是指在 Web 前端工程中,将 代码 和相关 资源 按照不同的 业务功能 进行归类和模块化。

根据 业务功能 进行模块化一直以来都是后端的普遍做法,而 Web 前端则通常都是按照 UI 界面的视图区块 View 来进行模块化,这样的模块实际上只是Component 组件,不具备独立自治的能力。究其原因我想是因为在早期 Web1.0 的时代,前端的职能就是仅仅作为后端 API 数据的一个 Render 渲染器,所以前后端的视野和格局出现了分化,也导致很多人说前端根本无架构之说。

然而 web 生态发展到今天,浏览器越来越强大,赋能越来越多,甚至不亚于一个小型操作系统,这时候的 Web 前端早已不是当初简单的数据渲染器,状态管理、会话维持、数据持久化、文件缓存、通信协议 … 随着 PWA、小程序、快应用的推广,WebAPP 不再是瘦客户端,渐渐成长为大胖小子。

此时的我们应当跳出“渲染器”的井口,而从一个完整的软件工程来思考我们的前端架构,Web 前端不只是一层 View、一个 GUI,我们需要回归到与后端一致的以 业务领域 为驱动的模块化视角。

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

为什么前端需要“微模块”?

  • 从开发角度来说 :我们需要 高内聚、低耦合 的松散结构体,而不是牵一发而动全身的巨石应用,这不管是对于开发、维护、还是后期渐进式重构,都至关重要。

    前端 Leader:经过一年多的迭代和人员变动,我们代码已经混乱不堪了,开发越来越吃力,必须要重构,否则玩不下去了!产品经理:嗯,我理解,这里面也有很多是我们需求变更频繁引起的,我支持你们重构!前端 Leader:感谢大佬理解,那新需求先停下来,等我们重构好了再迭代吧?产品经理:你们重构要多久?前端 Leader:产品这么复杂了,估计至少要 3 个月左右吧。产品经理被吓出一身冷汗:大佬,你要 3 天还可以考虑,停下来 3 个月估计公司都要关门了...
    前端 Leader:可是产品这么复杂,几天时间完成重构是天方夜谭。产品经理想了想:这样把,我每个迭代少安排几个需求,这样你们每个月就可以留几天时间重构了。前端 Leader:这可不是 1 +1= 2 的问题,而是 0 与 1 的问题,大佬你不了解!产品经理:谁说我不了解,你们就不能渐进式重构吗?前端 Leader:...
    

    可见重构并不难,难的是重构的同时保持正常业务迭代,我们首先要将应用隔离成很多小块,利用碎片化的时间局部重构。如果我们的前端工程是基于“微模块”构建,一来可以轻松的找到 局部重构 边界,二来也可以通过维持“微模块”的对外接口来无感知替换。

  • 从产品角度来说 :软件架构永远是服务于业务需求的。我们希望我们的产品能像搭积木一样 按需组合,可以快速包装出各种灵活多样的套餐,以满足客户越来越精细化的定制需求。

    某个大型应用包含 A,B,C,D,E,F,G 等若干功能,原来一直是整体打包出售...
    
    随着用户需求的多样化,有的用户仅需要部分功能,于是聪明的前端架构师“小李”利用时下流行的微前端技术,将应用拆分成了的 3 个子应用:-【基础应用】包含功能:A
    -【子应用 A】包含功能:B,C,D
    -【子应用 B】包含功能:E,F,G
    
    这样等于有 3 个套餐可以供客户选择:- 套餐 A:基础应用 + 子应用 A
    - 套餐 B:基础应用 + 子应用 B
    - 套餐 C:基础应用 + 子应用 A + 子应用 B
    
    然而用户的需求越来越精细化,有的需要 ABCD,有的需要 ACEG,有的需要 ABDF...
    这相当于要将每个功能点都独立成为一个子应用,上百个子应用如何管理与发布?而且同一个功能可能还存在需求版本的不同,这让“小李”无可适从。

    现在我们利用“微模块”来帮助小李解决问题:

    • 将各种独立的业务功能封装成不同的微模块:A,B,C,D,E,F,G
    • 将各种微模块按需求迭代版本,发布成 NPM 包
    • 某客户需要 A,C1( C 功能的某个版本),E2( E 功能的某个版本),G 功能,我们单独为该客户创建一个聚合工程分支,安装相应版本的微模块:npm install A C@1 E@2 G

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

我们知道世界上有一款建站神器wordpress,曾经号称世界上 50% 的网站都是由它创建的,我认为它的成功秘诀就是社区模版机制和功能插件化,你要什么功能都总能找到“前端 + 后端”一起打包安装的插件,这也类似于“微模块”的概念。

  • 从工程的角度来说 :“微模块”是跨工程、跨项目共享 通用业务代码 的理想决方案,对于跨端、跨平台复用 业务逻辑 尤其有用。

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

前端“微模块”的划分原则与边界

  • 拥有 高内聚、低耦合 的工程结构。
  • 拥有 独立自治 的子域逻辑。

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

从图中可以看到,每个微模块负责定义和维护自己领域内的事务,并且 麻雀虽小,五脏俱全,拥有独立的路由解析、状态管理、数据模型、控制器、视图、组件、资源、业务实体、API 管理等等 … 总之,所有与自己领域相关的资源都被内聚到了一起。

以下是某巨石应用的 SRC 目录,其特点是以“文件职能 ”作为一级分类、“ 功能模块”作为次级分类:

├─ src
│  ├─ api                 # API 接口管理
│  ├─ assets              # 静态资源文件
│  ├─ components          # 全局组件
│  ├─ config              # 全局配置项
│  ├─ enums               # 项目枚举
│  ├─ hooks               # 常用 Hooks
│  ├─ language            # 语言国际化
│  ├─ layout              # 框架布局
│  ├─ routers             # 路由管理
│  ├─ store               # store
│  ├─ styles              # 全局样式
│  ├─ typings             # 全局 ts 声明
│  ├─ utils               # 工具库
│  ├─ views               # 项目所有页面
│  ├─ App.vue             # 入口页面
│  └─ main.ts             # 入口文件

以下是 Elux 中基于微模块的 SRC 目录,其改进是将“功能模块 ”作为一级分类,“ 文件职能”作为次级分类:

src
├── modules
│      ├──  ModuleA
│      │     ├── entities
│      │     ├── assets
│      │     ├── api
│      │     ├── utils
│      │     ├── language
│      │     ├── components
│      │     ├── views
│      │     ├── model.ts
│      │     └── index.ts
│      │ 
│      ├── ModuleB
│      ├── ModuleC

微模块的台前与幕后

前端开发最终呈现的是 UI 界面,但这只是表象,支撑 UI 界面渲染和交互的是背后一系列 state、model、controller 等幕后英雄,它们根据自己所属不同领域被封装在各个 微模块 中,UI 既然与它们唇齿相依,必然也将跟随它们内聚在一起。

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

View 和 Component

本质上说 View 就是一个 Component,但我们从架构的思维来区分它们:

  • View:业务视图,它用来表现业务规则与逻辑,通常能够较为独立和完整的解决某一领域问题。
  • Component:UI 组件,它用来表现渲染规则与交互逻辑,通常不与具体业务直接相关,可复用在各种不同业务场景中。

所以在“微模块”的架构中,丰富多彩的 UI 界面由一个个单一职责的 View聚合 而成,每个 View 同样依据自身所解决的领域问题而被 分散 在各个微模块中,这里面有几个注意点:

  • 领域性 :View 被归属到不同 微模块 的原则是其解决的问题领域,而不是视觉上的几何空间。View 可以在视觉上被拆装、聚合、嵌套,这并不影响它们所属微模块。
  • 完整性:一个 View 通常能解决一个较为独立和完整的问题,View 与 View 之间是较为松散的关系,如果 2 个 View 之间联系紧密,那就不应当拆分它们。

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

不以视觉延伸和几何空间作为 View 的微模块归属原则 :如下图所示,假设有一个 View 用来展示 用户资料 ,我们将其放在 UserModule 这个微模块中,称其为UserModule.DetailView,但你发现其中又包含一个 该用户发表文章的列表 ,你当然可以把这个列表单独提取出来作为一个新的 View。从视觉上来看,它似乎和用户资料是连在一起的,似乎可以和UserModule.DetailView 放在同一个微模块中;但我们从它解决的问题来看,它属于文章领域,而与用户领域关系并不大,所以我们最好将其放在 ArticleModule 中,称其为ArticleModule.ListView

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

前端“微模块”的实现方案

  1. 定义和创建微模块,可借助于 Eluxjs 框架,当然你发现了其它框架也可以。
  2. 管理微模块,可借助于 NPM 仓库。
  3. 使用微模块,可借助于打包工具:
    • 静态编译:微模块作为一个 NPM 包被安装到工程中,通过打包工具(如 webpack)正常编译打包即可。这种方式的优点是代码产物得到打包工具的各种去重和优化;缺点是当某个模块更新时,需要整体重新打包。
    • 动态注入:利用Module Federation,将微模块作为子应用独立部署,与时下流行的微前端类似。这种方式的优点是某子应用中的微模块更新时,依赖该微模块的其它应用无需重新编译,刷新浏览器即可动态获取最新模块;缺点是没有打包工具的整体编译与优化,代码和资源容易重复加载或冲突。

微模块 - 前端业务模块化探索,拆解巨石应用的又一利器

微模块 vs 微前端

从本意上来说,微模块只是一种工程结构和模块化方案,而 微前端 只是它的一种应用场景之一。微模块架构不仅可以用来构建复杂的单体应用,也可以结合 Module Federation 实现多子应用独立部署的“微前端”。

如果单独就 微模块 + ModuleFederation方式实现的微前端,与传统意义上的 qiankun、icestark 等微前端方案相比,微模块方式 胜在粒度更细、更灵活、更轻巧,而 传统方式 则胜在隔离性更好。

想到一个非常形象的比喻:

IFrame vs 微前端 vs 微模块 可类比于 进程 vs 线程 vs 协程

从左至右:越来越轻量化,隔离性逐渐变弱,灵活性逐渐增加。所以鱼与熊掌不可兼得,具体哪种方案最适合还得看不同的产品需求。

落地与实例

光说不练假把式,下面通过一个简单的实例来说明如何实现以上构想,请看下篇:微模块 - 前端业务模块化探索(中)- 落地与实例

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-23发表,共计4008字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)