This guide will help you to use and test React Native for Web once it has been installed.
It is recommended that your application provide a Promise
and Array.from
polyfill.
It's recommended to rely on Facebook's official React web starter kit –
create-react-app –
which has built-in React Native for Web support (once you install
react-native-web
).
Add babel-plugin-react-native-web
to your Babel configuration. This will alias react-native
to
react-native-web
and exclude any modules not required by the app.
Render apps using AppRegistry
:
// index.web.js
import App from './src/App';
import React from 'react';
import { AppRegistry } from 'react-native';
// register the app
AppRegistry.registerComponent('App', () => App);
AppRegistry.runApplication('App', {
initialProps: {},
rootTag: document.getElementById('react-app')
});
Render components within existing apps:
import AppHeader from './src/AppHeader';
import React from 'react';
import { render } from 'react-native';
render(<AppHeader />, document.getElementById('react-app-header'))
Components will also be rendered within a tree produced by calling
ReactDOM.render
(i.e., an existing web app), but
otherwise it is not recommended.
Server-side rendering is supported using AppRegistry
:
import App from './src/App';
import ReactDOMServer from 'react-dom/server'
import { AppRegistry } from 'react-native'
// register the app
AppRegistry.registerComponent('App', () => App)
// prerender the app
const { element, stylesheets } = AppRegistry.getApplication('App', { initialProps });
const initialHTML = ReactDOMServer.renderToString(element);
const initialStyles = stylesheets.map((sheet) => ReactDOMServer.renderToStaticMarkup(sheet)).join('\n');
// construct HTML document string
const document = `
<!DOCTYPE html>
<html>
<head>
${initialStyles}
</head>
<body>
${initialHTML}
`
Minor platform differences can use the Platform
module.
import { Platform } from 'react-native';
const styles = StyleSheet.create({
height: (Platform.OS === 'web') ? 200 : 100,
});
More significant platform differences should use platform-specific files (see
the webpack configuration below for resolving *.web.js
files):
For example, with the following files in your project:
MyComponent.android.js
MyComponent.ios.js
MyComponent.web.js
And the following import:
import MyComponent from './MyComponent';
React Native will automatically import the correct variant for each specific target platform.
Jest can be configured to improve snapshots
of react-native-web
components.
{
"snapshotSerializers": [ "enzyme-to-json/serializer", "react-native-web/jest/serializer" ]
}
Jest also needs to map react-native
to react-native-web
(unless you are
using the Babel plugin).
{
"moduleNameMapper": {
"react-native": "<rootDir>/node_modules/react-native-web"
}
}
Please refer to the Jest documentation for more information.
The web packaging landscape is diverse and fractured. Packaging web apps is subtly different to packaging React Native apps and is also complicated by the need to code-split non-trivial apps.
What follows is merely an example of one basic way to package a web app using Webpack and Babel.
Install webpack-related dependencies, for example:
yarn add --dev babel-loader url-loader webpack webpack-dev-server
Create a web/webpack.config.js
file:
// web/webpack.config.js
const path = require('path');
const webpack = require('webpack');
const appDirectory = path.resolve(__dirname, '../');
// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
const babelLoaderConfiguration = {
test: /\.js$/,
// Add every directory that needs to be compiled by Babel during the build.
include: [
path.resolve(appDirectory, 'index.web.js'),
path.resolve(appDirectory, 'src'),
path.resolve(appDirectory, 'node_modules/react-native-uncompiled')
],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// Babel configuration (or use .babelrc)
// This aliases 'react-native' to 'react-native-web' and includes only
// the modules needed by the app.
plugins: ['react-native-web'],
// The 'react-native' preset is recommended to match React Native's packager
presets: ['react-native']
}
}
};
// This is needed for webpack to import static images in JavaScript files.
const imageLoaderConfiguration = {
test: /\.(gif|jpe?g|png|svg)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]'
}
}
};
module.exports = {
// your web-specific entry file
entry: path.resolve(appDirectory, 'index.web.js'),
// configures where the build ends up
output: {
filename: 'bundle.web.js',
path: path.resolve(appDirectory, 'dist')
},
// ...the rest of your config
module: {
rules: [
babelLoaderConfiguration,
imageLoaderConfiguration
]
},
plugins: [
// `process.env.NODE_ENV === 'production'` must be `true` for production
// builds to eliminate development checks and reduce build size. You may
// wish to include additional optimizations.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
__DEV__: process.env.NODE_ENV === 'production' || true
})
],
resolve: {
// If you're working on a multi-platform React Native app, web-specific
// module implementations should be written in files using the extension
// `.web.js`.
extensions: [ '.web.js', '.js' ]
}
}
To run in development from the root of your application:
./node_modules/.bin/webpack-dev-server -d --config ./web/webpack.config.js --inline --hot --colors
To build for production:
./node_modules/.bin/webpack -p --config ./web/webpack.config.js
Please refer to the Webpack documentation for more information on configuration.
Safari prior to version 10.1 can suffer from extremely poor flexbox
performance. The recommended
way to work around this issue (as used on mobile.twitter.com) is to set
display:block
on Views in your element hierarchy that you know don't need
flexbox layout.
There are properties that do not work across all platforms. All web-specific
props are annotated with (web)
in the documentation.