React-Native轉小程序調研報告:Taro & Alita


一. 我們的要求

期望的要求

  1. 基於React語法,將RN項目轉化為小程序項目

  2. 該小程序能同時在 微信小程序 和 支付寶小程序這兩個平台運行

底線要求

底線是能轉成微信小程序,因為目前來說,因為微信先發制人,再加上微信本身的用戶黏性,導致在小程序這一塊大多數其他平台都難以迎頭趕上,包括支付寶小程序,百度小程序,頭條小程序等等。

二. 目前可供選擇的生態,以及各自存在的問題

  1. 能將已有RN項目轉化為微信小程序的工具, 比如 Alita ,但它不能轉成支付寶或其他小程序

  2. 從零開發的多端框架,比如Taro(京東),chameleon(滴滴), uni-app等等,問題在於:很多框架,比如uni-app,chameleon是基於Vue語法的,無法適用我們React項目的情況

  3. 專門設計的微信小程序框架(mpvue,webpy) ,問題也是和上面類似,Vue的語法,而且只是針對微信小程序的

三. 最終的工具選擇:Alita && Taro

綜合我們對React語法的要求,以及對平台轉化的需求,最終覺得比較合適的有兩個工具/框架,分別是Alita 和 Taro

Alita介紹

  • Alita介紹:它是京東的ARES多端技術團隊,開發的React Native一鍵轉化為微信小程序的工具。不過只能轉成微信小程序,不能專成支付寶小程序

  • Alita的特性: Alita不是新的框架,也沒有提出新的語法規則,她只做一件事,就是把你的React Native代碼運行在微信小程序端。所以Alita的侵入性很低,選用與否,並不會對你的原有React Native開發方式造成太大影響。

Taro 介紹

  • Taro介紹:它是由京東凹凸實驗室開發的多端框架

  • Taro的定位:它和Alita不同,不是既有項目的轉化工具,而是從零開始開發的多端框架。

  • Taro特性:使用 Taro,我們可以只書寫一套代碼,再通過 Taro 的編譯工具,將源代碼分別編譯出可以在不同端(微信/百度/支付寶/字節跳動/QQ小程序、快應用、H5、React-Native 等)運行的代碼。

四. Alita && Taro 的調研總結

改造成本的對比

我們上面說了,Alita是將既有的React-Native項目轉化為微信小程序框架的工具,那么它是不是輕輕松松就能實現一鍵轉化呢? 其實不是的,Alita也要求你要完全遵循它的語法規則才能轉化成功,否則那個文件將不會轉化,這就需要對原有項目進行改造了
Taro自然也是這樣了,因為它本身就是一套多端框架,也需要修改成它的代碼規范才能運行

綜合對比

 

五. 采用 Alita 方案的改造思路

Alita可以通過運行下面命令的方式基於已有的RN項目生成一個新的小程序項目
alita -i rnProject -o wxProject
不過問題在於,必須要修改代碼以符合Alita的轉化條件(一開始想着能一鍵轉化,空手套小程序的我還是太單純了。。)

 

問題復現: 如果不對原有代碼改造就轉化會怎樣?

1.根據官方案例提供的example,原本目錄c下有一個文件:index.js,正確打包后如下圖所示
 
2.我這里寫入一個Alita禁止的寫法: 使用as關鍵字

 

// 修改前的 good style 
import React, {Component } from 'react';
// 修改后的 bad style
import React, {Component as BadComponent} from 'react';
export default class C extends BadComponent { 

}

 

 

原本打包后c目錄下原本有文件的,現在啥都沒有了
 
 
3.也就是說項目中一定不能有上面所講的Alita禁止的寫法,必須要進行轉化
 

借助eslint排查和修改不符合alita風格的代碼

首先我們要把Alita提供的eslint插件導入項目,把不符合Alita要求的代碼風格改掉,我們來看下eslint有哪些規則
 

Alita轉化前代碼風格修改流程

注意一個問題:並不是所有有問題的代碼風格alita的eslint插件都會做提示,實際上,它只會對80%的有問題的代碼報出警告,所以有部分代碼風格我們是要手動發現和修改的。所以我把問題分成了三類,分別按三種方式處理

A類問題

這些不符合eslint的代碼是會有警告的

解決辦法:逐個文件過一遍,把警告消除就好
  • 高階組件限制,也就是路由深度不大於5層

  • 動畫組件要使用alita的

  • 靜態限制

  • global變量不允許使用

  • 一個文件最多只能定義一個組件

  • React Native基本組件不支持屬性展開

  • this.props.xxComponent 要寫完全

  • 使用高階組件

B類問題

這些問題,eslint插件沒有提示,同時根據我們的使用習慣,有可能會這樣用的代碼風格

解決辦法:下面的大多數問題,都可以通過搜索的方式,找出問題並解決
備注:下面的“(數字)”在 參考資料中找到對應的條目,查看細節解釋
  • 路由組件需要用@areslabs/router

  • ref 必須是方法,不支持字符串

  • 不支持 onLayout 方法

  • 代碼體積限制:壓縮的代碼小於 4M,分包 8M,大於的話就不行

  • 函數組件在定義時候沒有同時導出

C類問題

這些約束,eslint插件沒有提示,但是我們一般都不會這么寫,除非作死

