React Native转web方案:react-native-web

react-native-web

说一下,最新版的RN-web的版本是0.12.0,适用于RN是0.60以上版本的。
以前的RN-web版本0.11.5的时候有example,这个版本有例子可以直接运行起来,而最新的0.12.0没有example。
本文所用的RN的版本:0.59.10。RN-Web的版本0.11.5。node的版本v13.8.0
相关开发文档:http://necolas.github.io/react-native-web/docs/?path=/docs/overview-getting-started--page

新建RN项目使用RN-web

  1. 首先使用react-native-cli初始化一个项目。
    sudo npm i -g react-native-cli
    react-native init rnweb
    初始化RN指定版本react-native init demo --version 0.59.10

  2. 在iOS或者安卓模拟器或真机上运行出来
    react-native run-ios
    react-native run-android

  3. 安装react-native-web
    修改 根目录/package.json,分别在后面加上,保存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"name": "myApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"web": "webpack-dev-server --config ./web/webpack.config.js --content-base ./web --inline",
"test": "jest"
},
"dependencies": {
"react": "16.8.3",
"react-native": "0.59.10",
"react-art": "^16.8.3",
"react-dom": "^16.8.3",
"react-native-web": "^0.11.5"
},
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/runtime": "^7.8.4",
"babel-jest": "^25.1.0",
"jest": "^25.1.0",
"metro-react-native-babel-preset": "^0.58.0",
"react-test-renderer": "16.8.3",
"babel-loader": "^8.0.5",
"file-loader": "^3.0.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.2.1",
"webpack-html-plugin": "^0.1.1"
},
"jest": {
"preset": "react-native"
}
}
  1. 根目录新建web文件夹
  2. web文件夹下,新建webpack.config.js的webpack配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const path = require('path');
module.exports = {
entry: path.resolve(__dirname, '../index.web'), // 入口文件
output: {
path: path.resolve(__dirname, 'dist'), // 输出的路径
filename: 'bundle.js' // 打包后文件
},
resolve: {
alias: {
'react-native$': 'react-native-web'
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
}
},
exclude: /node_modules/
},
{
test: /\.(png|jpe?g|gif|svg)$/,
use: {
loader: 'file-loader',
options: {
// name: 'images/[name].[ext]'
}
},
exclude: /node_modules/
}
]
},
devServer: {
port: 9090
}
}
  1. web文件夹下,新建index.html,复制保存
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, user-scalable=no">
</head>
<body>
<div id="react-app" style="height: 100vh; display: flex;"></div>
<script src="bundle.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
  1. 写一个针对 Web 平台启动入口文件,在根目录下 index.web.js
    新增配置之后,如下:
1
2
3
4
5
6
7
8
9
10
11
import App from "./App";
import { AppRegistry } from "react-native";

// register the app
AppRegistry.registerComponent("App", () => App);

// web enterance
AppRegistry.runApplication("App", {
initialProps: {},
rootTag: document.getElementById("react-app")
});

7.运行npm install或者是yarn install,然后运行 npm run web 或者是yarn web。

在浏览器中打开 http://localhost:9090/index.html

你就可以看到 React Native 转出的 Web 网页了。

适配自定义的 Native Modules

React Native 开发的 App 中经常会出现 React Native 官方提供的 Native Modules

够用的情况,这时你会在项目中开发自己的 Native Modules,然后在 JavaScript 中去调用自己的 Native Modules。这在 ReactNative 环境下运行没有问题,但转成 Web 后执行时会报错说 Native Modules 上找不到对应的模块,这时因为在浏览器环境下是不存在这些自定义的 Native Modules。为了让页面能正常在浏览器中运行,需要为 Web 平台也实现一份自定义的 Native Modules,实现方法可以在 Web 平台的执行入口的最开头注入以下 polyfill,内容NativeModules polyfill.js

1
2
3
4
import { NativeModules } from 'react-native';
import MyModule from './MyModule'; // 实现自定义 Native Modules 的地方

NativeModules.MyModule = MyModule; // 挂载 MyModule

这段代码的作用是把针对 Web 平台编写的自定义原生模块挂载到 Native Modules 对象上成为其属性,以让 JavaScript 代码在访问自定义 Native Modules 时访问到针对 Web 平台编写模块。

编写特定平台的代码
为了让 React Native 三端同构能正常的运行,在有些情况下你不得不编写平台特定的代码,因为有些代码只能在特定平台下才能运行,编写特定的 Web 平台代码有以下三种方法:

ReactNative.Platform.OS:所有端的代码都在一个文件中,通过以下代码来写 Web 平台专属代码:

1
2
3
4
5
6
7
8
9
import { Platform } from 'react-native';

if(Platform.OS==='web'){
// web 平台专属代码
}
process.env.platform:通过 webpack 注入的环境变量来区分:
if (process.env.platform === 'web') {
// web 平台专属代码
}

这段代码只会在 Web 平台下被打包进去,这和 ReactNative.Platform 的区别是:后者的代码会打包进所有的平台。

要使用这种方法需要你在 webpack.config.js 文件中注入环境变量:

1
2
3
4
5
6
7
plugins: [
new webpack.DefinePlugin({
'process.env': {
platform: JSON.stringify(platform),
__DEV__: mode === 'development'
}),
]

.web.js: 在 Web 模式下会优先加载 .web.js 文件,当 .web.js 文件不存在时才使用 .js 文件。
总结
React Native 三端同构在理论上虽然可行,并且有现成的方案,但实践是还是会遇到一些问题,例如:

在 Web 平台运行出的样式和 React Native 平台不一致,针对这种情况一般是 react-native-web 库的适配问题,可以在 Github 上提 issue 或 Pull Request。
有些 React Native 提供的 API 在 Web 平台不可能实现适配,例如调摄像头、振动等,对于这种问题可以在 Web 平台裁剪掉这些功能或使用其他交互方式替代。
React Native 三端同构虽然无法实现 100% 和 React Native 环境运行一致,但能快速简单的转换大多数场景,以低成本的方式为你的项目带来收益。

babel-plugin-react-native-web

官网例子

官网上的例子是用的RN版本是0.55的。RN-web的版本是0.11.5。
GitHUB上应该是只能下载最新版本了,放在了地址https://github.com/peilinghui/RN-web

  1. 首先在文件目录下react-native-web-master/packages/examples就是这个例子。然后在最上级目录下运行下面的命令。
1
2
yarn examples
open ./packages/examples/dist/index.html

打开index.html就能看到实例组件。来看下源码。
入口RNTesterApp。分别是.ios.js或者.android.js和.web.js.其中RNTesterExampleList中RNTesterList区分是.ios.js或者.android.js和.web.js,在RNTesterList文件中ComponentExamples通过key和module来对应相应的模块代码,

扩展:使用CRA创建React项目

构建React项目的几种方式:

构建:create-react-app 快速脚手架
构建:generator-react-webpack
构建:webpack一步一步构建

构建:create-react-app 快速脚手架

1
2
3
4
npx create-react-app my-app
cd my-app
npm install react-native-web
npm start

参考资源
React Native转web方案:react-native-web

链接
示范代码

文章目录
  1. 1. 新建RN项目使用RN-web
    1. 1.0.1. 适配自定义的 Native Modules
  • 2. 官网例子
  • 3. 扩展:使用CRA创建React项目
  • 本站总访问量 本站访客数人次 ,