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 Native 的组件作了一个 Web 端的实现,并提供相关打包工具,让你能够直接打包出一份能够跑在 Web 端的代码。react
为了重点突出转换过程,这里使用 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 包以及相关依赖,并配置 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 端也测试好了,就能够打包发布了。 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 组件:
在 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 官方文档上面已经列出来了一些平台差别问题 ,这里就再也不赘述了。
连接:
三步将 React Native 项目运行在 Web 浏览器上面