likes
comments
collection
share

Taro 2升级Taro 3小结

作者站长头像
站长
· 阅读数 61

背景

在2020年项目立项时,考虑到当时团队内部的技术栈主要是React,因此在最终的项目开发中使用了Taro来完成我们的小程序开发,而当时最新版本就是Taro 2.x;虽然随着这几年的版本迭代我们升级了几个小版本;但终究还是在Taro 2.x的范畴之中;而目前随着项目的迭代我们发现Taro 2.x对我们的开发体验越来越差,逐渐跟不上项目的迭代。因此萌生了将其升为3.x的想法。

在此记录一下升级中踩的坑(声明:我们项目中使用的是React)。

版本简介

Taro 3.x 相较于 Taro 1/2 编译时架构,Taro 3 采用了重运行时的架构,让开发者可以获得完整的 React / Vue 等框架的开发体验。具体原理请参考 《小程序跨框架开发的探索与实践》

Taro 1/2 以及 Taro 3的实现原理可参考: taro1/2及taro3实现原理

Taro 1/2升级到Taro 3虽然看文档需要修改的地方有很多,但是其实大部分情况都可通过搜索替换即可完成的(主要任务量时测试同学的,哈哈)

版本升级

注意:升级之前记得先提交原来的代码。

官方文档:taro-docs.jd.com/docs/migrat…

1、根据官方文档中的升级指南升级相应的依赖

官方做法

Taro 2升级Taro 3小结

个人做法

(推荐此做法) 为了更清楚的了解Taro 3相对于Taro 2的项目结构的差异:

  1. init了一个新的Taro 3项目;
  2. 根据初始化的项目中的依赖,删除掉旧项目中的相应依赖,使用新的依赖版本;
  3. 删除旧项目中的node_modules文件,重新执行npm install;

2、API和Hooks的修改

Taro 2中,所有的API都是在@tarojs/taro 中引入的;

而在Taro 3中,除了属于框架本身的 API 从框架自己的包中引入,其它的 API 仍然从 @tarojs/taro 引入。使用哪个框架来进行开发完全由开发者来决定。

对于我们来说修改项如下(旧的写法大家都知道,就不罗列了):

1、以函数式组件为例:

import Taro from '@tarojs/taro'
import { useState, useEffect } from 'react';

2、以类组件为例:

import Taro from '@tarojs/taro';
import React, { Component } from 'react';

注:当使用了 JSX 时,babel 会隐式地调用 React.createElement;因此只要你使用了 JSX,就要把 React 引入

3、项目以及页面配置

在Taro 2中,项目和页面的配置属性都是挂载在类属性或者函数式的属性上的。但是在Taro 3中项目配置以及每个页面的配置都是在自己的配置文件中去完成的。

参考一下之前我们init的Taro 3项目的文件结构

Taro 2升级Taro 3小结

结构其实很明确,那我们就按照此结构重写我们项目中的相应配置,并且删除之前的写在index.tsx中的无用配置即可.

注:此处的*.config.ts文件名中的“*”需要和你的页面文件名保持一致

下面贴个官网提供的实例:

Taro 2写法:

// app.js 项目配置
class App extends Component {
  config = {
    pages: [
      'pages/index/index'
    ],
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: 'WeChat',
      navigationBarTextStyle: 'black'
    }
  }
  render () {
    return ...
  }
}

// index.js 页面配置
function Index () {
  return ...
}

Index.config = {
  navigationBarTitleText: '首页'
}

Taro 3.x写法

// app.js 项目文件
class App extends Component {
  render () {
    return ...
  }
}

// app.config.js
export default {
  pages: [
    'pages/index/index'
  ],
  window: {
    backgroundTextStyle: 'light',
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: 'WeChat',
    navigationBarTextStyle: 'black'
  }
}

// index.js 页面文件
function Index () {
  return ...
}

// index.config.js 页面配置
const title = '首页'
export default {
  navigationBarTitleText: title
}

4、使用第三方React库

之前我们项目中使用的redux是这样引入的

import { connect } from '@tarojs/redux';
import { useSelector, useDispatch } from '@tarojs/redux';

现在由于taro不再维护@taro/redux库,因此我们需要在react-redux中去引入(记得install后再用),因此如下写法:

import { connect } from 'react-redux';
import { useSelector, useDispatch } from 'react-redux';

5、路由修改

旧版类组件的使用方式:this.$router 旧版函数组件使用方式:

import { useRouter } from '@tarojs/taro
const router = useRouter();

新版使用方式:

import { getCurrentInstance } from '@tarojs/taro'
const { router } = getCurrentInstance()

6、编译配置

这个没什么可说的,我们使用的是react,因此在配置中添加framework配置即可;

framework: 'react'

Taro 2升级Taro 3小结

7、Ref & DOM

ref:之前我们项目中ref是可以以字符串的形式去创建的,项目举例:

Taro 2升级Taro 3小结

Taro 2升级Taro 3小结

Taro 3已经不支持此写法,正确写法如下:

// 函数式组件
import { useRef } from 'react';

