Taobao FED

Why Rax?

Why Rax?

https://github.com/alibaba/rax

从今年 1 月 12 日在 Weex Conf 上宣布 Rax 开源,至今已过去一个月左右的时间,这段时间里,Rax 拿到 2400+ 的 star, 我们深知这对一个开源产品来说是微不足道的,但是从中可以发现的是「前端或者 Weex 社区对于类 React 的技术方案是有很大需求的」。同时,结合近期 GitHub 上的相关 issue, 大抵上就有了这样一篇完整介绍 Rax 的文章。

淘宝无线端的发展历程

在前端这条道路上,淘宝 FED 一直以来的使命就是「用技术为体验提供无限可能」,Rax 自然也是在追求体验的道路上发展出来的。

从 2014 年开始,结合阿里双十一双十二的数据变化,无论从用户访问量还是最终成交量上都可以清晰的看到:「移动端已然是当下业务的主要阵地」,当业务重心向移动端偏移时,技术也在悄然发生变化,传统而成熟的 PC 端技术方案俨然已经无法满足移动端对体验性能、开发效率等各个方面的要求,这也开启了我们在无线端上的技术探索之路。

KIMI

2014 年伊始,算是阿里无线业务起步的阶段,那时候大家把无线页面还称为 H5, 诸如 KISSY, jQuery 之类的库对于无线页面来说尺寸太大、加载太慢,于是我们基于社区成熟的 Zepto 迅速打造了 KIMI 这个核心库,然后围绕业务不断完善 KIMI 的组件生态以及包含工程化、性能检测等一系列生态。这套生态伴随着我们走过了将近两年时间,至今仍可以在一些页面上找到 KIMI 的影子。

然而,KIMI 始终是一个 Web 端的解决方案,即便可以通过一些方案去调用 native 的原生方法,也无法跨域无线端上 Web 体验不及 native 体验这样一个既定事实。于是,如何能让页面达到 native 的体验成为我们的下一个探索点。

React Web

说起 native 的体验,最直观的方案就是直接去写 native 代码,然而 native 的开发模式一直存在一些难以解决的问题:

  • 成本与效率:iOS, Andriod, Web 三端需要不同的技术团队各自开发一套,成本大,效率低
  • 灵活性:受限于 AppStore 的审核机制,版本发布周期较长,难以满足业务需求

所以,我们需要一套基于 Web 的开发模式但可以产出 native 页面的解决方案,效率与体验兼得。在这个思路下,阿里也有过一些尝试,不过都没有形成最终的解决方案,这里就不再详细讲述了。直到 2015 年中期,Facebook 开源了 React Native(RN), 虽然初期只有 iOS 的版本,但丝毫不影响其对整个无线开发方案的巨大冲击。RN 基本完美解决了需要编写两端代码的问题,同时还有一个非常活跃完善的 React 社区,因此这个方案也得到了诸多开发者的青睐。

接着,我们也快速在手淘里尝试了 RN 的方案,受限于 RN 的兼容性问题以及用户可能在浏览器端打开页面,因此整个页面必须要有能力降级到 Web 版本。这时候回想下 RN 的口号:Learn once, write anywhere. 但这对于我们来说,或许还不够,我们真正需要的是:Write once, run everywhere.

因此我们开始探索如何让 RN 的代码运行在 Web 端,这就是 React Web 方案。

Rax

2015 年双十一,Weex 的方案开始逐步使用,经过这次试水,证明了这套方案未来的场景及可行性,接着 2016 年 Weex 开始进入快速发展的阶段。但是使用 Weex 就意味着必须用 Vue 的语法,这对于整个团队来说是一个不小的挑战:PC 场景下的项目,小伙伴们普遍基于 React 开发,已经有了相当多的经验与沉淀。如果无线的项目要采用一个不同方案(Vue)去做,强推未必会不奏效,但是小伙伴们大概会伤心吧。

于是我们尝试将 React 与 Weex 结合起来,但是由于方案太过 hack 导致各种问题,遂无奈放弃。接着 Rax 的方案应运而生:「Rax 基于 React 的标准,支持在不同容器中渲染,当前最重要的容器即 Weex 和 Web」。

