共计 2005 个字符,预计需要花费 6 分钟才能阅读完成。
关于前端模块化
- 说到前端模块化,你马上想到的可能就是 cmd、amd、umd 等前端模块化标准,这些是属于
文件级别的模块化
; - 或者你会想到 component 的封装、npm 包的封装等等,这些属于
组件级别的模块化
; - 或者你会想到将页面切割成很多独立的区块,每个区块是一个模块,这些属于
视图级别的模块化
; - 而今天要探讨的是的
业务功能级别前端模块化
。
业务功能级别前端模块化在后台开发人员眼中再熟悉不过了,我们通常说的 ” 用户模块 ”,” 订单模块 ”,” 评论模块 ” 等都是从业务功能视角来划分的。随着前端承载的功能越来越厚重,现在已经不只是简单渲染一个视图而已,它往往也包含很多的业务逻辑和状态,所以越来越多的前端工程中也出现了 model、controller、states 等概念,如果前端模块化仅仅停留在文件、组件级别,那么整个工程将变得难以维护和拓展。
业务模块应当是高内聚、低耦合的整体封装
看了很多时下流行的前端工程结构,往往是这样:
├── src
│ ├── assets
│ ├── components
│ ├── layouts
│ ├── models //vuex 或者 dva,按业务功能划分模块
│ │ ├── user
│ │ ├── order
│ │ └── comment
│ ├── pages
│ ├── services
│ ├── utils
可以看到,在 models(store)这个领域,还是有按照业务功能划分了模块,但是 … 也仅限于 models 而已,脱离 view,单纯一个 model 模块有什么意义?这样的模块化完整吗?能独立开发吗?能灵活插拔吗?能横向扩展吗?
一个完整的模块应当包含:
- 一个 model 处理抽象逻辑和状态
- 一组相关的 views,用来展示 model。注意:model 和 view 是一对多的关系
- 一些其它 components 和辅助资源
它们应当集中归类到一个目录下面,而不是零碎的分散在各个角落,独立开发的时候我只需要拥有这个目录的修改权限而不是整个工程,插拔模块的时候只需要 copy 或 del 这个目录,而不是翻出各个目录去查找相关文件 …
所以我期望的工程结构应当是这样:
├── src
│ ├── assets // 公用资源
│ ├── components // 公用组件
│ ├── utils // 公用工具
│ ├── modules // 多个独立的业务模块
│ │ │
│ │ ├── user // 用户模块
│ │ │ ├── assets // 私用资源
│ │ │ ├── components // 私用组件
│ │ │ ├── utils // 私用工具
│ │ │ ├── model //model
│ │ │ └── views // 一个或多个视图
│ │ │ ├── page1
│ │ │ ├── page2
│ │ │ ├── list
│ │ │ ├── editor
│ │ │ └── layout
│ │ │
│ │ ├── order // 订单模块
│ │ │ ├── assets // 私用资源
│ │ │ ├── components // 私用组件
│ │ │ ├── utils // 私用工具
│ │ │ ├── model //model
│ │ │ └── views // 一个或多个视图
│ │ │ ├── page1
│ │ │ ├── page2
│ │ │ ├── list
│ │ │ ├── editor
│ │ │ └── layout
│ │ │
│ │ ├── comment // 评论模块
│ │ │ ├── ...
可以看到每个 module 都有一套独立的目录结构,各种资源都被区分为 公用资源
和 模块私有资源
,所有模块仅依赖公用资源,模块与模块之间切割得十分干净了。
视图的模块化
把 page(view)也归类到不同到模块,你可能会问:如果一个 view 里面包含了多个模块到内容,那这个 view 应当属于哪个模块呢?这种情况下,我们需要对该 view 进行切割,让其变成多个功能更单一的子 view,view 是可以嵌套的不是吗?
按需组合与加载
当某客户希望购买一个 ” 文章模块“,当然是围绕文章模块相关的代码和资源一并打包给他,单独给他一个 view 或者 model 是毫无意义的,那样也跑不起来。
按需加载也是一样:按需加载的应当是整个模块,而不是传统意义上的懒加载某个 component
所以,工程化打包的时候,应当把整个模块文件夹下所有代码打包成一个独立的 bundle,包括 views、model、components 和其它辅助代码。
注意对外封装
模块是按照“高内聚、低耦合”的原则划分的,模块与模块之间是松散的,大量的方法和接口应当封装在模块内部,仅按需对外暴露和导出。如果 2 个模块之间联系特别紧密,那是否要考虑一下它们是不是要合并成一个模块
关于微前端
从几何时前端也开始思考和借鉴后端“微服务”的概念,希望能找到一种方案让复杂的前端业务也能应用自治,但是目前来说这是一种美好的想法,具体怎么落地尚没有成熟案例,而尽可能的内聚、隔离模块之间的关系倒是理念共识。
我的解决方案
上面只是思考与思路,实现这个思路当然有各种具体的方案,比如我原创的:medux 系列框架,欢迎探讨:
- 欢迎试用跨平台前端框架 @medux
- 结合案例:medux-react-admin