We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
好的书本分章节、好的代码分模块,那么好的架构该如何定义呢?
咳咳,不要意思,题目起大了~~ 小生之辈,岂敢以架构而论。
不过话说来,很多人都认为前端无非就是 HTML+CSS+JS,一个目录一类文件,有何架构可言。但是我想说。。。。你说的都对!
HTML
CSS
JS
但是,笔者一直在探索不同的页面架构组织形式,鄙人愚见,好的架构,能够方便拓展和开发以及后期的项目维护。
在笔者刚开始接触前端的时候,就一直在思考怎么样的架构比较舒服易于扩展,且能装 B。React-Full-Dianping-Demo里面就有写到对于react+react-redux+soga的一些列代码组织的思考:react技术栈项目结构探究
react
react-redux
soga
一直还在学习,本文也只是拿来探讨下本次我开发一个页面时,我个人的一些代码组织方式。抛个砖~
望各位大佬不啬赐教。
src ├─ action-log │ ├─ constants.ts │ └─ index.ts ├─ app.js ├─ app.json ├─ common │ ├─ animation-utils.ts │ ├─ business-utils.ts │ ├─ constants.ts │ ├─ detail-utils.ts │ ├─ mtop-utils.ts │ ├─ net-utils.ts │ ├─ price-utils.ts │ ├─ storage-utils.ts │ ├─ string-utils.ts │ ├─ time-utils.ts │ ├─ type.ts │ ├─ url-utils.ts │ └─ utils.ts ├─ components │ ├─ loading-page │ │ ├─ index.css │ │ └─ index.tsx │ └─ pm-bottom │ ├─ index.css │ └─ index.tsx ├─ document │ └─ index.jsx ├─ event │ └─ EVENTS.ts ├─ modules │ ├─ bottom-action │ │ ├─ index.css │ │ └─ index.tsx │ └─ page-container │ ├─ base │ ├─ decorator │ ├─ index.tsx │ └─ libs └─ pages ├─ buyer-identity │ ├─ components │ ├─ constants │ ├─ customized-hooks │ ├─ index.tsx │ ├─ types │ └─ utils
或许上面看起来并不是很直观,截图解释下
大概的看下,脑海中有个大概的位置和每个文件的作用。下面我们再来细品
其实划分了这么多的目录,无非就是为了最大可能的复用。其中也包括对于组件状态的抽离、hooks 特性的利用。
毕竟是MPA应用,所以一切还都是围绕着 pages 展开。
MPA
pages
首先这里的action-log目录就不多说了,因为没有太多可借鉴性。大概就是返回一个 ActionLog对象,来进行一些业务上的埋点、信息收集等逻辑的处理。所以这里如果大家有一些公共的基础类封装,都是可以放这里的。
action-log
ActionLog
common ├─ animation-utils.ts ├─ business-utils.ts ├─ constants.ts ├─ detail-utils.ts ├─ mtop-utils.ts ├─ net-utils.ts ├─ price-utils.ts ├─ storage-utils.ts ├─ string-utils.ts ├─ time-utils.ts ├─ type.ts ├─ url-utils.ts └─ utils.ts
由于该项目的比较复杂,业务逻辑相对较多。所以这里我将 utils按照类别,区分出来了以上几种。方面后期开发中的维护和扩展,也便于查找。
utils
除了一些从命名可以区分出来的utils 以外,这里还放了一个 type.ts和constants.ts,用途自如其名。
type.ts
constants.ts
相信框架使用者对于 components 的命名都不为陌生.是的,就是对于一些公共组件的封装,比如我这里放的两个组件loading-page,pm-bottom等公共组件。components 相对来说是比较“小”的概念,划分依据这这个项目中也比较简单,就是是否为“木偶组件”(虽然 hooks 了以后,咱不太适合这么说),
components
loading-page
pm-bottom
modules ├─ bottom-action │ ├─ index.css │ └─ index.tsx └─ page-container ├─ base │ ├─ base.tsx │ ├─ error.tsx │ └─ scrollBase.tsx ├─ decorator │ └─ withError.tsx ├─ index.tsx └─ libs ├─ displayName.ts ├─ navbarTransparent.ts ├─ spm.ts └─ title.ts
更具有模块的概念,这里最典型的page-contaienr的模块,作用就是每一个页面的通用底层容器,早在之前的文章中其实有介绍到这个容器,如何用 Decorator 装饰你的 Typescript,所以这里就不再赘述了,其实就是一些基础功能的封装。所以也就是解释了event的目录存在。
page-contaienr
event
而这里modules和conponents最大的区别就是,复杂度和内部状态管理。如果内部状态较为复杂,且有很多的交互,那么我们就称之为 module.是的,这里的界限,我们划分较为模糊。
modules
conponents
module
但是当你拿到一份设计稿的时候,估计就能明白我的良苦用心了~
红色框就可以理解为 module,绿色框可以理解为 components
针对单个页面里面的组织,其实都大同小异。(突然发现前端架构没有太多可言)
目录区分的并不是很多,但是也都较为清晰。简单介绍下每个区域的分工,需要展开的,我们在后续展开介绍
index.tsx
format
customized-hooks
hooks
constants
api
spm
以上就是一些目录结构和代码组织的交代。其实还是比较简单清晰的。下面介绍下
碎碎叨叨道不到个明明白白
因为是业务代码,所以这里就不会粘贴太多代码了
简单的解释下上面的流程
初始化 UI 的逻辑比较偏于业务,其实没有太多可借鉴的。这里我代码里面的工作也就是适配 iPhone X的一些UI。
iPhone X
重点说下初始化接口数据的过程吧。其实也就是各个页面中的 components 的状态初始化
首先我们需要定义每一个模块的 props,毕竟是因为用的 ts,注释即文档。所以我们将每一个 components 的 props 都定义到 type 目录中,毕竟很多时候接口返回的数据,需要我们做一次 format,而这个 format 的目的就是为了 components 更好的使用。换句话说,这些接口,可复用! 那必然定义到外面
props
ts
type
注意接口上都要写注释啊!!!!理由如下:
将所有数据处理的方法,全部放到 utils 中(注意数据兜底的处理,这里我所有的数据处理都写好工具函数,并添加充分的单元测试)
真正的做到对 components 而言,开箱即用。
因为有 type 的定义和 components 之间的约束,所以无论是componemts 内部的数据使用还是 index.tsx 里面的模块引入时 props 的注入,都有很好的约束
componemts
编写时候的提醒
漏写时候的报错
由于我们使用了 hooks,且相对隔离的组件划分,原则上,组件通信其实并不是很多。当然,也必然是有的。
其实这方面的约束主要归结于业务的复杂度,如果数据逻辑比较复杂,且通信较多。那么可以考虑使用 useContext 和 useReducer
useContext
useReducer
说下这次需求中涉及到的通信。
原则:组件尽可能值管理自己的状态。
遵循如上原则,最终的业务交互逻辑都是由组件内部管理,涉及到的同级通信则通过父组件操作。而父组件操作的原则就是只拿数据,不做任何业务处理。(尽可能的撇清关系)
index
component
bundle
interface
以上约束后期应该都会编写相应的 Eslint 来进行强约束(咳咳,程序猿基本素养不可靠)
Eslint
最后看下我正在补充的单元测试,编写单元测试过程中,的确发现了不少工具函数的边缘情况处理的有问题
按照如上的 page 代码组织后面又写了一个页面,感觉代码的组织和状态的管理还是较为清晰的。后续会编写相应的 cli 来自动生成页面基础架构,比如 pmCli add page or pmCli add com
page
pmCli add page
pmCli add com
因为本文不方便粘贴太多代码,所以可能说的有些云里雾里,有任何疑问,欢迎公众号内回复【1】,加入全栈技术交流③群,一起交流
最后,本文只做一个抛转,并非定义一种规范。更多的约束和组织,希望大家多多交流,互相学习。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
咳咳,不要意思,题目起大了~~ 小生之辈,岂敢以架构而论。
不过话说来,很多人都认为前端无非就是
HTML
+CSS
+JS
,一个目录一类文件,有何架构可言。但是我想说。。。。你说的都对!但是,笔者一直在探索不同的页面架构组织形式,鄙人愚见,好的架构,能够方便拓展和开发以及后期的项目维护。
在笔者刚开始接触前端的时候,就一直在思考怎么样的架构比较舒服易于扩展,且能装 B。React-Full-Dianping-Demo里面就有写到对于
react
+react-redux
+soga
的一些列代码组织的思考:react技术栈项目结构探究一直还在学习,本文也只是拿来探讨下本次我开发一个页面时,我个人的一些代码组织方式。抛个砖~
望各位大佬不啬赐教。
项目架构
或许上面看起来并不是很直观,截图解释下
大概的看下,脑海中有个大概的位置和每个文件的作用。下面我们再来细品
目录职责
其实划分了这么多的目录,无非就是为了最大可能的复用。其中也包括对于组件状态的抽离、hooks 特性的利用。
pages 层以外的公共逻辑
毕竟是
MPA
应用,所以一切还都是围绕着pages
展开。action-log
首先这里的
action-log
目录就不多说了,因为没有太多可借鉴性。大概就是返回一个ActionLog
对象,来进行一些业务上的埋点、信息收集等逻辑的处理。所以这里如果大家有一些公共的基础类封装,都是可以放这里的。common
由于该项目的比较复杂,业务逻辑相对较多。所以这里我将
utils
按照类别,区分出来了以上几种。方面后期开发中的维护和扩展,也便于查找。除了一些从命名可以区分出来的
utils
以外,这里还放了一个type.ts
和constants.ts
,用途自如其名。components
相信框架使用者对于
components
的命名都不为陌生.是的,就是对于一些公共组件的封装,比如我这里放的两个组件loading-page
,pm-bottom
等公共组件。components 相对来说是比较“小”的概念,划分依据这这个项目中也比较简单,就是是否为“木偶组件”(虽然 hooks 了以后,咱不太适合这么说),modules
更具有模块的概念,这里最典型的
page-contaienr
的模块,作用就是每一个页面的通用底层容器,早在之前的文章中其实有介绍到这个容器,如何用 Decorator 装饰你的 Typescript,所以这里就不再赘述了,其实就是一些基础功能的封装。所以也就是解释了event
的目录存在。而这里
modules
和conponents
最大的区别就是,复杂度和内部状态管理。如果内部状态较为复杂,且有很多的交互,那么我们就称之为module
.是的,这里的界限,我们划分较为模糊。但是当你拿到一份设计稿的时候,估计就能明白我的良苦用心了~
page 的组织
针对单个页面里面的组织,其实都大同小异。(突然发现前端架构没有太多可言)
目录区分的并不是很多,但是也都较为清晰。简单介绍下每个区域的分工,需要展开的,我们在后续展开介绍
index.tsx
页面的入口文件,但是本身里面不会编写太多业务逻辑utils
该页面的工具函数,包括接口的请求、数据的format
等customized-hooks
自定义hooks
,这里有两个,初始化 UI 所需要的数据(边距等),业务请求的数据。constants
页面的常量,包括请求的api
、spm
埋点、固定的一些该页面业务数据等components
该页面的组件(注意这里没有 module,因为太多了真的容易混乱),页面的components
,有简单的,也有复杂的。以上就是一些目录结构和代码组织的交代。其实还是比较简单清晰的。下面介绍下
页面数据流向和管理规则
因为是业务代码,所以这里就不会粘贴太多代码了
简单的解释下上面的流程
初始化 UI 的逻辑比较偏于业务,其实没有太多可借鉴的。这里我代码里面的工作也就是适配
iPhone X
的一些UI。重点说下初始化接口数据的过程吧。其实也就是各个页面中的
components
的状态初始化interface
首先我们需要定义每一个模块的
props
,毕竟是因为用的ts
,注释即文档。所以我们将每一个components
的props
都定义到type
目录中,毕竟很多时候接口返回的数据,需要我们做一次format
,而这个format
的目的就是为了components
更好的使用。换句话说,这些接口,可复用! 那必然定义到外面注意接口上都要写注释啊!!!!理由如下:
将所有数据处理的方法,全部放到
utils
中(注意数据兜底的处理,这里我所有的数据处理都写好工具函数,并添加充分的单元测试)真正的做到对
components
而言,开箱即用。因为有
type
的定义和components
之间的约束,所以无论是componemts
内部的数据使用还是index.tsx
里面的模块引入时props
的注入,都有很好的约束组件通信
由于我们使用了
hooks
,且相对隔离的组件划分,原则上,组件通信其实并不是很多。当然,也必然是有的。其实这方面的约束主要归结于业务的复杂度,如果数据逻辑比较复杂,且通信较多。那么可以考虑使用
useContext
和useReducer
说下这次需求中涉及到的通信。
原则:组件尽可能值管理自己的状态。
遵循如上原则,最终的业务交互逻辑都是由组件内部管理,涉及到的同级通信则通过父组件操作。而父组件操作的原则就是只拿数据,不做任何业务处理。(尽可能的撇清关系)
约束
index
尽可能不写业务逻辑hooks
component
过于复杂需额外抽离component
、utils
和customized-hooks
等。参照上文component
的props
需抽离复用utils
方法编写充分的单元测试utils
的方法导出需单独导出(bundle
大小),且编写注释(调用时候的提醒)interface
,并且编写注释.毕竟注释即文档以上约束后期应该都会编写相应的
Eslint
来进行强约束(咳咳,程序猿基本素养不可靠)最后看下我正在补充的单元测试,编写单元测试过程中,的确发现了不少工具函数的边缘情况处理的有问题
结束语
按照如上的
page
代码组织后面又写了一个页面,感觉代码的组织和状态的管理还是较为清晰的。后续会编写相应的 cli 来自动生成页面基础架构,比如pmCli add page
orpmCli add com
因为本文不方便粘贴太多代码,所以可能说的有些云里雾里,有任何疑问,欢迎公众号内回复【1】,加入全栈技术交流③群,一起交流
最后,本文只做一个抛转,并非定义一种规范。更多的约束和组织,希望大家多多交流,互相学习。
The text was updated successfully, but these errors were encountered: