15

Taro2.x 跨端开发实践

 3 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzI1NDc5MzIxMw%3D%3D&%3Bmid=2247491037&%3Bidx=1&%3Bsn=3bd13db27e02e0e7291c4dff9841a51b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

导读

随着业务的快速发展以及要拓展在线渠道至APP、小程序以及M站。与此同时,用户数量的上升需要优化前端的性能和用户体验。本文主要介绍业主业务如何利用Taro2.x实现跨端来进行业务的快速迭代。

背景

业主业务之前一直是以h5的形式嵌入安居客和58app中的,用户如果需要自己发布卖房信息或者委托经纪人,是只能在app中操作的。
为了达到以下三个目标:

  1. 提高用户体验

  2. 需要将发房渠道扩展到小程序和M站

  3. 节约成本和减少重复性劳动

我们尝试进行跨端开发(React Native、小程序和H5)。

对市面上主流小程序框架来进行了对比:

MjyaUr6.jpg!mobile

  1. 支持React Native、小程序和H5的只有Taro和uni-app

  2. 安居客小程序是以Taro开发的,提供了宿主环境给到各业务方使用,以及公司内部有MPS CLI(WuBa MiniProgram for Standardization,小程序全端跨平台开发解决方案)

考虑到时间成本以及技术体系,最终我们选定Taro来进行尝试多端开发。

Taro[2.x]的官方文档是这样写的:

使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信 / 京东 / 百度 / 支付宝 / 字节跳动 小程序、快应用、H5、React-Native 等)运行的代码。

看完文档以为跨端开发是这样的:

e226Zzj.jpg!mobile

但,实际上是这样的:

VNbeY3.jpg!mobile

虽然官方说了支持RN,但是对应的 各端开发前注意-React Native 是最多的,显然利用Taro编译Rn,需要的前置条件相比小程序和H5来说是比较多的。

我们在实践过程中,遇到了以下的问题:

  1. 官方提供的RN 0.59.9版本与安居客和58app不兼容

  2. taro有些api在Rn端是依赖原生模块的,而这些模块在安居客58app没有集成

  3. 样式问题,RN对css的样式支持度很低

  4. jsx语法限制,由于小程序的限制,有些写法可能在rn和h5端没有问题,但是小程序端会报错

  5. RN端能力不足

  6. Taro官方组件库TaroUI不支持RN

在解决问题之前,我们大概了解下Taro是如何将一套代码编译成可运行在多端的

Taro框架原理

Taro是一个编译时框架,采用的是编译原理的思想,是对输入的源代码进行语法分析,语法树构建,随后对语法树进行转换操作再解析生成目标代码的过程。

Taro1.x编译构建系统是taro自研的:

FBvQ3uV.jpg!mobile

在2.x时,则是将各端编译器剥离,CLI只做区分编译平台、处理不同平台编译入参等操作,随后再调用对应平台的 runner 编译器 做代码编译操作,而原来大量的 AST 语法操作改造成 Webpack Plugin 以及 Loader,交给 Webpack 来处理。

Taro2.x:

7NN7nqF.png!mobile

解决问题

1. 官方提供的RN 0.59.9版本,安居客和58app不支持

这个问题只能修改Taro自身的RN版本,修改成安居客和58app支持的对应版本

2. taro有些api在Rn端是依赖原生模块的,而这些模块在安居客58app没有集成

RN开发时,如果你用了依赖原生模块的方法,而这个模块原生没有集成,那么就会出现红屏警告。

针对上面两个问题我们选择了私有化Taro Cli来进行解决:

我们是基于Taro2.2.6版本开发的,为了使Taro兼容58RN工程我们对源码做了以下改造:

  1. @tarojs/cli修改react-native版本

  2. @tarojs/helper、@tarojs/taro-rn、@tarojs/rn-runner修改cli依赖,删除安居客、58不支持的原生依赖(expo)

修改后上传到了58npm,然后在项目的.npmrc中添加对应的registry