Rax 体系

Rax 与 React

React 是一种标准,Rax 是对该标准的一个实现。

社区里很多人关心 Rax 与 React 的优缺点以及相互取代的可能性,事实上,从上文的发展历程就可以看出来,Rax 只是无线端的解决方案,与 React 并无冲突。事实上淘宝 PC 端的新项目,依然主要是基于 React,并且我们也有一套基于 React 的解决方案名为 ICE,通过一系列的工具帮助开发者提高效率,此处不再展开。

当然,Rax 跟 Preact 之类的方案也有本质区别,前者偏向于解决多端问题,后者偏向于解决性能问题,具体可参考下文「Rax 的特点」。

Rax 的特点

1. 设计上支持不同容器

Rax 在设计上抽象出 Driver 的概念,用来支持在不同容器中渲染,比如目前所支持的:Web, Weex, Node.js. 基于 Driver 的概念,未来即使出现更多的容器(如 VR 等),Rax 也可以从容应对。Rax 在设计上尽量抹平各个端的差异性,这也使得开发者在差异性和兼容性方面再也不需要投入太多精力了。

详细内容可参考 Rax Driver Spec.

2. 体积足够小

如上文所说,Rax 是一个面向无线端的解决方案,因此自身的体积对于性能来讲就显得非常重要。Rax 压缩 + gzip 后的体积是 8.0kb, 相比 React 的 43.7kb, 对于无线端友好了很多。

3. 支持返回多个同级节点

任何用过 React 的同学大概都踩过同一个坑:方法返回了多个同级节点导致报错。在设计上 React 只能返回单个节点,因此页面上或多或少会产生一些冗余的节点,这在 PC 端并没有太多问题,然而在无线 Android 端嵌套层级越多,应用的 crash 率会不断提高,这一点在低端 Android 机上表现尤其明显。因此 Rax 支持了返回多个同级节点的功能,如:

1
2
3
4
5
6
7
8
9
import {createElement, Component, render} from 'rax';

class Test extends Component {
render() {
return [1, 2, 3].map((item) => {
return <p>{item}</p>;
});
}
}

这一特性可以有效减少页面的嵌套层级,从而减少应用因嵌套层级过多而出现的 crash 问题。

4. 标准化

在上文里,我们不断的提各个端的一致性,一致则必有规范可依,Rax 遵循 W3C 标准,比如在 Weex 容器中已经可以直接调用 navigator, document, location, alert 等 W3C 的标准 API.

当然,受限于各个端的差异,标准化的道路还很长,「更标准化」这也是 Rax 未来的重要目标之一。

RAXUI

Rax 旨在解决多端一致的问题,这帮助我们无需关注各个端的差异性,实现「Write once, run everywhere」的愿景。然而在前端开发领域,开发人员需要直面的还是 UI 体系,不同项目间夜以继日的开发着功能类似的组件,想想就觉得头疼,因此 Rax 在最基础的元件 rax-components 之上实现了一套官方的 UI 组件,即 RAXUI.

RAXUI 是 RAX 上层的一套通用 UI 组件,帮助开发者快速完成模块和页面的开发。比如 Picture 组件是对元件里的 Image 做了一层封装,包含图片优化、H5 懒加载等更多功能,TabHeader 组件可以帮助开发者便捷的实现横向滚动导航… RAXUI 不仅能降低业务的开发成本,同时为了保证产品质量,RAXUI 在兼容性、性能、设计规范等很多方面都有更多更完善的考虑。在不久的将来,这套 UI 体系也会逐渐向社区开放。

未来

Write once, run everywhere. 这是口号,亦是目标。Rax 未来会在更多的端上不断探索,比如 VR/AR, 甚至之前微博上有同学提出的是否可以用 Rax 写微信小程序,也是一个蛮有意思的想法。

对于开发者来说,当越来越多的端不断出现在眼前时,我们应该如何应对?是通过不断的踩坑来整理一份长长的 checklist, 然后做项目时一一对照? 或者让我们一起来探索 Rax?

Rax 团队敬上。


相关链接