const modalRef = useRef();
<Modal ref={modalRef} />

// 类组件
import React, { createRef } from 'react';

class TestComponent extends React.Component<IProps, IState>{
    toast = createRef();
    
    ...
    
    render(){
        <Toast ref={this.toast} />
    }
}

DOM:Taro 3 在底层会维护一个精简的 DOM 系统,在框架中使用 ref 链接到的是一个 Taro Element 实例,因此你直接可以使用 HTMLElement 的部分方法直接操作它。如果你需要获取原生小程序 DOM 实例,那需要使用原生小程序的 SelectorQuery 来获取。

注:大部分和渲染相关的 DOM 属性你都可以通过像 Web 开发一样获取或设置(如果有必要的话你甚至可以通过 parentNode 和 childNodes 访问元素的父元素和子元素!),但元素的位置你还是必须通过原生小程序 DOM 实例的 boundingClientRect() 和 scrollOffset() 方法获取。

8、生命周期

react生命周期更名:

  • componentWillMount() -> UNSAFE_componentWillMount()
  • componentWillReceiveProps -> UNSAFE_componentWillReceiveProps()
  • componentWillUpdate -> UNSAFE_componentWillUpdate()

新增一个生命周期: componentDidCatch(err, info) ,这是由框架本身(React 或 Nerv)提供的。componentDidCatch(err, info) 会在组件和它的子孙抛出错误时触发,第一个参数 err 指向抛出的错误,第二个参数 info 是组件的调用信息。(可借此做日志管理)

9、$scope$componentType

Taro 3没有 this.$scope 和 this.$componentTypegetCurrentInstance().page 可以返回当前小程序页面的实例。

我们直接替换即可。

小结

对于之前项目中有使用CSS Modules 的人来说,经过上面简单的搜索替换添加等一系列操作后,我们的项目就已经能跑起来了(如果还跑不起来就根据控制台提示去补充修改即可),可以看到,虽然Taro 2升级Taro 3过程中我们要修改的地方很多,但其实细心看都是一些简单的搜索替换即可完成的事情,对于较小的项目,很容易就能完成Taro 版本的升级。但是对于内容较多的项目来说,更改的工作量就很大了。再此可以尝试使用一下官方推荐的一键升级工具:taro2-to-3,by @SyMind。

对于项目中之前没有使用CSS Modules 的人来说,最大的坑来了,继续往下看~~

10、样式问题

这个是我认为坑最大的一个。。。先看看文档怎么说的

在taro 3中,没有 组件的外部样式和全局样式 的概念,组件的配置(config.js)是无效的,页面和入口文件引入的 CSS 都会变成全局 CSS ,没有了 externalClasses 和 addGlobalClass 这两个概念。

如果你需要带作用域的 CSS,可以考虑使用 CSS Modules

好了,看了文档的解释我们再看看项目中的css怎么写的

Taro 2升级Taro 3小结

我们这样的写法会导致,我们在修改完项目之后极大概率(除非保证类名不会重复的项目不会出现,但是不会吧,不会真有这样的项目吧?)会出现项目的样式错乱的问题。

好,那我们就使用文档推荐的CSS Modules吧? 无非就是在配置文件中加配置嘛!

      cssModules: {
        enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
        config: {
          namingPattern: 'module', // 转换模式,取值为 global/module
          generateScopedName: '[name]__[local]___[hash:5]',
        },
      },

好,加完了!问题来了,项目中我们的写法都是形如className="XXXXX"的方式。再看看CSS Modules怎么写的

import styles from "./style.less";
// import { className } from "./style.css";

element.innerHTML = '<div class="' + styles.className + '">';

都是styles.clssName的命名方式

那我们要修改的岂不是很多~~ , 想想就崩溃了!那可以思考一下有没有什么简单的修改方式可以达成同样的目的呢?答案当然是有的,babel-plugin-react-css-modules是不是很熟悉呢?没错,我们web项目中很常用的一个插件,我们可以通过它很便捷的将className修改为styleName即可达到快速实现修改CSS Modules的目的。

install之后,我们还需要如下配置

Taro 2升级Taro 3小结

美滋滋,运行一下如下代码:

Taro 2升级Taro 3小结

Taro 2升级Taro 3小结

运行结果:

Taro 2升级Taro 3小结 很明显失败了,原因是生成的类名不一致,既然使用hash会导致命名不一致的问题,那我们就曲线救国使用一下"[path][name]__[local]"命名方式吧。

再次运行:

Taro 2升级Taro 3小结

完美配置生效,基于此我们就可以通过全局搜索替换的方式将className修改为styleName,从而降低我们的工作量。

总结

基于以上修改,我们已经完成了对于Taro 2升级Taro 3的操作,虽然已经完成了升级,但是还遗留了一个问题,那就是为什么两次生成的hash值不一致的问题,这个由于目前还没时间去深入探究,因此会留在下期去解答。有深入了解这块的小哥哥、小姐姐欢迎交流。

转载自:https://juejin.cn/post/7215991883801460792
评论
请登录