一个鲜为人知的事实是,优步开发了很多基于网络的应用程序,实际上有数百个,而且还在不断增加。其中许多是用于管理业务各个方面的内部应用程序,而其他的则是面向公众的。
一个更广为人知的事实是,web技术变化迅速,最佳实践也在不断发展。为数百名web工程师提供具有现代功能的高质量框架,同时跟上web平台的动态特性一直是一个挑战。
为了应对这一挑战,优步的网络平台团队建立了Fusion.js,一个开源Web框架,使Web开发更容易,并产生轻量级,高性能的应用程序。
动机
随着Web行业的最佳实践,优步需要将其老化的单片网框架改造为解决这些持续技术债务的挑战所带来的挑战。但是,我们还希望让工程师继续使用他们喜欢的技术(例如,反应和redux),同时保持与优步应用健康监测基础架构的兼容性。
具体而言,我们希望核心框架解决以下痛苦点:
- 服务器端渲染,代码分割和热模块重新加载所需的复杂配置和所需的多种工具的样板
- 实现和共享功能缺乏良好的抽象,涉及服务器呈现的React应用程序的不同方面的功能(即,跨越服务器和客户端,处理序列化/水合,服务器 - 客户端通信等)
- 由于位于不同位置的代码的紧密耦合而导致的脆性
- 测试副作用和单身的困难
- 整体框架缺乏灵活性
虽然现有解决方案涉及一些这些挑战,但我们发现在框架之上粘合一个库通常需要更改多个不相关的文件。例如,在服务器可译款应用中支持Redux涉及在与服务器相关文件中的某处添加设置代码,在浏览器中的某处类似代码,HTML模板的水合作代码,反应提供者组件等集成i18n库或浏览器性能指标库导致相同的问题。
To make matters more difficult, a lot of application-specific code can depend on libraries that manage side effects (e.g., for logging or data persistence), and it can be difficult for an engineer to integrate such a library in a testable way without the help of a service layer abstraction.
虽然我们想要提供易于设置的,与优步团队使用的各种图书馆进行易于设置的战斗集成,但我们也希望避免单片框架,以便保持束尺寸小。
我们更喜欢模块化方法而不是现有的整体方法的另一个原因是,它迫使我们明确依赖关系,这使我们更容易避免常见的技术债务来源,例如上帝的对象,ad-hoc内部接口,以及紧密耦合。
Fusion.js是我们努力的顶峰。
谁应该使用fusion.js?
Fusion.js是寻找开源样板的一个不错的选择,以建立一个现代,非琐碎的Web应用程序。
简而言之,Fusion.js是一个mit授权的JavaScript框架,它支持像React和Redux这样的流行库,并具有像热模块重新加载、数据感知的服务器端渲染和bundle拆分支持这样的现代特性。
除了预先配置、优化的样板文件的明显优点之外,Fusion.js还提供了一个灵活的基于插件的架构。这使得它非常适合现代的单页应用程序和web应用程序,这些应用程序依赖于复杂的服务层来满足质量需求,如可观察性(例如跟踪日志、度量仪表板等)、彻底的测试(例如单元/集成/端到端的测试)和国际化。
有关Fusion.js的好处,请查看我们的文档.
基于插件的架构
Fusion.js应用程序普遍的,这意味着应用程序具有单个入口点文件,可以在服务器和浏览器上重用代码。在Universal应用程序中,React组件还可以在服务器上获取数据并渲染HTML,从而通过利用浏览器的本机HTML解析器来改善浏览器上的页面加载时间并避免JavaScript DOM API的开销。
单入口点架构也使Fusion.js插件本身具有通用性,它允许插件开发人员基于代码所属的库(而不是代码运行的环境)共同定位代码片段。
插件通过中间字可访问HTTP请求生命周期,也可以访问React树以添加提供程序组件。它们还可以初始化浏览器代码。
最终,这些品质使得可以使用单行代码安装库,而不管库需要多少不同的集成点。由于插件很容易添加和删除,因此它也很容易理解它们的耦合,对捆绑尺寸的影响以及重构时的其他代码质量属性。它们还可以初始化浏览器代码。
类型的依赖注入
插件利用依赖项注入,这意味着它们可以将定义的API暴露为其他插件的服务,并且可以在测试期间轻松嘲笑插件的依赖关系。当依赖关系负责与数据存储基础设施或其涉及可观察性时(例如,日志记录,分析和指标)时,这尤其重要。
也可以通过Flow.js静态地确保静态类型稳定性,如下所示:
中间件管理
多年前一个明显的挑战是流行的HTTP服务器库表达有一个API,它鼓励急切的副作用,这使得复杂的响应转换难以封装和测试。对于我们以前的体系结构,应用程序开发人员经常需要对Express请求/响应对象进行临时的monkey-patch,并小心地将不相关的关注点放在一起,这种方式只在需要按预期工作的顺序调用函数时才有意义。自然地,考虑到副作用丰富的子系统的高耦合时间需求,测试变得极其困难。
这个问题从Fusion.js的设计阶段就开始被关注。经过大量研究,我们选择雷竞技是骗人的了采用koa.,它提供了一个更单位测试的基于上下文的API,以及基于下游和上游概念的请求生命周期管理的优雅和轻量级抽象。
事实证明,KOA采用的设计决策补充了Fusion.js中的设计决策。
KOA中间件为React Provider组件提供逻辑集成点,下游/上游抽象与React Server呈现的上下文的生命周期完美地对齐。网络副作用与应用逻辑分离,提高可测试性。
困扰我们老应用的上帝对象和操作顺序问题现在已经通过Fusion.js依赖注入和图形解析机制解决了。
可测试性
在过去的几年中,JavaScript生态系统中出现了大量高质量的测试工具,人们对测试技术的认识也有所提高。
除了支持现代的测试工具,如开玩笑,酶, 和傀儡师,Fusion.js还为开发人员提供了测试插件的工具。这Fusion-Test-utils包允许嘲笑服务器本身,使得可以在任何插件和模型的任何排列之间快速运行集成测试。
只是一开始
在优步内,由于内部版本,使用Fusion.js已经存在超过60多个存储库。由于新的Web项目和旧项目自动迁移到Fusion.js,我们预计此号码将迅速增加。鉴于此需求,框架级别的改进应显着提高这些项目的软件质量基准。
我们的路线图包括添加更多的性能优化和面向测试的工具,以及更好的Flow支持。
如果您有兴趣使用Fusion.js和/或想要贡献,请查看文档和我们的Github组织.如果您有意见或问题,您也可以联系我们松弛.
订阅我们的新闻以跟上优步工程的最新创新。






