编程小思
首发于编程小思
浅谈中等规模单页应用的前端架构实践

浅谈中等规模单页应用的前端架构实践

一个人做项目,自己就是整个团队。—— 鲁迅

过去的两年内实习过两次,参与了公司两个大型项目,但是很遗憾的是由于自己的惰性、能力的不足以及项目规模比较大,没能从整体上深入理解整个应用的架构和 flow。最近几个偶然的机会,在两个偏个人的中等规模项目上都承担了构建整个项目前端的任务,其中一个还是完全自己开发。对比之前造的小轮子和小项目,构建规模较大的项目的时候,更多地会把注意力从技术本身,转移到工程角度上。在这篇文章中我想简单谈一下自己开发过程中的体会。

P.S: 由于这几个项目都是偏向个人项目,所以适用性上来说可能更偏向于个人或者小团队。都是个人的经验和体会,所以求更有经验的朋友来指正建议。

一、技术选型

脚手架

曾记得 16 年初刚学 React 的时候,各个技术都没接触过,在 Windows 电脑上照着 tutorial 配置 webpack,写了一个 Hello World 都用了一下午的时间。然而不得不佩服的是,现在的社区真的是太强大了,各大框架都有了自己的 cli 工具,React 有 create-react-app,Vue 有 vue-cli,以及各种各样的零配置打包工具也在 2017 年大放异彩。这一方面解放了开发者在配置环境上挣扎的烦恼,让初学者更快地上手、接触新技术的核心,但是也给了很多人不去继续深入学习 webpack 的借口,比如我(逃

所以在这个层面上考虑了诸多理由后我都使用了 create-react-app。主要理由有三个:

第一,前期不用自己维护各种配置文件,因为这个阶段重要的是出东西,所以别的事情上别给自己找麻烦。

第二,后期如果想单独定制自己的配置,也不麻烦,eject 或者是 fork 一份自己的 create-react-app 都是可选择项。更方便的是,react-app-rewired 这个项目可以在不 eject 的情况下,更改大部分配置,可以说十分方便安全。在其中一个项目中,由于 CRA 不支持 class decorator,为此 eject 可以说不是很“值”,所以我选择了借助 react-app-rewired 引入 mobx。

第三,社区的强大。一旦一个技术火了,周边各项技术就蜂拥而至,这是很正常的现象。create-react-app 也有了各种自己的 boilerplate,以及第二点中所说的 react-app-rewired,这些都是社区中产生的周边。所以一旦自己的项目遇到了问题,在 Github 或者 StackOverflow 上会有很多开发者的支持和帮助。

路由

开始真正写项目之后,对于一个单页应用,开始就应该考虑路由。目前各大框架都有了自己非常成熟的路由解决方案,配套 React 我们有 React-Router,使用方法也相对比较简单。在这方面更应该关注的是的是项目的约定。

在这里我也有一个问题,到目前为止,我的的做法是把所有的 <Route /> 都放到最外层的 Container 里,但是一旦项目规模持续增加的话,可想而知 Route 的数量也会相应增加,导致最外层的组件产生了很多冗余代码,维护起来也很困难。前提是想保持单页应用的情况下,不知道这种场景应该怎么解决?

状态管理

前端的状态管理一直是一个火热的话题。

但是在这方面我的第一个问题是:“你真的需要一个单独解决状态管理的方案吗?”

在几个月前,我写了 Eat More Veggie 这个项目,我试着不用任何工具,单凭自己写的一个 DataStore Class 配合 React 的 local state 完成所有的状态管理,自己实现了一个类似 trigger callback 的机制。实际效果非常棒,代码十分清爽,解耦程度高,可读性强。之前在 Twitter 上看到 tj 的一条推,他也说自己最好的状态管理工具就是 {},一个 JavaScript 的对象,别无其他。

所以,什么情况下开始考虑单独解决状态管理,引入别的工具呢?

我自己的答案是:当组件之间通信过于复杂,仅靠单向数据流不能满足需求,反而会降低可读性的时候。

在这种情况下,再来考虑各种解决方案。

在 React 的进化过程中先后出现了 Flux,Redux 等等解决方案。在使用 Redux 写了大量的代码之后,我还是说不出来我真的喜欢使用这个库。我非常喜欢它的设计哲学和源码的简洁,但是我真的不喜欢用它。最主要的原因是它的 boilerplate 太多了,强行把 data flow 变复杂了;另一方面是因为它并没有解决一些核心的问题,比如说异步。很多问题都要再引入注入 redux-saga, redux-thunk 之类的中间件,无疑增加了学习成本。

虽然使用 Redux 的经验比较多,但是最后还是选择了 MobX。最主要的原因是代码简洁,boilerplate 少。这一点带给我的另一个好处是,如果将来一旦决定不用 MobX ,而选择其他的解决方案,重构起来难度相对来说也小。

组件库

单人开发要想做出一个美观、一致性高,且规模比较大的项目的时候,组件库是必须的。很多公司都有自己的组件库,大公司更是无一例外。在这一点上,还是很感谢很多公司以及个人的开源组件,我在这两个项目中分别用了 Material-UI 和 antd。

怎样判断一个组件库是否值得尝试?首先 bottom line 是你觉得它的基本设计风格是否满足你的需求。然后要继续考虑它文档是否完备;定制程度怎么样;有没有一个相对较多的使用人数作为基础;在社区内是否活跃,等等。

二、没有银弹

回想早在两三年前最初学前端的时候,正值新旧技术交替。现在各个技术又处在一个平静期。技术层面上来说,之所以出现新旧更替,无非是在优劣对比上的量变引起了质变。然而即使在日新月异的前端,“没有银弹”这句老话也同样适用。没有一个技术可以解决所有的问题,甚至解决某个场景的所有问题都很困难。

网络上有很多从技术层面上对比各种框架工具的文章,在这不过多赘述。颇有感悟的一点是,衡量一个技术靠不靠谱,这个标准越来越脱离了技术本身,而是要结合业务场景、社区支持等等因素。

从架构这个角度而言,”没有银弹“这句话也告诉我们不要试图揣测”用一套方案解决所有问题“。我曾经听一个人说”前端 React + Redux,然后有个组件库,不就为所欲为了吗?“。说实话我对这样的说法感到嗤之以鼻,对技术丝毫没有敬畏之心不说,能说出这句话来,对他究竟有没有写过前端都产生怀疑。

三、平衡学习导向和开发效率导向

业务代码很多人都不喜欢写。一个很重要的原因,就是熟悉了业务流程之后,机械操作慢慢占据了大部分代码。慢慢的,就剩下了写写增删查改这种操作,由此诞生了 CRUD 后端程序员这种说法。这种现象在各个公司很普遍,某种程度上,我感觉公司就是希望你往这个方向发展,毕竟业务熟练之后,开发效率也随之提高。但是这对个人技能有没有帮助呢?有。毕竟 coding 某种程度上就是熟练度。

但是少了新技术、新场景的刺激,也少了很多乐趣。

自己从头写项目的优势之一,就是可以根据自己的技术水平和需求选择自己喜欢的路线。以开发效率作为导向的话,可以偏向选择自己熟悉的技术栈;在这其中可以掺杂使用一些新技术,作为学习的需要。根据需求,掌握平衡很关键。


四、罗马不是一天建成的

罗马不是一天建成的。对于一个项目而言也是如此。最初经历的技术选型和具体架构很可能并不成熟,在未来的开发过程中不断引进新的,抛弃旧的。这也是软件工程中不可避免的一个现象。很多公司都有”技术债“,也是由于这个原因。所以得到的启示是不要不敢动刀,甚至要在可以看到可预测未来的情况下,提前动刀,来减少未来不必要的麻烦,提前止损。


以上。


推荐阅读

《黑客与画家》

《重构——改善既有代码的设计》

文章被以下专栏收录