技術實踐丨React Native 專案 Web 端同構

華為雲開發者社群發表於2021-01-19
摘要:儘管 React Native 已經進入開源的第 6 個年頭,距離釋出 1.0 版本依舊是遙遙無期。“Learn once, write anywhere”,完全不影響 React Native 淪為“不會 JavaScript 也能用”的框架,那如何將在 React Native 專案中引入 react-native-web 呢?

react-native-web 簡介

倉庫地址: https://github.com/necolas/react-native-web

react-native-web 是由 前 Twitter 現 Facebook 工程師 Nicolas Gallagher 實現並維護的開源專案,是一個使 React Native 元件和 API 能執行在 Web 上的庫,其和 React Native Windows, React Native macOS 等庫將 React Native 擴充到一個又一個新的平臺。目前推特、expo、大聯盟足球、Flipkart、優步、《泰晤士報》、DataCamp 以及我們小作坊都在生產中使用了 react-native-web。Chrome、Firefox、Edge,Safari 7 +、IE 10+都支援通過 react-native-web 構建的 web 應用。當然值得注意的是,官方文件明確表示不支援 React Native 中不推薦使用的元件和 API,因此如果您專案中的某些功能依賴第三方庫,可能那部分的功能在 web 端同構時需要額外處理。

淺顯地認為react-native-web就是把React Native的元件和API都用適用於Web的標籤和API再適配實現一遍,使其在Web上的行為和在原生應用上儘量保持一致,從文件中提到的 Alert 和 Setting 模組以及其對應的原始碼中大概能感受到一二,比如TextInput:

switch (keyboardType) {
    case 'email-address':
      type = 'email';
      break;
    case 'number-pad':
    case 'numeric':
      inputMode = 'numeric';
      break;
    case 'decimal-pad':
      inputMode = 'decimal';
      break;
    case 'phone-pad':
      type = 'tel';
      break;
    case 'search':
    case 'web-search':
      type = 'search';
      break;
    case 'url':
      type = 'url';
      break;
    default:
      type = 'text';
  }
  if (secureTextEntry) {
    type = 'password';
  }

因此也借鑑了 React Native 的一些程式碼,作為適配的依據。

技術實踐丨React Native 專案 Web 端同構

如果您想基於 React Native 實現多端統一化方案,可參考去哪兒前端團隊的實現方案:跨端開發, 倉庫地址:https://github.com/qunarcorp/qrn-remax-unir

新增到React Native專案

一般來說新建 React Native 專案時可以選用 expo-cli 或者 react-native-cli 來建立。expo-cli 中已經預置了對web的支援,如下圖所示.

技術實踐丨React Native 專案 Web 端同構

而我們實際開發中可能用 react-native-cli腳手架來構建專案比較多些,那麼如何引入 react-native-web呢?

我們先初始化專案:

npx react-native init rn_web
# 當然也可以使用模板,如
# npx react-native init rn_web --template react-native-template-typescript

此時我們的專案並不支援在web中使用:

技術實踐丨React Native 專案 Web 端同構

為了專案能在web環境中執行,我們需要藉助今天的主角--react-native-web,有請主角出臺:

cd rn_web
yarn add react-native-web
yarn add -D babel-plugin-react-native-web webpack webpack-cli webpack-dev-server html-webpack-plugin react-dom babel-loader url-loader @svgr/webpack

接著我們施展Copy大法,將我們初始化能用到的App.web.jsx、index.html、index.web.js、webpack.config.js這幾個檔案一把 down下來:

curl -L https://gist.github.com/hu-qi/bde8a6d2b45325d93b1665174f938faa/download | tar -xvz --strip-components=1

技術實踐丨React Native 專案 Web 端同構

react-native-web

然後在package.json中新增build和web的指令碼:

"build": "rm -rf dist/ && webpack --mode=production --config webpack.config.js",
"web": "webpack serve --mode=development --config webpack.config.js"
技術實踐丨React Native 專案 Web 端同構

就和 expo-cli 初始化的專案一樣可以執行yarn web,這時會在本地8080埠執行一個服務,這時我們分別執行yarn ios 和 yarn android就能看到在ios模擬器和Android模擬器中顯示和web端一模一樣的頁面,一次 react-native-web 的多端同構 Hello World 就成功實現了,當然這也意味著我們還可能編譯成小程式,後續有機會一起探討探討!

技術實踐丨React Native 專案 Web 端同構

此處的注意點:

  1. 程式碼能得以成功拷貝全靠梯子,當然也可以選擇去網頁下載;
  2. Android能得以成功執行,全靠給許可權sudo 755 android/gradlew;
  3. React Native 入口檔案需修改為 App.web,不然只有Web端才能讀取App.web.js;
  4. 適當執行./gradlew clean重新yarn android等多年經驗積累騷操作排除故障.

探究程式碼

關鍵的操作在於那行Copy程式碼的命令,那究竟上文中提到到下載了4的檔案到底做了啥呢?Copy攻城獅心中也有一個大大的問號,Talk is cheap, show me the code,開啟檔案看看那些程式碼吧!

常見的單頁面應用入口,像下面程式碼中的 div 我們稱其為“根” DOM節點,因為其中的所有內容都將由React DOM進行管理。在當前案例中,我們只是設定一些基本樣式以使主體div具有完整的高度和寬度:

 <html> 
... 
... 
  <body> 
    <div id =“ app-root”> </ div> 
  </ body> 
</ html>

使用index.web.js可以在Web和移動端之間區分開來,通過.web.js副檔名可以使該檔案僅在Web上使用,其他一些可用的擴充套件如.native.js、.ios.js和.android.js適用於移動端。當然,如果您希望將本不同端的程式碼都儲存在一個index.js檔案中,則可以使用import { Platform } from 'react-native'來按照條件區分不同平臺的程式碼。可以參考React Native官方文件中有關平臺特定程式碼的更多資訊。

index.web.js:
... 
...
AppRegistry.runApplication(appName,{ 
  initialProps:{},
  rootTag:document.getElementById('app-root'),
});

這與我們移動端的index.js非常相似,不過它還將您的應用程式掛載到根目錄中index.html的div上。

webpack雖然是重點內容,但此處不過過多介紹,請前往官方文件閱讀更加詳細的內容,此案例中我們用到了三個外掛:

  1. HtmlWebpackPlugin建立HTML;
  2. HotModuleReplacementPlugin用於熱模組重灌;
  3. DefinePlugin定義變數,例如__DEV__或NODE_ENV中react-native-web。

該檔案是臨時新增的檔案,用於在使用React Native Web 同構之前驗證我們的設定是否正常執行。最終,您可以刪除此檔案,因為App的入口js檔案可以在移動端執行,也能在Web端執行。不過為了處理某些在Web上能執行而在移動端不能執行的業務,需要將程式碼抽離出來存放在`.web.js`為字尾的檔案中。

後記

結合上述的簡單案例,在後續實際業務中,我們可以逐步嘗試同構業務到Web並逐步進行驗證。

本文分享自華為雲社群《React Native 專案 Web 端同構初探》,原文作者:胡琦。

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章