解決辦法: 發現有問題再來排查
備注:下面的“(數字)”在 參考資料中找到對應的條目,查看細節解釋
  • for循環中返回組件,key不指定

  • 作為props的組件進行多層級傳遞

  • 從外部引用JSX片段

alita自身也在不斷改進它的轉化限制

 

六. 采用 Taro 方案的改造思路

問題列表(Problem)

Taro其實也有一個叫eslint-config-taro 的eslint插件幫助檢查各種不符合Taro要求的代碼風格,總結如下

改造難度從上往下遞減,上面難,下面簡單

  • P1. Animation, 原生平台組件和第三方組件Taro是不支持的,需要尋找方法規避轉化問題

  • P2. 設計稿的單位,尺寸匹配問題等問題需要修改解決的思路

  • P3. RN用的樣式編碼方式和引用方式需要修改

  • P4. 路由系統要修改為Taro自帶的路由系統 和 API

  • P5. 網絡請求要修改,fetch/Ajax 等原生的要改成Taro的Taro.request這一API

  • P6. 引用圖片、音頻、字體等文件的方式要改

  • P7. 部分RN樣式屬性值Taro是沒有的,而且部分樣式屬性的默認值RN和Taro不一致

  • P8.因為小程序的特殊需求,導致部分代碼不符合Taro的編碼規范,總結如下

  • P9. aync/await的使用要通過導入taro的包來開啟

  • P10.redux的使用改為 @tarojs/redux

解決思路

P1. Animation, 原生平台組件和涉及前兩者的第三方組件,這三者Taro是不支持的,需要尋找方法規避轉化問題
解決思路
  • 如果是小范圍的改動,可以通過平台變量process.env.TARO_ENV去規避(值有 weapp/alipay/h5/rn)

  • 如果是大范圍的改動,可以通過腳本后綴名差異的方式區分小程序和RN平台(xxx.weapp.js和xxx.js)

P2. 設計稿的單位,尺寸匹配問題等問題需要修改解決的思路
  • 設計稿的單位要修改, Taro似乎不支持純數字的長度,所以要改成rem或者Px

  • 設計稿尺寸匹配問題,Taro默認是根據750的設計稿匹配的,可以在配置文件的designWidth屬性中進行修改

  • 如果是行內長度樣式,那么要做手動轉換:Taro.pxTransform(10)

P3. RN用的樣式編碼方式和引用方式需要修改
  • RN是通過向style中導入對象的方式引入樣式,而Taro是通過className結合import樣式文件的方式引入樣式

  • RN的屬性命名方法是駝峰,而Taro是短橫線

react-native的樣式編碼方式

class App extends React.Component {
  render () {
    return ()
  }
}
 
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#000',
    opacity: 0.6
  }
})

 

Taro的樣式編碼方式(類似傳統的CSS編碼方式)

// index.js
import "index.css"
class App extends React.Component {
  render () {
    return ()
  }
}
// index.css
.bar {
  height: 10Px;
  background-color:'10px'
}

 

P4.路由系統要修改為Taro自帶的路由系統 和 API

比我們可能會選擇react-navigation模塊作為我們的導航工具,而我們需要改造成Taro自帶的
import Taro from '@tarojs/taro'
Taro.navigateTo(params).then(...)

 

P5. 網絡請求要修改,fetch/Ajax 等原生的要改成Taro的Taro.request這一API

import Taro from '@tarojs/taro'
 
Taro.request({
 url: 'http://localhost:8080/test',
 data: {  foo: 'foo' },
 header: { 'content-type': 'application/json' }
}).then(
 res => console.log(res.data)
)

 

P6. 引用圖片、音頻、字體等文件的方式要改 
  • RN用的是<Image source={...} />和<ImageBackground source />

  • Taro用的是<Image src={...} />

// 引用文件
import namedPng from '../../images/path/named.png'
// 使用
<View>
 <Image src={namedPng} />
</View>

 

P7. 部分RN樣式屬性值Taro是沒有的,而且部分樣式屬性的默認值RN和Taro不一致

  • 部分屬性值存在差異,例如marginVertical,paddingVertical等等,RN有,但是Taro沒有

  • 部分屬性的默認值存在區別,在RN中,flexDirection默認是column,而在其他的平台中,flexDirection默認是row

P8.因為小程序的特殊需求,導致部分代碼不符合Taro的編碼規范,總結如下
因為這些坑很少會主動踩到,除非作死
(1)事件參數(props)都要以on開頭
// 錯誤
const element = <View bindtap={this.onTag} />
// 正確
const element = <View onClick={this.onTag} />

(2)不能對this.props.children做任何操作

// 錯誤的兩種寫法
this.props.children && this.props.children
this.props.children[0]

(3)不能使用 Array#map 之外的方法操作 JSX 數組

// 錯誤,JSX數組不能用非Map方法,普通數組才可以
const components = [<Component />...];
components.find(component => {
  return component === <View />
})

 

P9. aync/await的使用要通過導入taro的包來開啟

很簡單,不用考慮工作量
import '@tarojs/async-await' 
// 下面就可以正常使用async/await了

 

P10.redux的使用改為 @tarojs/redux
API似乎沒有變?應該是無需擔心了

參考資料

Alita官網 https://github.com/areslabs/alita 
Taro官網 https://taro.aotu.io/ 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM