React全家桶:石墨文档大前端技术选型分享

技术文章 来源:前端之巅 发布:2017-08-09 浏览:1034

摘要:技术选型是个很大的话题。对于创业公司而言,为了适应业务节奏,「灵活」与「高开发效率」是技术选型最看重的两点。石墨文档前端团队既包括桌面和移动端的 Web 版前端工程师,也包括 iOS 和 Android 的 App 的开发者。下面分几块来介绍石墨文档前端团队目前使用的技术栈。

技术选型是个很大的话题。对于创业公司而言,为了适应业务节奏,「灵活」与「高开发效率」是技术选型最看重的两点。而这两点也是这些年前端技术井喷时期新出现的技术最注重解决的两个问题。然而石墨文档作为一款拥有众多企业用户的富前端应用,复杂的表格、文档以及离线同步逻辑使得我们对于前端技术栈的工程化和稳定性有很高的要求,考虑到过于新的技术往往生态尚不完善以及相关的「最佳实践」缺乏验证,我们对于这些技术的选择相对谨慎。石墨文档前端团队的所有技术选型也都是围绕如上两点考虑的。

技术栈的选择

石墨文档前端团队既包括桌面和移动端的 Web 版前端工程师,也包括 iOS 和 Android 的 App 的开发者。下面分几块来介绍石墨文档前端团队目前使用的技术栈。

网站:React

石墨文档是一个支持多人实时协作的在线办公平台,用户可以在上面写作、制表、实时分享和讨论。如图一所示,整个网页版相对而言业务专一但却非常复杂。石墨文档网页版在 2015 年前是一个基于 jQuery 构建的非单页应用,用户的每一次点击都需要重新加载整个页面,体验非常不好。而且 jQuery 这样的类库抽象层次比较低,复杂度随着代码量增加呈指数式上升,不适合构建大型项目,所以我们决定引入一个框架来解决这些问题。

图一 石墨文档的桌面目前是一个单页应用

 三国鼎立的框架版图

在当时 JavaScript 前端框架呈现出了三国鼎立的态势:Angular, React 和 Vue 虽然各自发展的态势不同,但是却都牢牢占据着主流地位。所以我们希望从这三个框架中选择出未来石墨文档网页版前端技术栈的核心,使得在提高开发效率和降低维护成本的同时,也能够保证新的技术栈在未来一段时间相对流行和易于招聘优秀人才。

Angular 在这三个当中应用得最为广泛,团队中也有几个人有过 Angular 开发经验。但经过仔细分析,Angular 1 已经能嗅出一点衰落的味道了,而且 Angular 2 的前景尚不明朗。相比而言,处在上升期的 Vue 虽然表现出了不错的潜力,但在那时生态仍然显得不够成熟,选择其作为网页版的核心框架非常冒险。所以既具有不错的潜力,社区也相对活跃的 React 成为了我们最后的选择。另外当时 React Native 已经发布,相关的生态圈也在飞速发展逐渐繁荣,这成为选型天平上倾向 React 的一个不算轻的砝码。

 React 带来的变化

相对于 Angular 和 Vue 而言,React 对于 JavaScript 工程师的水平要求更高一些。尤其是在大型项目中,对 React 不熟悉的情况下很容易写出难以维护或性能低下的代码。我们在迁移到 React 的初期,由于团队只有少数几个人接触过这个框架,所以经历了一段时间的「阵痛」,例如对于 shouldComponentUpdate 的错误使用使得一些错误变得不易追踪调试。不过随着大家的不断实践,React 逐渐给项目的开发带来了非常积极的影响。开发新功能的效率得到了显著的提高,同时凭借组件化,团队之间的分工更加明确,代码也更加利于维护。

移动端:React Native

在 2015 年团队决定全面转向 React 时,恰巧 React Native 刚刚发布。虽然 React Native 并不是我们选择使用 React 的最终原因,但是其也为之后移动端的技术选型和石墨文档前端团队的构建思路埋下了一个伏笔。

 从原生到 React Native

2016 年,我们的 iOS 和 Android App 均是使用原生语言(Swift 和 Java)开发的,随着用户量的逐渐增多,用户对 App 的功能需求也越来越多,其中之一就是离线支持。离线支持对于石墨文档的场景来说是一个非常复杂的功能,需要处理离线时多层级文件结构的移动、创建、删除以及权限的同步问题。讨论技术方案时发现如果在每个平台(包括我们的网站)重新实现一遍的话成本非常高。

当时我们正好在做移动端 App 的新版产品设计,涉及到的产品改动很多,恰好此时后端也在进行数据接口化的重构,同样依赖移动端不少的改动。于是我们想到了趁此机会使用 React Native 对现有 App 进行重建的方案并立即开始了调研。调研的结果非常乐观,虽然当时很多人声称 React Native 有很多坑,但是我们也看到了一些激动人心的成功案例。考虑到当时整个前端团队的技术积累都在 React 栈中,而且我们的移动端 App 开发工程师也有不错的前端基础,所以最终决定将移动端彻底转向 React Native。

 React Native 的是与非

目前使用 React Native 开发的石墨文档 iOS 版已经上线三个月了,而相应的 Android 版也已经发布了一个月。在这段不算长的时间中,我们收到了非常多来自用户的积极反馈。作为石墨文档的重度用户,我们自己平时写技术文档、阅读和评论产品需求时经常会用到石墨文档移动端 App,实际体验而言使用 React Native 开发的版本在流畅度方面并不弱于之前的原生 App,至少正常使用的情况下性能差异并不会让用户察觉到。

图二 引入 React Native 后的 iOS 和 Android 平台实现了代码复用

