背景
随着业务代码不断迭代,小程序的主包内容已经越来越脱离掌控,Taro3提供新的压缩功能被我们看中;而且代码体积的不断臃肿,Taro2带来开发体验也是越来越差;加之官方对于Taro2除了重大bug已经不在更新。这些问题都迫使我们不得不升级到Taro3,在升级之前已经能够预想到遇到各种各样的问题,现在把其中遇到的一些坑跟大家分享一下。
升级之前
版本区别
这里节选自官方文档供大家参考:传送门
Taro1/2
Taro 1/2 属于编译型架构,主要通过对类 React 代码进行语法编译转换地方式,得到各个端可以运行的代码,再配合非常轻量的运行时适配,以及根据标准组件库、API 进行差异抹平,从而实现多端适配的目的,整体架构如下。
而 Taro 1 与 Taro 2 的都是基于这种架构建立的方案,他们之间的区别主要是 Taro 1 在小程序端是自建构建体系,而 Taro 2 则是所有端都采用 Webpack 进行编译,可以降低 Taro 自身编译系统的复杂度,同时能够让开发者使用 Webpack 的生态来自定义编译过程和结果,可以认为 Taro 2 是 Taro 1 和 3 之间的一个过渡性版本。
Taro3
Taro 3 则可以大致理解为解释型架构(相对于 Taro 1/2 而言),主要通过在小程序端模拟实现 DOM、BOM API 来让前端框架直接运行在小程序环境中,从而达到小程序和 H5 统一的目的,而对于生命周期、组件库、API、路由等差异,我们依然可以通过定义统一标准,各端负责各自实现的方式来进行抹平。而正因为 Taro 3 的原理,所以我们可以在 Taro 3 中同时支持 React、Vue 等框架,甚至我们还支持了 jQuery,在不久的将来我们还能支持让开发自定义地去拓展其他框架的支持,比如 Angular,Taro 3 整体架构如下。
升级前建议
官方升级指南
再升级前建议阅读官方升级指南进行基本迁移:传送门
taro2-to-taro3
在升级之前推荐使用脚本taro2-to-taro3,这个可以大大减少一些不必要的工作量,比如:
- React中对于
Component
的引入方式; - page-config的抽离;
- router路由的获取。
下面将详细的介绍。
盘点
基本迁移
taro-imports
在 Taro 2.x 中,所有面向应用开发者的 API 都在 @tarojs/taro 包中。
在 Taro 3.x 中,将 React 的 API 从 react 包中引入,其它的 API 仍然从 @tarojs/taro 引入。
js
- import Taro, { Component } from '@tarojs/taro';
+ import React, { Component } from '@tarojs/taro';
+ import Taro from '@tarojs/taro';
class Wallace extends Component {
componentDidMount() {
Taro.request().then(() => {});
}
render() {
return <div />;
}
}
page-config
在 Taro 2.x 中,页面的配置挂载在类组件的类属性或函数式的属性上,通过 AST 分析取出来,然后生成 JSON 文件。
在 Taro 3.x 中,使用 *.config.js ,该文件和页面文件在同一文件夹。
js
// foo.jsx
export default class Index extends Component {
- config = {
- navigationBarTitleText: '首页'
- }
render() {
return null;
}
}
+// foo.config.js
+export default config = {
+ navigationBarTitleText: '首页'
+};
router
在 Taro 2.x 中,通过 this.$router 访问当前组件/页面路由的详情。
在 Taro 3.x 等价的 API 是 @tarojs/taro 包中的 getCurrentInstance().router。
js
class Foo extends Component {
+ $instance = getCurrentInstance();
componentWillMount() {
- console.log(this.$router);
+ console.log(this.$instance.router)
}
}
样式问题
该问题出现的原因就是taro2和taro3编译结果不同的原因,在taro2中会有#shadow-root 作为样式的隔离,但是taro3里面就没有这种隔离,导致了一些样式问题。
高度塌陷问题
这种就只能在迁移过程中一个一个去发现,解决方案:理解margin塌陷和margin合并及其解决方案
样式隔离问题
在老的仓库中,会有一些样式使用的直接导入less样式,这样在失去#shadow-root 隔离的情况下,就是导致一些样式污染的问题,这里的建议是当前页面改造成css-module 做一下样式的隔离。
this.$scope
丢失问题
升级之后通过this.$scope
不能获取到之前实例,原因是$scope问题。
由于 Taro Next 没有自定义组件,所以也没有了 this. <math xmlns="http://www.w3.org/1998/Math/MathML"> s c o p e 和 t h i s . scope 和 this. </math>scope和this.componentType 的概念。getCurrentInstance().page 可以返回当前小程序页面的实例。
如果你的页面用到了大量的this.$scope 方法,推荐你使用如下方式兼容
js
class MyComponents extends Component {
get $scope() {
const pages = Taro.getCurrentPages()
const current = pages[pages.length - 1]
return current
}
componentDidMount(){
console.log(this.$scope)
}
render(){
return <View />
}
}
获取节点的问题
在Taro2中通过Ref获取的节点是原生小程序的DOM实例 ,而Taro3获取到的是类似ReactELement的TaroElement 的一个虚拟dom。但是你要boundingClientRect() 或者scrollOffset() 就必须使用获取到原生小程序的DOM实例,你可以通过如下的方式获取到
即使如此,我们在获取节点的过程中依旧会遇到没有返回节点的情况,这个也是Taro异步渲染带来的问题,建议是在onReady之后调用
从此生命周期开始可以使用 createCanvasContext 或 createSelectorQuery 等 API 访问小程序渲染层的 DOM 节点。传送门
mobx升级带来的问题
数据监听问题
mobx升级之后之前监听的方式
已经不能正确在监听到数据的变化,现在推荐使用的方式是
reaction监听副作用问题
mobx升级之后reaction之前书写方式已经不能正常监听,如下:
现在推荐如下几种方式解决
- 写在constructor 里面,这也是最推荐的方式,改造量最小。
js
class Store {
activeStat = 0
...
constructor() {
makeAutoObservable(this)
reaction(
() => this.activeStat,
debounce(async () => {
// todo...
}
}, 500)
}
...
getList = async () => {
this.list = await ajax()
}
}
- 实例化后写在后面
- 实例化后写在组件里面
结尾
在升级过程中,我们还遇到了很多奇奇怪怪的问题,有的跟Taro有关,有的跟小程序有关,就比如说某些插件在不同的版本会有不同的表现,在不同平台的兼容,这些问题处理起来都是比较棘手的。而且本身的业务逻辑是比较复杂,有很多点是我们没有监控到的,导致上线也是出现了一些问题。所以最后还是奉劝大家一句,没事就别乱升级,代码能跑就行。