JavaScript的React Web庫的理念剖析及基礎上手指南_其它

來源:互聯網
上載者:User

React Web的目的及意義非常明確: 讓React Native代碼跑在Web上 讓一套代碼運行在各個移動終端,對前端及業務來說,這是開發效率中一個質的提升。在項目初期,我們也曾向 React團隊諮詢過類似的問題,他們團隊的核心同學 @vjeux 也認為這是非常酷的事情,也是他們未來想做的事情。也許在發布React Native for Android的時候,也會發布React Web也說不定。(YY一下)
技術架構
基於React Native的適配方案,有幾個:
1.制定一個Bridge標準,RN與RW 各自用最優的方式實現這套標準。
比如基於Flex布局,我們實現一套一致的 Flex Component, <Flex> 、<Cell> 等。
2.完全向RN看齊,RW實現RN的所有能實現的API。
在討論中,最終選擇了後者。
因為React Web的理念,讓React Native代碼跑在Web端,那麼就決定了RW只是一個構建及打包工具,脫離RN,RW的實現則沒有太大的意義,那麼整體的技術方向就非常明確了: 實現RN一致的Style、Component及API,最終通過構建工具編譯成web版本。

樣本

下面我們來看一下React Web項目的建立過程:
第一步:安裝 React web 並進行相關配置
這一步操作主要是安裝 react-web 包以及相關依賴,並配置 webpack 打包指令碼等。
為了簡化這一步操作,我們開發了命令列工具 react-web-cli 只需要執行兩行命令即可。同時命令列工具還支援啟動調試伺服器、打包等功能,在後面介紹。
安裝 cli 工具:

npm install react-web-cli -g

安裝配置 React web 等:

react-web init <當前項目目錄>

執行完成之後,會在你項目目錄下面 npm install 相關庫,並自動建立 web/webpack.config.js 檔案,裡面有一份寫好的配置。此時目錄結構為:

.├── README.md├── android/├── index.android.js├── index.ios.js├── ios/├── package.json└── web/ └── webpack.config.js

第二步:添加入口檔案並進行相關配置
每個項目都需要有一個入口檔案,通常用來引入調用其他組件並初始化項目,比如 index.ios.js 表示 iOS 平台上的該項目的入口檔案。為了符合 React Native 的檔案命名規範,我們建立一個 index.web.js 作為入口檔案,並且需要在 webpack 中指定該檔案為入口檔案。開啟 web/webpack.config.js 檔案,修改 config 變數:

var config = { paths: { src: path.join(ROOT_PATH, '.'), index: path.join(ROOT_PATH, 'index.web'), },};

然後我們建立 index.web.js 檔案。這個檔案其實跟 index.ios.js 非常像,只是略有不同。主要區別在於:iOS 只需要 AppRegistry.registerComponent('Awes', () => Awes); 即可讓 Xcode 的 Native 代碼接收處理你的 JS 代碼,而 Web 端是需要插入到 DOM 節點中才可以用。因此我們需要在 index.web.js 最下面添加如下代碼:

AppRegistry.registerComponent('Awes', () => Awes);if (Platform.OS == 'web') { var app = document.createElement('div'); document.body.appendChild(app); AppRegistry.runApplication('Awes', { rootTag: app });}

然後在最上面 require 部分需要引入 Platform 組件。這樣配置部分就已經處理完成了,執行 react-web start 命令即可啟動調試伺服器啦!

可以隨便修改試下,跟 React Native 模擬器裡面的體驗幾乎一樣。
第三步:測試並打包 Web 版本代碼
當你修改開發完,並對 Web 端也測試好了,就可以打包發布了。react-web-cli 工具打包的命令是:

react-web bundle

