React Web:讓React Native代碼跑在Web上

jopen 9年前發布 | 113K 次閱讀 React Web

React Web:讓React Native代碼跑在Web上

說明:公司項目尚未開源,本文僅闡述實現方案,不涉及具體技術實現細節,見諒。

===============正文分割線=============

前言

非死book發布React Native 已有兩個多月,從開源初期我們就開始籌劃的React Web終于也有了一個V1版本。在這次618大促的兩個主會場中落地,實現了React Native代碼到web的轉換。

React Web的目的及意義非常明確: 讓React Native代碼跑在Web上讓一套代碼運行在各個移動終端,對前端及業務來說,這是開發效率中一個質的提升。在項目初期,我們也曾向 React團隊咨詢過類似的問題,他們團隊的核心同學@vjeux也認為這是非常酷的事情,也是他們未來想做的事情。也許在發布React Native for Android的時候,也會發布React Web也說不定。(YY一下) 

React Web:讓React Native代碼跑在Web上

技術架構

基于React Native的適配方案,有幾個:

  • 制定一個Bridge標準,RN與RW 各自用最優的方式實現這套標準。比如基于Flex布局,我們實現一套一致的 Flex Component, 等。

  • 完全向RN看齊,RW實現RN的所有能實現的API。

在討論中,最終選擇了后者。

因為React Web的理念,讓React Native代碼跑在Web端,那么就決定了RW只是一個構建及打包工具,脫離RN,RW的實現則沒有太大的意義,那么整體的技術方向就非常明確了: 實現RN一致的Style、Component及API,最終通過構建工具編譯成web版本。 

React Web:讓React Native代碼跑在Web上

技術細節

Style補齊

RN中主要依靠FlexBox方式進行布局,它與CSS中的flexbox有一些差異,但概念基本是一致的。

在Style兼容方面,組內的同學做了很多探索,整理了布局中的差異性與共性。 在《react-native與react-web的融合》、《react-native之布局篇》兩篇文章中有詳細的論述。

舉個2個例子:

Flex布局轉換

在RN中,使用Flex布局,只需要簡單使用flex: 1 即可完成Flex布局。而在Web端,則需要添加瀏覽器前綴,并給父級加上display:flex才能表現一致。

RN:

React Web:讓React Native代碼跑在Web上

轉換到Web

RW:

React Web:讓React Native代碼跑在Web上

Border轉換

RN :

React Web:讓React Native代碼跑在Web上

轉換到Web :

React Web:讓React Native代碼跑在Web上

Style的兼容,主要是Flex布局的兼容,其他都是比較小的細節點,沒有多大難度。

前期的原型demo

React Web:讓React Native代碼跑在Web上

component補齊

component補齊是件非常有意思的事情,相當于有個架構師幫你把接口定義好了,你只需要實現對應的接口行為就行。

有2個組件,是整個RW轉換最為關鍵,也是最有難度的組件:ScrollView、ListView 。剛好這方面,淘寶同學開發的xScroll與這兩個native組件的理念非常接近。并且xscroll本身的實現也參考了Native中UIScrollView的接口。

也舉個適配的例子:

Text組件中有個props numberOfLines 其表現的行為是多行文本截斷。

在web端,可通過css來控制:

React Web:讓React Native代碼跑在Web上

其最終比較效果: 

React Web:讓React Native代碼跑在Web上

View組件的效果,效果對比圖:

React Web:讓React Native代碼跑在Web上

API補齊

API的補齊,相對比較簡單,沒有太難實現的API,并且很多API均來自Web。比如:requestAnimationFrame、Promise。

其中比較特別的API:fetch。在Native中,是拉取json格式的數據。而在web端則會存在跨域的問題。在實現上,fetch不僅需要支持json,同時也要支持jsonp,對開發者透明。

對于系統級別的API,則返回空對象。

packager補齊

RN里實現了一套編輯及打包機制。這也是RW適配比較關鍵,同時也是技術難度比較大的一環。通過一致的構建,才能讓代碼無差異性。

在packager的實現上,@元彥同學在RN的基礎上,實現了一套一致的打包工具,將RN的代碼完美的編譯成web版本。

舉個例子:

在RN中,實現了一套require機制:可以不使用路徑就可require文件。

比如:

var Dimensions = require('Dimensions');

學過nodejs的都知道,Dimensions 如果不帶上路徑,則查找當前目錄和nodemodules包,而在RN中,Dimensions這個API并不在nodemodules里,而是在RN中的Libraries/Utilities/Dimensions.js中。

這種require方式,是在packager中通過DependencyResolver將所有文件讀入內存,再進行包名查找替換。

實際應用

本次天貓618大促中的預熱主會場及主會場,就是基于RN與RW的實現。無差異性運行在IOS平臺上。下圖是編譯后的2個版本:

React Web:讓React Native代碼跑在Web上

在實際的項目中,也暴露出一些問題:

  • 性能問題。在android機器上跑RW版本比較吃力。

    1. Flex布局本身(display: -webkit-box;)就是一個耗性能的css屬性,大規模使用在低端android下性能堪憂。

    2. 每個component都有其生命周期,在Web端,每個View都是一個component,導致在dom結構上,比原生reactjs實現復雜一倍,而reactjs調用mountComponent方法會帶來一定的性能損耗。也就是說,越復雜的頁面,性能約差。

  • 瀏覽器本身原因無法做到100%還原。比如RN中0.5px,0.3px的實現,在瀏覽器端除了iOS8外,其他web環境均不支持1px以下的數值。 

React Web:讓React Native代碼跑在Web上

  • 拋棄了web的大部分功能,同時無法使用web最佳的方式來優化代碼,而Native要照顧到web端的展示,也無法很好的使用一些特性,如上面說的0.5px實現。

  • 無法解決所有兼容性問題。用純web來寫頁面,也都會遇到瀏覽器間的兼容性問題,目前RW沒有提供一套寫Hack的機制來解決兼容性。感覺就像Chrome與IE6的對比,要完美兼容IE6,務必無法優雅的使用一些Chrome所支持的新特性。

還有一些其他的細節問題,后續會通過PPT的形式來分享給大家。

總結與思考

React Web的實現,其最大的難度在于性能優化。這也許是非死book不推崇write once, working anywhere的主要原因。

那么 RW的實現是否有意義,這取決于業務的側重點,如果80%的流量來源于APP,那么在web端,通過體驗降級來換來業務開發效率提升,我覺得是有其存在的意義的。

在業務層面上實現write once, working anywhere,在組件層面,可以使用各端最佳的方式實現,也未嘗不可。

這次618的嘗試,是個非常不錯的開始,后續天貓在RN中的探討,會更加深入,比如在React Native中添加Web的布局方式,讓開發方式更靈活。在開發規范上,兩邊會做一些平衡等。

來源:Hugo Web前端開發

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!