共计 4166 个字符,预计需要花费 11 分钟才能阅读完成。
在开始聊之前,我想定义一下架构的概念。大部分小伙伴都会问一个问题:
前端能有啥架构,不就是文件放到哪个文件夹吗?
对,但也不对,所以咱们须要对齐认知:
到底什么是架构?
在开始之前,我心愿你将视线从前端这个点扩大开,站在你正在参加开发的整个零碎来思考这个问题。
而后咱们先来看看一个绝对权威的对 架构的定义 是什么样的:
Architecture is the fundamental organization of a system embodied in its components, their relationships to each other, and to the environment, and the principles guiding its design and evolution.
这是 IEEE1471 对于架构的一个定义,它来自于 IEEE 规范协会 下辖的 IEEE 计算机协会。
从这里的定义来看架构指的是“零碎的根本组织 ”,体现为“ 组成这个零碎的组件以及组件之间的关系 ”,同时还应该蕴含该零碎“ 与环境的关系 ”,最初架构还应该“ 领导零碎的设计和演变”。
好的,那么零碎又是啥?
A system is a collection of components organized to accomplish a specific function or set of functions. The term system encompasses individual applications, systems in the traditional sense, subsystems, systems of systems, product lines, product families, whole enterprises, and other aggregations of interest. A system exists to fulfill one or more missions in its environment.
所以 零碎指的是 “为了实现某个或者一系列性能而组合起来的 组件的汇合”,它能够是“单个利用、传统意义上的零碎、子系统、零碎的零碎、产品线、产品系列”等。
这里的 组件 能够了解成零碎中的组成部分,比方一个零碎中的数据库、一个个拆分好的服务、不同的前端利用等。
而 组件之间的关系 指的是组件之间的交互关系是怎么的,比方前端利用通过 http 申请调用后端服务,后端服务调用数据库实现数据更新。
咱们如同还漏了个 环境:
The environment, or context, determines the setting and circumstances of developmental, operational, political, and other influences upon that system.
能够看到这里的环境并不单纯指开发人员平时所说的“测试环境、生产环境”。它还蕴含了经营环境、政治环境等会对系统造成影响的更为狭义的环境。
总结来看,架构像是一种蓝图,它规定了零碎中都有什么样的组件,组件与组件之间如何交互,当变动呈现时应该如何进行扩大和扭转来进行应答,从而实现对系统的演进。更重要的是它还须要关注组织构造、业务特点和部署环境等环境限度,在受限的状况下进行正当布局。
那么前端架构呢?
到这里咱们就须要将眼光从整个零碎再放回到前端这个利用上来。
因为各个我的项目各个组织的环境不尽相同,没有方法找到一个路径来解决不同环境下的不同问题,所以这篇文章也不会关注零碎的环境,会将重点放在架构形容的前半部分。
接下来我会以 React 为例进行开展,首先是 ng 曾经做的太欠缺了,没必要在官网文档的根底上造轮子,照着文档来就完事了。其次是 Vue 我没咋用过,没啥发言权,最初是 React 以“自在”著称,各种写法形形色色,我想总结一个绝对靠谱的样子进去。
组件
在开始聊组件前我想再次和大家对齐认知 – React 只是一个 UI 库。
A JavaScript library for building user interfaces.
你说它简陋也好,说它扯淡也行;你夸它自在也罢,扁它是撒手掌柜也能够。但这就是事实,它真的就只管用它的规定来渲染 UI。它不论你的路由,不论你的 API,甚至不太想管跨页面(全局)UI state。
那都是你开发者的事,关我 React 什么事?
于是“理所应当”,React 的生态十分“凋敝”。为了能更好地实现你的我的项目,你须要补齐一些组件:
Request Client
这是你与后端服务通信的要害,大多数我的项目在 fetch API 遍及后就开始应用 fetch API 了,当然也有很多人偏差于老牌的 axios,选什么不重要,要害你得有。
更多人开始缓缓地在 Client 外面包一层,我把它叫做 Client Wrapper 它能够帮你更好地治理缓存,晋升开发体验,比方 React Query 和 SWR。
View Model
我其实没有想到更好的名字来命名这个组件,这个组件百分之九十九的状况下是一个 React Hook,它向外裸露 React 组件所须要的所有 callback 和 data,负责解决和持有 UI 所需的 data 和相干计算,同时提供用于反馈用户操作的 callback。
奇怪的点在于这个命名来自于面向对象,然而因为 React 开始全面拥抱函数式,一个函数被用 Model 来命名着实有点奇怪。
Model
这个组件次要用来解决业务逻辑和后端数据转换,相当于对业务的建模,是一个充血模型。它个别被 View Model 调用,用来转换后端数据、内聚相干业务逻辑等等。
它带来的益处是屏蔽后端业务对前端 UI 的影响,只有 Model 放弃接口不变,后端数据变动或者业务产生扭转,在前端 UI 设计不变的状况下能够将变动屏蔽在 Model 内,不必对其它中央进行批改。
它还有可能会解决一些通用的逻辑,比方解决缓存,比方错误处理等等,所以也可能会呈现相似于 Error Model 这样的 Model。
与 View Model 这个货色的命名同理,把一个函数叫做 Model 的确有些奇怪。然而数据加行为这样的组合如同叫 Model 也没啥不妥?
组件关系
在领有这些组件的状况下来看看咱们这个零碎的架构会长成什么样子。
图中箭头代表调用关系,连线代表可能成为这个组件的一些实现。Client Wrapper 画成了虚线是因为可能有的我的项目感觉它是多余的,并不需要,所以是一个可有可无的组件。
当用户操作页面上的元素时,React Component 充当的 View 组件会触发 View Model 中裸露的 callback,callback 会依据具体情况调用 Client 和(或)Model 解决响应逻辑,最初依据不同的状况更新 View Model 中的 data 实现对页面数据的更新。
须要阐明的是图中省略了一些 技术组件,比方全局 state 治理,比方可能波及的事件处理组件等等。他们应该依照职责的不同被归属到不同的组件中,而如果你发现有一些组件没方法进行归属那或者就是你扩大本人架构的时候了。
目录构造
到这里咱们曾经聊了组件和一半组件之间的关系。为什么是一半呢?因为组件之间不仅仅有调用关系,它还应该蕴含在文章结尾提到的:
文件该放到哪个文件夹里
组件应该如何在我的项目中被归类的问题我在这篇文章中曾经聊过一次了,然而既然是“从新思考”架构,理所应当我想对外面的货色做一些改良。
目录划分的思维没有产生扭转,还是 分类 与分层,然而有了不一样的架构之后会有一些扭转。
首先是一些“无关紧要”的目录,比方 assets mocks request context
它们的作用和文件夹一样曾经很表意了,不做过多解释。
components
与上一篇文章不一样的是,我将 ui-components 和 components 合并到了一起。
在实际的过程中发现,一些时候 ui-components 和 components 没有显著的界线,比方外面略微有一些逻辑但又不多的时候放在哪里就会很难堪;再比方团队里大家对于不同组件的认知不一样,分类的时候就会不一样;
最初其实这样拆离开当前并没有多太多的益处,如果仅仅是为了相似于“拆一个公共的 UI 库”会很不便这样的理由保护两个 components 文件夹会减少许多不必要的心理累赘,要思考的问题会城北增长,属实没有必要。
其次合并后的文件夹也能够缩小保护老本,升高管理负担。
model
因为 Model 这个组件在架构中的呈现,我的项目中应该不会再呈现各种各样的 utils 函数了,他们应该被以各种模型的形式内聚到一个个 Model 中。如果某个 Model 变得很简单,阐明你的模型出了些问题,能够思考对其进行拆分下放到一个文件夹中来治理。
pages
这个文件夹没有太多扭转,然而因为 Model 和 View Model 的引入会有些许不同:
最初
咱们从架构的定义开始聊起始终到聊完前端架构中组件与组件之间的关系。有意思的是最初咱们的架构变成了一个简直等于 MVVM 的架构,于是我第一次在我脑子里领会到了架构的演进。
在我四年的一个个我的项目中,我的项目架构缓缓清晰起来:
Class 时代循序渐进拆分文件夹
Functional 时代循序渐进拆分文件夹
为了做 TDD 将逻辑与 UI 以 hooks 的形式拆散
为了解决芜杂的 utils 文件和隔离业务逻辑退出了 Model
最初我查阅了一些对于 Android 我的项目 MVVM 的材料,发现外面存在大量模版代码,也回想起我的项目上 Android 小伙伴吐槽他们所应用的整洁架构和 MVVM 存在大量无用的中间层。
所以集体认为至多在当初我遇到的这些我的项目中这些模版代码属实没有必要,这些组件曾经可能撑持起大多数业务我的项目。
另一方面我也真真切切领会到了思考和多元化的力量。这些演进呈现的契机要么是为了解决难题(比方大家说的前端不好 TDD);要么是我在写了一段时间后端代码同时学习 DDD 的货色退出进来的(建模);要么是 pair 或看书看博客的时候一些间接间接的输出(和组里 TL pair 探讨,看到邱巨匠的博客)。
可能它当初不是最初的起点,但它是我当初能看到的后方。
References
- GUI Architectures
- How To Structure React Projects From Beginner To Advanced
- Tao of React – Software Design, Architecture & Best Practices
- 可保护的 React
本文由 mdnice 多平台公布