对于 React Native 的坑,由于之前技术调研时听得太多,实际开发起来反而比预想中的顺利。总结下来主要存在两个问题:一个是性能问题。举例来说,导航部分之前我们用的是 NavigationExperimental,在最近的一次重构中,我们 fork 了 react-navigation 在原有功能的基础上加了一些拓展,以适应我们较为复杂的导航需求。重构之后在大多数机型里表现得很流畅,但是在一些低端安卓机上性能和原生组件相比还是存在不易被忽略的差异。这个组件目前已经开源在我们的 GitHub 上:

https://github.com/shimohq/shimo-navigation

我们遇到的另一个性能问题是列表组件引起的,官方提供的 ListView 和 FlatList 在大数据量的情况下(如图二中桌面上的文件列表条目有时会比较多)容易成为性能瓶颈。为此现在的文件列表是使用原生代码开发的,后面我们马上会做一个通用的原生端模板式渲染组件来对列表进行渲染。不过总体来说 React Native 的性能还是令人满意的,对于一些比较慢的地方也能够有针对性地进行优化。

除了性能问题,另一个就是进行第三方 SDK 对接时,往往对方不会提供 React Native 接口。这时就需要我们这边进行一些桥接工作。这个过程本身并不复杂,不过如果 React Native 工程师完全没有原生开发经验的话还是会有一些吃力。因此在团队构成方面,虽然我们不再需要专职的 iOS 和 Android 开发工程师,所有新的业务功能都可以由 JavaScript 工程师实现,但是我们在招聘时仍然更青睐有原生应用开发背景的 React 工程师。目前我们移动客户端组的不少工程师都是既擅长 React/Redux,也掌握 iOS 或 Android 平台上的原生开发知识。

打包工具:Webpack & Rollup

石墨文档主站的打包是通过 Webpack 实现的。Webpack 提供了强大的一站式解决方案,使得 JavaScript、CSS 和图片等静态资源可以通过简单的配置实现需要的整合或拆分打包效果。

一些独立的内部类库则使用了 Rollup 进行打包,Rollup 支持了 Scope hoisting,生成的代码可读性明显好一些,更重要的是其能生成体积更小的代码包以及更快(虽然可以忽略不计)的运行速度。不过相对于 Webpack 而言,Rollup 在一些地方(尤其是开发调试方面)仍有欠缺,使得 Webpack 仍将是我们新项目的默认选择。

另外我们也在持续关注 Facebook 前段时间发布的 Prepack,一款 JavaScript 代码优化工具。通过在几个内部项目中进行的实验,能够看出其在特定代码片段可以起到不错的提升作用。不过由于其仍在早期开发过程中,我们并没有在生产环境中使用。

代码规范:Standard

要提升一个团队的产出效率,就要改善团队的协作方式。统一代码规范能够大大提升团队内部的代码交流效率。在一个团队中,不同的工程师会有不同的编码偏好,如经典的 JavaScript 到底要不要写分号的问题。实际上这些代码风格的争论并没有多少意义,真正有意义的则是确定并严格执行一套统一的代码风格。统一代码风格能够显著提升团队内部每个人的代码理解速度,从而实现高效 Code Review。多个人协作同一个项目时也不会出现因为修改代码风格而发起的无意义的 Pull Request。

在石墨文档,我们使用了 standard 作为基准规范。Standard 的理念在于不可配置,停止争论。其规定了一系列代码规范,比如代码不加分号、统一使用单引号包裹字符串等。之所以使用 standard 作为基准规范而不是直接使用其作为 lint 工具是因为 standard 对于特定的规则并没有做更严格的要求,如大括号内部是否需要空格符等,所以我们基于 standard 的规则定义了一系列额外规则,旨在能够让团队的每个人在理解代码时不会被代码风格的细微差异引入的噪音所干扰。当然在指定这些额外规则时,我们约定了「制定的新规则不能和 standard 的规则冲突」,这使得我们不会陷入制定代码风格的无止尽的讨论中。

技术栈与团队构建

技术栈与团队构建是相互影响的。技术选型造就了团队的职能结构,而反过来团队的具体情况也会对技术选型提出不同的要求。

在拥抱 React 之前,当开发任何新功能时,需要至少三名研发(即网站前端、iOS 工程师和 Android 工程师)参与进来。其中每个人对需求的理解可能都会有一些偏差,导致比较高的沟通成本。而使用 React 之后,由于这三个主要平台使用的都是同样的技术栈,大量的代码得以复用和共享,我们得以探索新的团队构建模式。目前石墨文档前端团队正在逐步向跨平台团队转变,具体而言即每个产品需求由同一个前端工程师来完成,这名工程师会负责这个需求的网页版、iOS 和 Android 版的开发。这样无论是前期需求讨论,还是开发完成后的确认与 QA 流程,效率都能大幅度提升。

而随着石墨文档前端团队的迅速发展,我们也一直在思考如何能够通过技术选型来更加适应团队的当前情况。除了上文提到了使用 standard 来统一团队代码规范外,TypeScript 也是我们正在调研的技术方向。相比于 JavaScript,TypeScript 的静态类型更适合构建大型的应用,这正是其吸引我们的地方。

作者介绍:

李子骅,石墨文档技术总监


前端之巅.png

原    文:前端之巅
作    者:李子骅

免责声明:

  1. SDK.cn遵循行业规范,所有转载文章均征得作者同意授权并明确标注来源和链接。
  2. 我们十分尊重原创作者的付出,本站禁止二次转载如需转载请与原作者取得联系。
  3. 转载SDK.cn的原创文章需注明文章作者、链接和"来源:SDK.cn"并保留文章及标题完整性未经作者同意不得擅自修改。
  4. 作者投稿可能会经SDK.cn适当编辑修改或补充。
推荐工具 意见反馈