React Native 項目運行在 Web 瀏覽器上面

React Native 的出現,讓前端工程師擁有了使用 JavaScript 編寫原生 APP 的能力。相比以前的 Web app 來講,對於性能和用戶體驗提高了很是多。javascript

可是 React Native 的代碼只兼容兩個平臺(iOS 和 Android),並無兼容 Web 端訪問。這裏是由於 Facebook 開發人員認爲 Web 端天生兼容性就巨麻煩,並且平臺差別性是註定存在並且也要保留的,因此 React Native 的目標是 Learn once, write anywhere ,而不是 Write once, run anywhere 。 html

然而 Write once, run anywhere 又是一個剛需。從產品仍是用戶的角度試想一下,APP 的安裝成本仍是很高的,如何讓用戶立刻體驗到你產品的功能再決定是否要安裝?此外,尤爲是重要的產品,除了 APP 客戶端以外,還要有一套兜底的 Web 端以便用戶在某些特殊場景下使用。React Native 可讓你寫一份代碼跑在兩個平臺,可是你卻還要再寫一份 Web 的如出一轍的應用。就顯得十分蛋疼了。 前端

因而 React web 就出現了。java

React Web 介紹 

簡單的一句話描述 React Web 就是:它幫你把 React Native 的組件作了一個 Web 端的實現,並提供相關打包工具,讓你能夠直接打包出一份能夠跑在 Web 端的代碼。react

將 React Native 應用建立一個 Web 版的幾個步驟 

爲了重點突出轉換過程,這裏使用 React Native init 的最簡 Demo 來作實驗(名字叫 Awes 代碼在 https://github.com/taobaofed/demo/tree/gh-pages/react-web )。 React Web 已經把 React Native 比較複雜的 UI Explorer Demo 跑起來了 ,因此只要你的代碼能跑在 iOS 或者 Android 上面,你基本不用擔憂有什麼組件上的問題。固然若是有,能夠立刻提 Issue 過來,咱們有一個小組在支持 React web :)。 android

第一步:安裝 React web 並進行相關配置 

這一步操做主要是安裝 react-web 包以及相關依賴,並配置 webpack 打包腳本等。 webpack

爲了簡化這一步操做,咱們開發了命令行工具 react-web-cli 只須要執行兩行命令便可。同時命令行工具還支持啓動調試服務器、打包等功能,在後面介紹。 ios

安裝 cli 工具:git

npm install react-web-cli -g

安裝配置 React web 等:github

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 的命名規則肯定文件)。 

一些存在的問題 

在 Web 端兼容性是個很是麻煩頭疼的事情,React Web 已經盡力幫你抹平兼容性問題和代碼差別,儘量的讓你減小改動就能夠建立 Web 版本的應用。但受限於 Web 端的一些固有限制(好比請求跨域),不可避免的就會有一些須要你改代碼的地方。

爲此,能夠經過 if (Platform.OS == 'web') 的方式判斷目標平臺,並針對性的作一些平臺兼容性處理。一樣的,也能夠將 web 替換爲 ios 或者 android 判斷其餘平臺。 

在 React web 官方文檔上面已經列出來了一些平臺差別問題 ,這裏就再也不贅述了。

連接:

三步將 React Native 項目運行在 Web 瀏覽器上面

三步將 React Native 項目運行在 Web 瀏覽器上面(原文)

使用 Babel + React + Webpack 搭建 Web 應用

相關文章
相關標籤/搜索