点击“开发者技术前线”,选择“星标🔝”
13:21 在看|星标|留言, 真爱
来源:凹凸实验室
开发者技术编辑部:可可
Taro 是什么?
Taro 是由凹凸实验室打造的一套遵循 React 语法规范的多端统一开发框架。现如今市面上端的形态多种多样,Web、App 端(React Native)、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信小程序、H5、App 端等)运行的代码。同时 Taro 还提供开箱即用的语法检测和自动补全等功能,有效地提升了开发体验和开发效率。Taro 能提供什么?
一次编写,多端运行
既然是一个多端解决方案,Taro 最重要的能力当然是写一套代码输出多端皆可运行的代码。目前 Taro 已经支持一套代码同时生成 H5 和小程序,App端(React Native)端也即将支持,同时诸如快应用等端也将得到支持。同时 Taro 也已经投入到了生产环境使用,目前已经支撑了一个 3 万行代码小程序的开发并上线。京东购物 小程序和 一起有局 小程序也在使用 Taro 部分重构中,即将上线。未来也将接入更多业务。Taro 的设计思路
Taro开发人员:我们的初心就是做一款能够适配多端的解决方案,结合业务场景、技术选型和前端历史发展进程,我们的解决方案必须满足下述要求:- 代码多端复用,不仅能运行在时下最热门的 H5、微信小程序、React Native,对其他可能会流行的端也留有余地和可能性。
同时满足这几个需求并不容易,在我们经过充分地调研和思考之后发现只有 React 体系能够满足我们的需求。而对于微信小程序而言,使用 React 完全没有办法进行开发——直到我们从 codemod 得到灵感:在一个优秀且严格的规范限制下,从更高抽象的视角(语法树)来看,每个人写的代码都差不多。
也就是说,对于微信小程序这样不开放不开源的端,我们可以先把 React 代码分析成一颗抽象语法树,根据这颗树生成小程序支持的模板代码,再做一个小程序运行时框架处理事件和生命周期与小程序框架兼容,然后把业务代码跑在运行时框架就完成了小程序端的适配。对于 React 已经支持的端,例如 Web、React Native 甚至未来的 React VR,我们只要包一层组件库再做些许样式支持即可。鉴于时下小程序的热度和我们团队本身的业务侧重程度,组件库的 API 是以小程序为标准,其他端的组件库的 API 都会和小程序端的组件保持一致。
Taro 1.2发布以来,1.3 经历了6 个月的开发时间,近 2千次的代码pr,除了京东内部,还有行业百位开发者的共同参与。支持 JSX 语法和 React Hooks
—
在 Taro 1.3 中,开发者可以充分发挥自己的创造力和想象力,可随意地写 if-else ,随意地写匿名函数,把 JSX 放在类函数中,也可以放在普通函数中。只要编译器和和 ESLint 不报错,就可以这么写。开发团队优先把 React Hooks 带到了 Taro 中,还写了两个小例子展示如何在 Taro 中使用 Hooks:https://github.com/NervJS/taro-v2ex-hookshttps://github.com/NervJS/taro-todomvc-hooks
支持 QQ 小程序和快应用
—
快应用的开发模式非常特别,它的 API、组件系统、组件库和其他小程序端差异非常大,并且快应用有自己的标准规范,各大安卓厂商对运行时的实现和限制也各不相同。这块痛点终于也被 Taro 解决了。QQ 小程序作为新兴的小程序,大家普遍对它了解不多,但 Taro 也率先实现了对 QQ 小程序的支持。意味着,不管你的业务要支持哪一个小程序端,只要维护一套代码,Taro 就能生成对应小程序平台的代码。同时 Taro 也成为了业界首个同时支持微信、百度、字节跳动、支付宝、QQ 小程序和快应用共 6 端小程序的开发框架。新增新的生命周期和 Context API
—
在 Taro 1.3 支持了 React 16 的新生命周期函数static getDerivedStateFromProps()和 getSnapshotBeforeUpdate() 。当新的生命周期函数注入到类组件时,老的生命周期函数将不会被调用,能减少一次渲染和更新的开销。Taro 1.3 还实现了 新 Context 通过声明式的 API 来传递组件的更新,使得Taro 跨组件通信和共享状态更为直观。同时,例如 react-redux 这样的热门库也正在基于 Context 和 Hooks 进行重构,我们也非常期待与社区一起探索 React/Taro 新的开发与设计模式。大幅提高 H5 性能和可用性
—
在 Taro 1.3 中,优化了编译代码的方式,实现了资源最小引入和按需加载引入,将原有最小项目的编译大小降低了 80% 左右。提高用户极致体验。H5 端的 API 数量和质量也得到了大幅地增长,Taro 1.3 新增了 28 个 H5 API。Taro Doctor
—
从 Flutter Doctor 中得到启发,开发了 Taro Doctor。Taro Doctor 就像一个医生护士一样,有诊断项目的依赖、设置、结构,以及代码的规范是否存在问题的能力,并尝试给出解决方案。但和真正的医生不一样,Taro Doctor 不需等待队列。你只需要在终端运行命令:taro doctor ,就像下图里一样:
更多
—
Taro 1.3 还做了许多额外的工作,为Taro 的稳定性以及将来更多的可能性夯实了基础:
组件传参(props)系统重构
在 Taro 1.0 到 1.2 的小程序端,我们一直使用原生小程序框架的组件传参系统,但小程序组件系统没办法传递函数的值,也无法传递非具名参数,并且各小程序组件的实现各不相同。为了解决这些问题,在 Taro 1.3 中我们自己实现了一套组件传参系统。新系统会使得传参相关的代码更为可靠,同时也是我们支持更多 JSX 语法的基础。
命令行工具(CLI) 重构
在 Taro 1.3,我们将命令行工具使用 TypeScript 进行了重构并逐步添加更多测试用例。重构之后我们可以更加大胆地为 CLI 添加新功能,替换老旧依赖。同时我们也会将 CLI 的功能以 API 的形式暴露出来,赋能给其它开发工具和我们的合作伙伴。
移动端容器更换
我们和京东的 ARES 团队合作,把原有的移动端容器 expo 替换为深度定制的 JDReact。JDReact 大幅提升了 Taro 移动端的可控性,可以让我们突破 expo 的掣肘,引入原生移动端代码,提供定制功能和 API,并且性能和稳定性的表现都会更好。
支持开发小程序插件
小程序插件是小程序带来的一个非常优秀的特性,可以极大地提高代码复用率,降低包大小,为开发者带来诸多便利,目前微信、支付宝小程序已经支持插件功能。而从 1.3 版本开始,Taro 支持直接开发微信与支付宝小程序插件,这意味着 Taro 项目将和小程序插件无缝对接,不再有开发模式切换的成本。
支持「小程序·云开发」
「小程序·云开发」是微信小程序联合腾讯云团队提供的一个非常强大的功能,它是一款 Serverless 服务,为开发者提供了「云函数」、「云数据库」和「云文件存储」三大能力,并且将这些能力封装成特定的接口,可以帮助开发者快速构建微信小程序的后端服务。为了让 Taro 开发者能够享受到「小程序·云开发」的能力,Taro 也加入了对「小程序·云开发」的支持,为「小程序·云开发」提供了初始化模板,并且将小程序云相关的 API 进行了封装,方便开发者进行使用。同时,「小程序·云开发」已提供 H5 版本的 SDK,Taro 支持将小程序、H5 的调用方式进行统一封装,帮助开发者快速打造 Serverless 的多端应用。升级兼容性
—
正如前面所提到,Taro 1.3 是一个酝酿时间最久,拥有特性最多的大版本,对 Taro 底层也进行了不小的重构,所以,1.3 版本的升级带了以下 2 个兼容性问题。
JSX 中的事件监听函数必须绑定作用域
在之前的 Taro 版本中,JSX 中绑定的事件监听函数,是可以不需要绑定任何作用域,就能访问到组件实例的,例如:import Taro, { Component, Config } from '@tarojs/taro'
import { View, Button } from '@tarojs/components'
export default class Test extends Component {
state = {
hello: 'noclick'
}
clickHandler () {
this.setState({
hello: 'click'
})
}
render () {
return (
<View className={styles.index}>
<Button onClick={this.clickHandler}>点击</Button>
</View>
)
}
}
上述例子中, <Button /> 按钮绑定的点击事件,在之前版本中是能够正常执行的,Taro 会默认将 clickHandler 的作用域绑定为当前组件实例,但是这并不符合 React 中的实际情况,所以,在 1.3 版本中,我们对这一问题进行了修复,现在 JSX 中的事件监听函数必须绑定作用域,否则就会报错。render () {
return (
<View className={styles.index}>
<Button onClick={this.clickHandler.bind(this)}>点击</Button>
</View>
)
}
或者你也可以在 `constructor` 中将函数进行提前绑定作用域
constructor () {
this.clickHandlerBind = this.clickHandler.bind(this)
}
render () {
return (
<View className={styles.index}>
<Button onClick={this.clickHandlerBind}>点击</Button>
</View>
)
}
还有一种做法是,将 clickHandler 写成箭头函数,这种方式在新旧版本中均可以正常运行。
暂时无法在原生应用中使用 Taro 组件,后续支持
结语
经过数个月的开发,Taro 从第一次 commit 到发展成包括 16 个包,十多位同学共同参与的大型项目。与此同时,Taro 也在生产环境支撑了数个复杂业务线上项目的开发,将来也会支撑更多业务。
Taro 的技术方案和实现也根植于社区,我们也希望为技术社区的发展壮大贡献一份自己的力量。秉持着凹凸实验室长久以来开源、开放、共享的优良传统,我们今天将 Taro 全部代码开源,为广大开发者快速开发多端项目提供一整套技术解决方案。未来,我们也将继续拓展 Taro 现有能力,支持更多端能力,继续完善开发者体验,提高开发者效率,帮助更多开发者,同时也从社区中汲取养分,让 Taro 变得更加强大。
Taro 官网:https://taro.jd.com
GitHub: https://github.com/NervJS/taro
END开发者技术前线 ,汇集技术前线快讯和关注行业趋势,大厂干货,是开发者经历和成长的优秀指南。
好文点个在看吧!