盘一盘Taro2升级到Taro3踩到的坑

背景

随着业务代码不断迭代,小程序的主包内容已经越来越脱离掌控,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,这个可以大大减少一些不必要的工作量,比如:

  1. React中对于Component的引入方式;
  2. page-config的抽离;
  3. 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之前书写方式已经不能正常监听,如下:

现在推荐如下几种方式解决

  1. 写在constructor 里面,这也是最推荐的方式,改造量最小。
js 复制代码
class Store {
  activeStat = 0
  ...
  constructor() {
  makeAutoObservable(this)
  reaction(
    () => this.activeStat,
    debounce(async () => {
      // todo...
    }
             }, 500)
    }
  ...
  getList = async () => {
    this.list = await ajax()
  }
}
  1. 实例化后写在后面
  2. 实例化后写在组件里面

结尾

在升级过程中,我们还遇到了很多奇奇怪怪的问题,有的跟Taro有关,有的跟小程序有关,就比如说某些插件在不同的版本会有不同的表现,在不同平台的兼容,这些问题处理起来都是比较棘手的。而且本身的业务逻辑是比较复杂,有很多点是我们没有监控到的,导致上线也是出现了一些问题。所以最后还是奉劝大家一句,没事就别乱升级,代码能跑就行。

相关推荐
虾球xz4 分钟前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇9 分钟前
HTML常用表格与标签
前端·html
疯狂的沙粒13 分钟前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员29 分钟前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐31 分钟前
前端图像处理(一)
前端
程序猿阿伟38 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒40 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪1 小时前
AJAX的基本使用
前端·javascript·ajax
力透键背1 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M1 小时前
node.js第三方Express 框架
前端·javascript·node.js·express