Taro 设计思想与架构
TIP
Taro 诞生之初是为了解决微信小程序开发的一系列痛点,那么它是如何从一个小程序开发框架慢慢演变成一个多端统一开发框架的呢?
使用 React 语法来写小程序
谈一谈小程序开发
微信小程序为我们的业务提供了一种新的展现形态,但对于开发者来说,开发体验则显得并不那么友好。
首先,从文件组织上看,一个小程序页面或组件,需要同时包含 4 个文件:脚本逻辑、样式、模板以及配置文件,在开发一个功能模块时,就需要在 4 个文件之间切换,而当功能模块多的话,就需要在多个文件之间切换,这样显然非常浪费时间。
其次,从开发方式上看,在前端工程化思想深入人心的今天,小程序的种种开发方式显得有些落后了,主要体现在以下几个方面:
- 没有自定义文件预处理,无法直接使用 Sass、Less 以及较新的 ES.Next 语法;
- 字符串模板太过孱弱,小程序的字符串模板仿的是 Vue,但是没有提供 Vue 那么多的语法糖,当实现一些比较复杂的处理时,写起来就非常麻烦,虽然提供了 wxs 作为补充,但是使用体验还是非常糟糕;
- 缺乏测试套件,无法编写测试代码来保证项目质量,也就不能进行持续集成,自动化打包。
所以,从开发方式上看,小程序开发没有融入目前主流的工程化开发思想,很多业界开发模式与工具没有在小程序开发中得到相应体现,像是从前端工业时代回退到了刀耕火种的年代。
最后,从代码规范上看,小程序的规范有很多不统一的地方,例如内置组件的属性名,有时候是全小写,有时候是 CamelCase 格式,有时候又是中划线分割的形式,这样就导致编码的时候得不时查阅文档才能确定写法。
如何更优雅地开发小程序
在 Taro 的设计之初,我们的想法就是希望能够以一种更加优雅的方式来开发小程序,解决小程序开发上的种种痛点,首先我们希望能使用前端工程化的方式来进行开发,同时在语法上,我们希望能抛弃小程序的四不像语法,遵循一套我们熟悉的框架语法来进行开发,这样不仅能更好地保证开发质量、提升开发体验,同时也能大大降低开发者开发小程序的成本。
于是,在开发方式上,Taro 打造了一套完善编译工具,引入了前置编译的机制,可以自动化地对源文件进行一系列的处理,最终输出小程序上的可执行文件,包括代码的编译转换处理,加入文件预处理功能,支持 NPM 包管理等等,这一部分的原理,将会在后续章节中为大家介绍。而语法标准上,我们把目光投向了市面上流行的三大前端框架。
React、Vue、Angular 是目前前端框架三巨头,他们各有各的风格,关于他们的优劣,在业界也是一直争论不休,这本身也是智者见智仁者见仁的事,所以在本文中就不再评述。Taro 最终采用的是 React 语法来作为自己的语法标准,主要有以下几点考虑:
- React 是一个非常流行的框架,也有广大的受众,使用它也能降低小程序开发的学习成本;
- 小程序的数据驱动模板更新的思想与实现机制,与 React 类似;
- React 采用 JSX 作为自身模板,JSX 相比字符串模板来说更自由,更自然,更具表现力,不需要依赖字符串模板的各种语法糖,也能完成复杂的处理
- React 本身有跨端的实现方案 - React Native,并且非常成熟,社区活跃,对于 Taro 来说有更多的多端开发可能性。
最终,Taro 采用了 React 语法来作为自己的语法标准,配合前端工程化的思想,为小程序开发打造了更加优雅的开发体验。
如何实现优雅
那么如何实现使用 React 来开发小程序呢?在 Taro 中采用的是编译原理的思想,所谓编译原理,就是一个对输入的源代码进行语法分析,语法树构建,随后对语法树进行转换操作再解析生成目标代码的过程。
探索多端可能性
多端统一开发一直是所有开发人员的共同追求。在终端碎片化的大背景下,前有 Hybrid 模式拉开序幕,后有 React Native、Weex 风起云涌,再到如今 Flutter 横空出世,种种这些都是为了能够 Write once, run anywhere 。给每一种终端单独进行开发的成本是昂贵的,所以一个能够尽可能抹平多端开发差异的开发解决方案就显得极为重要。
多端转换原理
开发时我们遵循 React 语法标准,结合编译原理的思想,对代码文件进行一系列转换操作,最终获得可以在小程序运行的代码。而 React 最开始就是为了解决 Web 开发而生的,所以对代码稍加改动,也可以直接生成在 Web 端运行的代码,而同属 React 语法体系下的 React Native,也能够很便捷地提供支持。同理其他平台,如快应用、百度小程序等,将源码进行编译转换操作,也能获得该平台下的对应语法代码。
抹平多端差异
基于编译原理,我们已经可以将 Taro 源码编译成不同端上可以运行的代码了,但是这对于实现多端开发还是远远不够。因为不同的平台都有自己的特性,每一个平台都不尽相同,这些差异主要体现在不同的组件标准与不同的 API 标准以及不同的运行机制上。
以小程序和 Web 端为例。
可以看出小程序和 Web 端上组件标准与 API 标准有很大差异,这些差异仅仅通过代码编译手段是无法抹平的,例如你不能直接在编译时将小程序的 <view />
直接编译成 <div />
,因为他们虽然看上去有些类似,但是他们的组件属性有很大不同的,仅仅依靠代码编译,无法做到一致,同理,众多 API 也面临一样的情况。针对这样的情况,Taro 采用了定制一套运行时标准来抹平不同平台之间的差异。
这一套标准主要以三个部分组成,包括标准运行时框架、标准基础组件库、标准端能力 API,其中运行时框架和 API 对应 @taro/taro,组件库对应 @tarojs/components,通过在不同端实现这些标准,从而达到去差异化的目的。
而在标准的定制上,起初我们想重新定制一套标准规范,但是发现在所有端都得实现这套标准的成本太高,所以我们就思考为什么不以一个端的组件库、API 为标准呢?这样不仅省去了标准定制的时间,而且在这个端上我们可以不用去实现这套标准了。最终在所有端中,我们挑选了微信小程序的组件库和 API 来作为 Taro 的运行时标准,因为微信小程序的文档非常完善,而且组件与 API 也是非常丰富,同时最重要的是,百度小程序以及支付宝小程序都是遵循的微信小程序的标准,这样一来,Taro 在实现这两个平台的转换上成本就大大降低了。