上面两个问题解决后,就可以进行RN的开发了:

整个 RN 端的开发流程如下:

j6jyEjm.jpg!mobile

执行yarn dev:rn,Taro会先编译成RN代码放在rn_temp下,再通过metro server启动服务打包rn_temp下的js文件生成jsbundle,就可以在app通过127.0.0.1:8081访问rn页面。

那么这里来解决第三个问题: 3. 样式问题,RN对css的样式支持度很低

这是官方的开发注意说明:

样式上 H5 最为灵活,小程序次之,RN 最弱,统一多端样式即是对齐短板,也就 是要以 RN 的约束来管理样式,同时兼顾小程序的限制,核心可以用三点来概括:

  • 使用 Flex 布局

  • 基于 BEM 写样式

  • 采用 style 属性覆盖组件样式

RN 中 View 标签默认主轴方向是 column,如果不将其他端改成与 RN 一致,就需要在所有用到 display: flex  的地方都显式声明主轴方向。

那么这里怎么将RN的样式区分出来呢?

Taro是有提供样式的条件编译:

yqI3iaq.jpg!mobile

但实际使用时,2.2.6 样式文件条件编译*.rn.scss不起作用,文件内条件编译是可以的,但是编译时会有警告。

因为2.x里用的都是webpack,这里直接用 webpack.NormalModuleReplacementPlugin来进行修改,将RN的样式剥离出来,这样编写样式时就能以RN为基准来进行编写。

webpackChain(chain, webpack) {
chain.merge({
plugin: {
NormalModuleReplacementPlugin: {
plugin: new webpack.NormalModuleReplacementPlugin(
/\.scss/,
function (resource) {
let isReplace = true;
for (let i = 0; i < BUILD_TYPE.length; i++) {
const ext = BUILD_TYPE[i];
if (resource.request.indexOf(`.${ext}.scss`) > -1) {
isReplace = false;
break;
}
}
const replaceStr = resource.request.replace(
/\.scss/,
`.rn.scss`
);
if (
fs.existsSync(resource.context + '/' + replaceStr) &&
isReplace
) {
resource.request = replaceStr;
}
}
),
},
},
});
},

在index.scss中直接@import ./index.rn.scss,然后补充小程序和h5支持的如fixed等css属性。

还有一个问题是,Taro处理样式文件时,每个样式文件都会有这样一个函数:

// 一般app 只有竖屏模式,所以可以只获取一次 width
const deviceWidthDp = Dimensions.get('window').width
const uiWidthPx = 375


function scalePx2dp (uiElementPx) {
return uiElementPx * deviceWidthDp / uiWidthPx
}
}

然后将10px替换成scalePx2dp(10),这样就会发现在iPhone 6 和6Plus上的字体大小是不一致的,会根据屏幕来进行等比缩放的

但在业主项目中,UI规范是要求字体大小、宽高不根据屏幕进行缩放,h5不要使用rem,所以需要通过修改postcss-pxtransform、rn-runner 和Taro.pxTransform

怎么样修改node_modules中的代码呢,一般是私有化,但也有很方便的方法。

我们可以直接使用 patch-package 修改node_modules中包的源码

然后在package.json中添加:

 "scripts": {
+ "postinstall": "patch-package"
}

N7ZrMfV.jpg!mobileUNv2eq6.jpg!mobileRjqY7fN.jpg!mobileZ3MV7nQ.jpg!mobile

其中在rn中是将className处理成style的,覆盖组件样式可以通过style传递,但style可能是数组,这点需要注意下。

4. jsx语法限制, 由于小程序的限制,有些写法可能在rn和h5端没有问题,但是小程序端会报错

由于小程序的限制,有些写法可能在rn和h5端没有问题,但是小程序端会报错,所以使用Taro编写代码时需要遵循 Taro的最佳实践

5. RN端能力不足

6. Taro官方组件库TaroUI不支持RN

