Integrating react-native-web into a React Native Project: A Step‑by‑Step Guide
This article explains how to extend a React Native project with react-native-web, covering the motivation, required dependencies, project setup, webpack and Babel configuration, entry‑file creation, AppRegistry usage, component implementation, and JDReact’s practical extensions for seamless multi‑platform deployment.
React Native enables JavaScript developers to build native iOS and Android apps, but its original vision of "Write once, render anywhere" did not include the web. Facebook later introduced the concept of "Learn once, write anywhere" and open‑sourced react-native-web , which maps React Native components to web equivalents (e.g., View → div , Image → img ) without modifying existing code.
1. Project scaffolding
First, set up the development environment (macOS, iOS) and install required tools:
brew install node
# Watchman monitors file changes
brew install watchman
# Switch npm registry to Taobao
nrm use taobaoCreate a new React Native project and install its dependencies:
react-native init rnweb
cd rnweb
npm installRun the app on iOS to verify the native setup:
yarn ios
# or
yarn react-native run-ios2. Adding react-native-web
Install the core libraries needed for the web target:
npm install react react-dom react-native-webCreate the web entry file index.web.js :
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
AppRegistry.registerComponent(appName, () => App);
AppRegistry.runApplication(appName, { initialProps: {}, rootTag: document.getElementById('root') });3. Webpack & Babel configuration
Install the build tools:
npm install webpack webpack-cli webpack-dev-server --save-dev
npm install babel-loader --save-devConfigure webpack.config.js (development mode shown):
const path = require('path');
module.exports = {
entry: './index.web.js',
output: { filename: 'index.web.js', path: path.resolve(__dirname, 'build') },
mode: 'development',
module: { rules: [{ test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader' } }] },
resolve: { alias: { 'react-native$': 'react-native-web' } },
devServer: { contentBase: path.resolve(__dirname, 'build'), port: 3001 },
plugins: [new (require('html-webpack-plugin'))({ template: path.join(__dirname, 'index.html') })]
};Provide a simple HTML template ( index.html ) that contains a div#root placeholder for the React app.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,viewport-fit=cover">
<title>React Native For Web</title>
</head>
<body>
<div id="root">React Native For Web</div>
</body>
</html>4. Development server
Start the live‑reloading server:
npm run dev # defined as "webpack-dev-server" in package.jsonThe server serves the bundled files at http://localhost:3001 . If errors appear, ensure Babel is fully configured (see step 8).
5. Babel full‑stack
npm install @babel/core @babel/runtime @babel/preset-react @babel/preset-env @babel/preset-flow --save-devUpdate webpack.config.js to include the Babel loader (already shown in step 3).
6. AppRegistry deep dive
Both native and web entry points rely on AppRegistry . On the web, AppRegistry.registerComponent stores a runnable in an internal map, and AppRegistry.runApplication invokes renderApplication (which ultimately calls ReactDOM.render or hydrate ) to mount the component tree into the DOM.
// Simplified AppRegistry implementation
var runnables = {};
var AppRegistry = {
registerComponent(appKey, componentProvider) {
runnables[appKey] = {
getApplication(appParameters) { return _getApplication(componentProvider, appParameters); },
run(appParameters) { renderApplication(componentProvider, null, null, appParameters); }
};
return appKey;
},
runApplication(appKey, appParameters) { runnables[appKey].run(appParameters); }
};7. Component implementation example (Text)
The Text component in react-native-web decides whether to render a span or div based on nesting, applies style handling, and forwards refs:
class Text extends React.Component {
renderText(hasTextAncestor) {
const { style, numberOfLines, selectable, onPress } = this.props;
const component = hasTextAncestor ? 'span' : 'div';
const supportedProps = { /* classList, dir, ref, style */ };
return React.createElement(component, supportedProps);
}
render() {
return (
{hasTextAncestor =>
hasTextAncestor ? this.renderText(true) :
{this.renderText(false)}
}
);
}
}
export default applyLayout(applyNativeMethods(Text));8. JDReact practical extensions
JDReact builds on the open‑source React Native stack, adding custom plugins, a dedicated .web.js entry, and a scaffolding tool that generates a web folder with webpack and HTML templates. Its package.json distinguishes runtime dependencies from dev‑only web libraries, and provides scripts web‑init , web‑start , and web‑bundle to automate initialization, local development, and production bundling.
{
"scripts": {
"web-init": "node ./xxxx-web/cli.js init",
"web-start": "node ./xxxx-web/cli.js start",
"web-bundle": "rm -rf build-web && node ./xxxx-web/cli.js bundle"
},
"dependencies": {
"react": "16.8.3",
"react-native": "0.59.9"
},
"devDependencies": {
"xxxx-web": "^2.0.2"
}
}Running npm run web-init creates a web directory with webpack.config.* files; npm run web-start launches the dev server; and npm run web-bundle produces a production build.
Conclusion
By following the steps above, a standard React Native project can be extended to support iOS, Android, and Web with minimal code changes. The process involves installing react-native-web , configuring webpack and Babel, creating a web entry point, and understanding the role of AppRegistry . JDReact further streamlines this workflow for large‑scale enterprise projects.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.