React Native 的出現,讓前端工程師擁有了使用 JavaScript 編寫原生 APP 的能力。相比以前的 Web app 來講,對於性能和用戶體驗提高了很是多。html
可是 React Native 的代碼只兼容兩個平臺(iOS 和 Android),並無兼容 Web 端訪問。這裏是由於 Facebook 開發人員認爲 Web 端天生兼容性就巨麻煩,並且平臺差別性是註定存在並且也要保留的,因此 React Native 的目標是 Learn once, write anywhere
,而不是 Write once, run anywhere
。前端
然而 Write once, run anywhere
又是一個剛需。從產品仍是用戶的角度試想一下,APP 的安裝成本仍是很高的,如何讓用戶立刻體驗到你產品的功能再決定是否要安裝?此外,尤爲是重要的產品,除了 APP 客戶端以外,還要有一套兜底的 Web 端以便用戶在某些特殊場景下使用。React Native 可讓你寫一份代碼跑在兩個平臺,可是你卻還要再寫一份 Web 的如出一轍的應用。就顯得十分蛋疼了。react
因而 React web 就出現了。android
簡單的一句話描述 React Web 就是:它幫你把 React Native 的組件作了一個 Web 端的實現,並提供相關打包工具,讓你能夠直接打包出一份能夠跑在 Web 端的代碼。webpack
爲了重點突出轉換過程,這裏使用 React Native init 的最簡 Demo 來作實驗(名字叫 Awes 代碼在 https://github.com/yujiangshui/react-web-example )。React Web 已經把 React Native 比較複雜的 UI Explorer Demo 跑起來了,因此只要你的代碼能跑在 iOS 或者 Android 上面,你基本不用擔憂有什麼組件上的問題。固然若是有,能夠立刻提 Issue 過來,咱們有一個小組在支持 React web :)。ios
這一步操做主要是安裝 react-web
包以及相關依賴,並配置 webpack 打包腳本等。git
爲了簡化這一步操做,咱們開發了命令行工具 react-web-cli
只須要執行兩行命令便可。同時命令行工具還支持啓動調試服務器、打包等功能,在後面介紹。github
安裝 cli 工具:web
npm install react-web-cli -g |
安裝配置 React web 等:npm
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 端也測試好了,就能夠打包發佈了。react-web-cli
工具打包的命令是:
react-web bundle |
打包完成後,文件會存放在 web/output/
目錄下面,能夠直接打開 index.html
(若是 app 有請求操做,須要起本地服務器查看),再檢查一下就能夠發佈了。
好奇的同窗看到這裏可能會有一些疑問,上面命令行工具的一些命令作了什麼事情?爲何 React web 將 React Native 代碼打包出一份用在 Web 端的代碼?React web 安全可靠嗎,裏面都是什麼東西?
這裏簡單的介紹下 React web 的實現原理和上面步驟實際作的事情。
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
組件:
<span>
標籤便可,因此 React web 的實現 就直接搞一個 <span>
標籤,綁一些事件什麼的就 OK 了。在 UI Explorer demo 中能跑起來的 React Native 組件,你均可以放心的用。
作出了兼容 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
的保持一致便可讓代碼不替換也能夠工做。
此外配合插件還能夠實現另一種引入方法,請看下面。
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 的命名規則肯定文件)。
在 Web 端兼容性是個很是麻煩頭疼的事情,React Web 已經盡力幫你抹平兼容性問題和代碼差別,儘量的讓你減小改動就能夠建立 Web 版本的應用。但受限於 Web 端的一些固有限制(好比請求跨域),不可避免的就會有一些須要你改代碼的地方。
爲此,能夠經過 if (Platform.OS == 'web')
的方式判斷目標平臺,並針對性的作一些平臺兼容性處理。一樣的,也能夠將 web
替換爲 ios
或者 android
判斷其餘平臺。
在 React web 官方文檔上面已經列出來了一些平臺差別問題,這裏就再也不贅述了。
歡迎踊躍嘗試,遇到問題能夠隨時提 Issue 哦:)