React-Native轉小程式調研報告:Taro & Alita
一. 我們的要求
期望的要求
-
基於React語法,將RN專案轉化為小程式專案
-
該小程式能同時在 微信小程式 和 支付寶小程式這兩個平臺執行
底線要求
底線是能轉成微信小程式,因為目前來說,因為微信先發制人,再加上微信本身的使用者黏性,導致在小程式這一塊大多數其他平臺都難以迎頭趕上,包括支付寶小程式,百度小程式,頭條小程式等等。二. 目前可供選擇的生態,以及各自存在的問題
-
能將已有RN專案轉化為微信小程式的工具, 比如 Alita ,但它不能轉成支付寶或其他小程式
-
從零開發的多端框架,比如Taro(京東),chameleon(滴滴), uni-app等等,問題在於:很多框架,比如uni-app,chameleon是基於Vue語法的,無法適用我們React專案的情況
-
專門設計的微信小程式框架(mpvue,webpy) ,問題也是和上面類似,Vue的語法,而且只是針對微信小程式的
三. 最終的工具選擇:Alita && Taro
綜合我們對React語法的要求,以及對平臺轉化的需求,最終覺得比較合適的有兩個工具/框架,分別是Alita 和 TaroAlita介紹
-
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)
-
設計稿的單位要修改, Taro似乎不支援純數字的長度,所以要改成rem或者Px
-
設計稿尺寸匹配問題,Taro預設是根據750的設計稿匹配的,可以在配置檔案的designWidth屬性中進行修改
-
如果是行內長度樣式,那麼要做手動轉換:Taro.pxTransform(10)
-
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
// 錯誤 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/
&n