Taro升级
Taro 3出来有段时间了,有一个小程序用Taro 2写的,升级了一下,前前后后花了几个月时间,中间还失败了几次,踩了不少坑。
最主要的问题还是这类工具文档相对缺乏,很多时候只能摸瞎,碰运气解决问题。
本文主要记录踩坑记录,分享个人的踩坑经历,让踩同样的坑的人能快速绕过同样的坑,并不是一篇系统性的解释taro原理或者新老taro版本对比的文章,也不对Taro升级做完整的解释。
怎么读这篇文章:
- 文章重点分两部分,第一部分是
升级流程
, 相当于升级教程。 第二部分是问题流水账
, 相当于问题解决手册,遇到具体的错误可以直接查阅这地方的内容。 - 升级前建议按照升级流程把里面的每一步都做一遍,出问题也没关系。做一遍升级流程里面的内容,你可以直接跳过很多坑。
- 如果遇到具体的错误,可以去流水账里面找相应的问题和解决方法。
升级的坑我简单分几类:
- 一类是配置的问题,Taro的架构变了,依赖变了,配置结构也变了,导致有很多编译运行的问题. 这是最难搞的,因为这属于
Taro
私有设计,除了Taro官方的网站,很难在其它地方找到说明. - 第二个是Taro的运行时变化。以前很多都是编译时绑定的代码。以前的
react
,mobx
,Taro自己封装一遍,在编译器绑定,现在呢,都直接用原生的包了,不封装了, 运行时绑定。那么这个升级时要特别注意,小心. - 第三类,Taro的生命周期变化。Taro 2的时候还有主动调用
Taro.render(<App />, document.getElementById('app'))
, Taro 3里面没有了,是被动调用了。Taro 2的代码在Taro 3下就怎么也跑不起来了。这种坑不说,很难发现。 - 第四类,Taro有一些隐式绑定(运行时绑定),编译能过,跑的时候不能过,抛的错就定位不是非常清晰。
- 第五类是接口升级,因为很多库版本也跟着升级了,有一些库一些用法和接口也不一样,也会发现一些问题。 这些干扰因素会造成很多不必要的困扰,让你误判问题所在,兜圈子,浪费时间。
- Taro 版本共存的问题. 这个问题会在升级流程的最前面说一下解决办法。
下面我会简单记录一下升级的流程, 然后记一下出错处理流水账, 再尽可能的对Taro做一些分析, 解释一下为何会有那些问题。
升级流程
升级主要有以下几步流程,大家可以参考。
升级前请先新建一个taro 3的模板项目,下面要用到。
Taro版本共存
升级的时候可能需要不同版本的taro共存。 包括taro库和taro cli的共存。
taro库不用说了,在package.json里面。 重点是taro cli. 如果有全局的taro cli, 不同的taro项目编译就会有环境冲突。
解决办法是,
- 删除全局taro cli:
yarn global remove @tarojs/cli
, 在我另外一篇文章调试taro代码有提到. - 创建项目的时候用
npx
命令:npx @tarojs/cli init xxxx
- taro cli不要全局安装, 写到package.json 的devDependency里面去. 这样项目会优先用当前目录下的taro工具版本.
// for taro 3 "devDependencies": { "@babel/core": "^7.8.0", "@tarojs/cli": "^3.0.26",
解决了taro 环境共存的问题,接下来就可以正式进入升级环节了。
0. 读升级文档
升级前先读从旧版本迁移到 Taro Next, 这片文章非常好! 好在哪地方?
第一,它是官方文档,可信。
第二,它用词非常讲究,给人一种力量!文章的精华就在第一段,它让人读完以后精神备受鼓舞,斗志昂扬,内心的冲动按耐不住,迫不及待得去动手升级。 这篇文章给人以精神的力量,给人以信心和勇气!我们踩坑缺的不就是这个么?
然后,你就在遇到问题->解决问题->新问题->解决问题->新问题…的跌宕起伏中,被希望和失望反复折磨!
相信我,能这样折磨你的,除了你的初恋,就只剩下升级Taro这件事了。
这篇教程可以做为优秀的励志技术类文章范文!
我只读类第一段,然后就开始了。 后面的两段遇到问题后回头看过,看不懂,等于没有看,怪自己。
对于学有余力的同学,可以再看看Taro 版本升级权威指南, 大佬(隔壁老李)写的,还是挺深入的。 这篇我也没有仔细看过, 主要是看不懂。
升级完后回头看,泪两行!
1. 升级package.json
这是第一步,非常重要,建议老老实实按照最后一句的做法去做!
从旧版本迁移到 Taro Next 这篇文章有告诉你怎么升级主要的packages。我告诉你,这是不够的。
- 因为Taro 3里面有新的preset,
babel-preset-env
不用了, babel-preset-taro, 需要添加到devDependencies
里面去。 而Taro 2依赖的一些devDependencybabel-plugin-transform-runtime
不需要单独配置了,还有一些devDependency被废弃,不移除会导致编译器不正常工作. @taro/mobx
已经不支持了,要换成mobx
和mobx-react
regenerator-runtime
这个坑人,要去掉.- …
搞来搞去,你会陷入试错的汪洋大海之中,到最后,你也搞不清楚哪个包是对的,哪个是错的。
你会和我一样,绕来绕去,浪费大把的青春时光, 本应该把妹,晒太阳的,却被迫摸键盘,面对冰冷的机器,遭受无情的嘲笑,还搞不定。
最后怎么搞? 老老实实,新建一个Taro 3模板项目,把里面的package.json拷贝过来,覆盖,然后把自己的依赖一项一项添加。 相信我,这样做笨了点,但管用,能减少无意义的生命浪费。
##babel.config.js 从上面新建的模板项目里直接拷贝过来,什么也不用改。
2. 替换config/index.js
这个配置文件改动非常大,坑了我非常多时间。
从模板项目里面拷贝config/index.js覆盖,注意,是覆盖! 然后再想办法把自己需要的配置加回来。
到这里,大概率应该就可以运行yarn dev:weapp
进行编译了,是不是很Happy?
别高兴太早! 后面还有更坑人了,后面的坑编译器都不吱声, 静静等着你。
3. 所有的Taro.Component替换为React.Component
Taro不再自己封装React/Nerv/Vue等框架了,需要把所有import {Component} from "@tarojs/taro"
替换为 import {Component} from "react"
.
4. 修改src/app.jsx
这个地方我挺惊讶的,Taro启动方式变了,这么重要的事情, 官方升级文档好像没有说明。
针对app.jsx
, 除了Component
的替换外,还需要以下两处非常重要的改动:
- 删除文件最后一行
Taro.render(<App />, document.getElementById('app'))
- 添加一行
export default App
要不然,你就拼命挣扎吧!
5. import React
这是一个很神奇的bug, 在编译的时候代码不抛错,你也没有直接引用React
, 但是,你得import React from "react"
, 要不然运行的时候会抛错, 找不到React。
你需要在每个页面顶部加下面一句, 保平安:
import React from "react"
6. mobx升级
如果你用到了mobx, 你得
- 把包
@tarojs/mobx
替换成mobx-react
import { observer, inject } from '@tarojs/mobx'
替换成+import { observer, inject } from 'mobx-react'
- app.jsx:
import { Provider } from '@tarojs/mobx'
import { Provider } from 'mobx-react'
- app.jsx:
<Provider store>
替换成<Provider {...store} >
. 这个根据你自己的实际情况调整.
6. 导出页面config
taro 3不认内嵌的config了,需要把config提到单独的文件里面去。
把页面里下面的内容:
// src/pages/settings/settings.jsx
config = {
navigationBarTitleText: '设置',
enablePullDownRefresh: true,
onReachBottomDistance: 50,
usingComponents: {
}
}
抽到单独文件
// src/pages/settings/settings.config.js
export default {
navigationBarTitleText: '设置',
enablePullDownRefresh: true,
onReachBottomDistance: 50,
usingComponents: {
// "van-image": "../../components/vant-weapp/image/index"
}
}
做完上面的几步,大部分坑会消失。
问题流水账
接下来开始记流水账了。 把所有我遇到的报错记录下,然后提供对应的解决方法,仅供参考。同一个问题,不同的环境,原因也会不一样,解决方法也会有差异。
每个标题就是出错提示。下面有对应的解决方法。
Support for the experimental syntax ‘jsx’ isn’t currently enabled.
错误提示: Support for the experimental syntax 'jsx' isn't currently enabled.
这个是因为Taro preset的问题,babel配置的问题。
解决办法:
- 从模板项目里面拷贝
babel.config.js
到老项目里面去. - 如果还有问题,注意按照安装步骤里面说的,把
package.json
覆盖一遍, 然后config/index.js
覆盖一遍。
// babel.config.js
// babel-preset-taro 更多选项和默认值:
// https://github.com/NervJS/taro/blob/next/packages/babel-preset-taro/README.md
module.exports = {
presets: [
['taro', {
framework: 'react',
ts: false
}]
]
}
缺少 app 全局配置,请检查!
错误提示: 缺少 app 全局配置,请检查!
原因: 3.0.2 版本需要把全局配置信息写到 app.config.ts 文件中,而不是直接写在app.jsx 文件中。
解决办法就是把app.jsx里面的config写入到app.config.js里面去, 直接export default
配置内容就可以了:
// app.config.js
export default {
pages: [
'pages/index/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: 'black'
}
}
Support for the experimental syntax ‘decorators-legacy’ isn’t currently enabled
错误提示: Support for the experimental syntax 'decorators-legacy' isn't currently enabled
package.json
升级和config/index.js
配置升级的问题,参考升级流程1、2。
Cannot read property ‘onShareAppMessage’ of undefined
出错提示: Cannot read property 'onShareAppMessage' of undefined
解决办法:
走一遍升级流程3、4.
Cannot read property ‘mount’ of undefined
出错提示: Cannot read property 'mount' of undefined
原因分析: Taro 2架构为编译型架构,也就是编译期就绑定React的引用了. Taro 3为运行时架构,编译器不绑定React, 运行时绑定。所以,你要在代码里面显示import React
, 无论你页面是否有显示引用React
. Taro 架构参考Taro 版本升级权威指南.
大家如果对Taro加载逻辑感兴趣,可以测试断点函数common.ts-> mount
进行调试.
解决办法, 在页面的顶部加入下面一句:
import React from "react"
Error: MobX injector: Store ‘lessonStore’ is not available! Make sure it is provided by some Provider.
出错提示:
Error: MobX injector: Store 'lessonStore' is not available! Make sure it is provided by some Provider.
原因分析:
Mobx provider的绑定发生了变化,不自动展开store了。
解决办法:
app.jsx: <Provider store>
替换成 <Provider {...store} >
.
ReferenceError: React is not defined
出错提示:
运行时抛ReferenceError: React is not defined
错误.
解决办法, 在每个页面的顶部加入下面一句:
import React from "react"
react.ts:54 TypeError: Object(…) is not a function
出错提示:
在一个纯函数页面里,抛错react.ts:54 TypeError: Object(...) is not a function
.
原因:
React很多类型定义是在运行时绑定。
解决办法:
- 在每个页面的顶部加入下面一句:
import React from "react"
- 把
import {useState, useEffect} from 'react'
替换为import {useState, useEffect} from '@tarojs/taro'
页面配置不起作用,标题不对
原因, config要独立到xxx.config.js里面去。
解决办法, 参考升级流程步骤6.
Error: module “pages/about/about.js” is not defined
这是一个Taro里面的常量,或者说是宏替换的问题,叫常量有误导性,容易踩坑, 我就是这么进坑的。
这个坑大部分人应该不会踩。我记录下来是想告诉大家一个调试的思路。
这个页面看上去一切正常,没有什么语法问题。 编译完也没问题。 运行的时候就是没法正常加载这个页面,提示有一个什么unexpected token :
, 我把页面里面所有可疑的:
都尝试改了一下,不能解决问题。
折腾了很久,无果。
后来, 查看了一下编译后的文件,发现了下面诡异的东西:
// 编译后的about.js
this.state={
contact: 联系地址: xxxxxx
}
编译前是这样的:
// about.jsx
this.state = {
contact: CONTACT_INFO
}
CONTACT_INFO
是一个常量(宏), 赋值为'联系地址: xxxxxx'
, 看上去很正常的一个字符串。
坑出来了,Taro替换的时候会把CONTACT_INFO的值的最外层引号去掉,然后再引用它的地方替换,于是就出现上面的运行时错误。
这个坑我踩了两次。
解决办法: 给CONTACT_INFO
再套一层双引号: '"联系地址: xxxxxx"'
我记录这个问题不是要喷这个常量替换有多容易踩坑(立个flag, 这个坑是新人必踩的), 我是想说,不要总盯着原文件改问题,大胆地看一看编译后的内容,可能会有惊喜。
最后
个人精力有限,细节难以非常详述,更欢迎大家在微信群里讨论。
祝Taro越来越好,国产的这么棒的东西,值得支持!
参考
没有太多参考,都是摸索出来的,taro的资料还是有点少。 享受一下自主踩坑的乐趣吧。