打包完成後,檔案會存放在 web/output/ 目錄下面,可以直接開啟 index.html (如果 app 有請求操作,需要起本機伺服器查看),再檢查一下就發行就緒了。
這個過程中發生了什嗎?
好奇的同學看到這裡可能會有一些疑問,上面命令列工具的一些命令做了什麼事情?為什麼 React web 將 React Native 代碼打包出一份用在 Web 端的代碼?React web 安全可靠嗎,裡面都是什麼東西?
這裡簡單的介紹下 React web 的實現原理和上面步驟實際做的事情。
React Web 將 React Native 組件做了 Web 端的實現
React 將代碼與平台環境分離,多了一層,這樣開發人員可以在平台環境層面做一些處理,使得同樣一份代碼適應更多的平台環境等。
比如 react-canvas 按照 React 的文法書寫代碼,在平台環境層面做一些處理(將你 React 代碼運行並用 canvas 渲染),然後實現特定目標(在移動端提高效能)。
React Native 中,一份代碼能同時跑在 iOS 和 Android 上面,也是一樣的道理。React Native 團隊在對應平台的 Native app 上面做了一些處理,使其可以解析執行 React 文法的代碼。
還有同構(isomorphic)的應用,伺服器端使用 React + Node.js 產生 HTML,用戶端使用 React 擷取進行用戶端相關互動和功能,也是一樣的道理。
為此, React v0.14.x 版本開始,專門分成兩個庫 react 和 react-dom ,其實是把對瀏覽器平台的特殊處理剝離了出來,單獨變成了 react-dom 庫。
React Native 比較特殊的地方在於,組件最底層的實現是 Native 的實現,所以就不支援 span、div 等標籤。而動畫等,也是直接調用 Native 進行介面渲染。所以不支援 Web 端,但是絕大部分組件,都是可以用 Web 技術進行類比實現。動畫可以用 CSS3 、基礎元素可以用同等 HTML 標籤類比、布局以及相容性問題可以用 CSS 來處理,所以 React web 只需要把 React Native 的組件用 Web 技術重新實現一遍,藉助 React 這一層,即可實現一份代碼運行在多個平台上面。
舉一個非常簡單的例子,Text 組件:
React Native 的實現 是調用了很多 React Native 底層的代碼實現的。
對於 Web 端,輸出一行文本使用 <span> 標籤即可,所以 React web 的實現 就直接搞一個 <span> 標籤,綁一些事件什麼的就 OK 了。
在 UI Explorer demo 中能跑起來的 React Native 組件,你都可以放心的用。
webpack 幫你切換打包目標
做出了相容 Web 端的組件,那打包的時候豈不是要把所有要打包的組件中的 require('react-native') 全部更換成 require('react-web')?不然怎麼用的我的 Web 元件打包?
強大的 webpack 附帶了 alias 配置項可以幫你解決這個問題:

resolve: { alias: { 'react-native': 'react-web', 'ReactNativeART': 'react-art', }, extensions: ['', '.js', '.jsx'],},

這樣在打包時,但凡 require('react-native') 的地方全都用 react-web 包替換,而 react-web 的 module.exports 與 react-native 的保持一致即可讓代碼不替換也可以工作。
此外配合外掛程式還可以實現另外一種引入方法,請看下面。
通過 Haste 方法引入組件以提高效能
webpack 以及其他的支援 CommonJS 規範的打包工具,都會把檔案中 require 的所有組件都打包在一起。對於 React Native 來說代碼體積大小無關緊要,而在 Mobile web 來說,就要稍微重要一些了。特別是如果你的項目只需要 Text 組件,但由於 require('react-web') 結果把所有的組件全部打包進來了,就比較傷感。
基於 webpack 外掛程式,還可以用另一種方式引入組件以解決這個問題,你可以叫它 Haste 方式。使用這種方式需要載入 webpack 外掛程式 haste-resolver-webpack-plugin,預設的 webpack 配置已經幫你載入好了,你可以直接在組件裡面這樣用:

var Text = require('ReactText');

而不是以前那樣:

var {Text} = require('react-native');

這樣 webpack 打包時,對於前者,只會把那一個組件內容打包進來,因此可以減小體積、提升效能。這是怎麼實現的呢?
載入了外掛程式的 webpack 打包時,會先掃描所有組件並讀取組件頭部 @providesModule 的資訊(比如 Text 組件的資訊),然後當其他檔案中 require 了這個組件名稱,就會自動定位到這個檔案進行打包。同時還可以區分平台,即便是同一個名字,打包時會區分平台去打包對應的檔案(根據 index.xxx.js 的命名規則確定檔案)。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.