在现代前端应用的工程实践中,单页应用SPA(Single Page Application)会为用户提供更极致的体验,加之更具灵活性的前后端分离的架构,已成为主流趋势。与之相对的,传统的单体Web应用(Monolithic Web Application)往往是基于多页面模式的,且前后端代码放在一起,虽然耦合性较强,页面给用户的体验也不够连续,但在产品研发的特定阶段仍具有较强的优势,早期的ASP.NET、Java Spring MVC,以及Ruby on Rails都是单体应用的代表性框架。本文将以FreeWheel从单体应用改造为前后端分离的单页应用的实践为例,着重介绍前端演进期间所遇到的挑战和解决方案。
相较消费者,商业用户对前端应用的需求更具复杂性,且更强调质量。FreeWheel深耕企业级的视频广告领域10年,其基于Ruby on Rails框架为广告主打造的Web管理应用已经历多轮迭代和演进,目前已达到20多个产品模块,1200+页面,代码量已达到143.5万行代码,其中包含39万行基于jQuery的传统JS代码。为保证其质量,其中包含了20.2万行单元测试代码,除此以外,还有独立的近2万个自动化测试脚本。在两年前,我们感受到了单体应用的局限性,并决定将其改造成为前后端分离的架构。
技术选型
FreeWheel前端展现的业务多种多样,但其用户体验强调高效性和高一致性。为辅助业务研发团队进一步提升前端开发的效率和效果,我们在改造前期订立了组件化的目标,力求将统一的用户体验和复杂的内部交互逻辑封装进组件,通过自动化测试保证其质量,并最终在业务模块中广泛复用。
针对以上目标,我们选择React作为新前端核心技术,以ES6作为开发语言,利用Webpack和Babel进行编译打包。以Mocha全家桶加Enzyme作为单元测试框架保证组件质量。每个业务模块均开发、打包并发布为一个独立的SPA,多个模块SPA之间,除了以统一的SSO服务保证用户认证外,并无更多的耦合,这一点保证了多个业务模块团队的工作不会互相制约。
在单向数据流框架选择上,我们基于Facebook的Flux推进了相当长的一段时间。在上线两个业务模块后,我们认识到FreeWheel的业务对前端数据流需求的复杂度远高于常见的TodoMVC样例,Flux实现这些需求时会遇到较多困难。我们评估了当时的社区新秀Redux,它能一定程度缓解我们遇到的问题但仍有局限性。我们最终决定以Redux和ImmutableJS为基础,开发一套新的单向数据流框架Spark-modula。这点在下一节会有详细描述。
类似的还有前端路由。我们初期的选型是React-router,随后根据项目需要开发了新的前端路由框架Spark-router。
更详细的前端框架选型及新旧对比如下:
至于后端,我们的选型是以Golang开发的微服务。借此契机,团队将原来内置于单体应用中的后端服务重新做了一次梳理,并逐步重构成微服务架构中的若干个微服务。前端在通过SSO验证后,以JSON格式与微服务交换数据。这些微服务除了满足前端使用,也会通过Gateway作为API暴露给我们的客户,更会为公司内部的其他微服务提供基础。后端架构不是本文重点,故不赘述,有兴趣的读者请参见FreeWheel发表的其他文章。