Taro提供的组件和Api相对比较基础,通用性更强,但基本都是以小程序提供的api为基准,适配到h5和rn,在rn端是利用Expo进行支持的,但是58和安居客app端并没有集成对应的依赖,所以需要利用app端已有的功能进行封装,抹平业务中的平台判断。

例如rn中的请求Request是必需的API,利用原生Module提供的Request进行支持:

新增rn-request.ts:

import { NativeModules } from 'react-native';


declare type RequestData = {
method: string;
url: string;
params: any;
};


export function fetch(requestData: RequestData): Promise<any> | null {
return new Promise<any>((resolve, reject) =>
NativeModules.HTTPModule.Request(
requestData,
(response: any) => {
resolve(response);
},
(error: string) => {
reject(error);
}
)
);
}

在fetch.ts中:

export default async function fetch(options: RequestParams) {
const {
url,
data = {},
method = 'GET',
header = {},
credentials = 'include'
} = options;
try {
let result;
if (process.env.TARO_ENV === 'rn') {
result = await require('./rn-request').fetch({
url,
method,
params: data || {},
});
} else {
result = await Taro.request({
url,
method,
data,
header,
credentials,
});
}
...
// do somethine
...

业务中使用到的业务组件如picker、modal等,不同端的Api如登录、跳转等需要我们自行封装。

使用条件编译来抹平不同端的差异:

if (process.env.TARO_ENV === 'weapp') {
// 微信小程序端执行逻辑
} else if (process.env.TARO_ENV === 'h5') {
// h5 端执行逻辑
} else if (process.env.TARO_ENV === 'rn') {
// react-native 端执行逻辑
}

发布:

MbYZ7fz.jpg!mobile

Rn是利用58的rn热更新平台进行打包,所以需要将rn_temp下的文件推送到特定分支,比如rn_deploy,然后在热更新平台配置仓库地址、分支,进行构建ios和安卓包。

M7raEvU.jpg!mobile小程序则是作为分包接入安居客微信小程序中,利用58的小程序全端跨平台开发解决方案MPS CLI发布。

Qr2yimy.jpg!mobileH5的还是走云平台部署流程。

最终实现的效果:

yYJBzmf.jpg!mobile

总结与展望

我们利用Taro开发了新版房贷计算器、业主频道、业主直卖表单和管理详情页,以及正在开发的业主房源管理页等。
达到了我们的目标:

  1. 提高用户体验

  2. 需要将发房渠道扩展到小程序和M站

  3. 节约成本和减少重复性劳动

但在实践中,踩了不少坑,在开发业务的同时需要针对api和组件进行底层封装、Taro框架调整,以及样式适配ios、安卓、小程序和h5,实际业务开发时间比开发H5相同需求多了1倍左右。

目前跨端开发还处于摸石头过河的阶段,多端统一的组件、sdk积累较少,在组件库、sdk丰富完善后,可以抹平各端差异,开发效率基本接近目前小程序、h5开发情况。

目前在和app同学一起补全RN的端能力,推动app、小程序的底层api和组件的统一,实现业务开发无需关注各端差异,专注于业务本身,高效开发。理想情况下,使用Taro编写的业务代码可以无缝对接到多端。

作者简介:

祝求智:房产事业群--用户前端开发部,前端开发工程师

参考文献:

  1. https://taro-docs.jd.com/taro/docs/2.x/README

  2. https://aotu.io/notes/2020/01/08/taro-2-0/

  3. https://aotu.io/notes/2018/06/07/Taro/

福利环节

为了鼓励优质内容传播,【58技术】公众号近期会持续推出不定期活动奖励。

  1. 评论区互动留言,即可参与此次活动

  2. 留言转发集赞,点赞量前三名(点赞数需大于10)可获得定制版新年代码台历一本

  3. 活动时间:截至2021年1月15日

FZBre2Q.jpg!mobile

Nb2iMvQ.jpg!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK