Blog

Share code between mobile and web with react-native-web

Nowadays applications often have to support multiple platforms. Besides a web-application, there is also a need for mobile applications on multiple
platforms. Therefore a developer requires knowledge of webdevelopment, iOS development, Android development and probably a lot of time. This means
projects often require multiple teams of developers, working on the same application for different platforms with multiple codebases. Wouldn't it be great to have a single shared codebase
that would work on both mobile and web?

React is a component-based Javascript library to create interactive user interfaces in the DOM.
React Native lets you build native mobile apps with Javascript in a similar way to React.
In React Native it is already possible to have a single codebase which is able to create both native apps for iOS and Android. So instead of building
an app in both Swift and Java, a developer can write React code. A technique a webdeveloper is often familiar with nowadays. React
Native is already used in production for Facebook, Instagram, Airbnb apps and many others.

So, imagine you are using React Native and also creating a web application with React. You will probably encounter a lot of duplication between those applications.
React Native uses <View> and <Text> components, while React just uses <div> and <span> elements. This is where the React
Native Web
library comes in handy. This will translate your React Native components to HTML elements
which will render in your browser. So, simply said a <View> component will become a <div> and a <Text> element will become a <span> element.

Setup

Below is an example of a simple webpack config suitable for React Native Web. The most important is the last part (react-native: react-native-web).
An alias is created for React Native, so that all the React Native components are delegated to React Native Web.

const path = require('path');
const webpack = require('webpack');

module.exports = {
  devServer: {
    contentBase: path.join(__dirname, 'src')
  },
  entry: [
    path.join(__dirname, '../index.web.js')
  ],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: [
          'react-hot',
          'babel-loader?cacheDirectory=true'
        ]
      },
      {
        test: /\.(gif|jpe?g|png|svg)$/,
        loader: 'url-loader',
        query: { name: '[name].[hash:16].[ext]' }
      }
    ]
  },
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurenceOrderPlugin()
  ],
  resolve: {
    alias: {
      'react-native': 'react-native-web'
    }
  }
};

For more detailed instructions visit the React Native Web Github repository.

Generated DOM

React Native Web generates your DOM based on your React Native components.

Generated classes in DOM

As you can see React Native Web generates a class for every styling property. This will not result in a concise, clean and uncluttered DOM. Luckily the React
developer console will give you a better overview.

React console

Animations

React Native Web also supports some animations provided by React Native. So even your animations will still work in your browser. Nice!

Animations

Missing modules and views

React Native Web is still in an initial phase. This means not all the modules and views from React Native are released yet for the web counterpart.
It is not even possible to implement all the components for the web. Simply because some functionality is absent for the web. But there are some
workarounds for this problem. Like in React Native you can guard the use of some code by using Platform.OS which equals 'web' for React Native
Web. For complete components you are able to create a separate file with the same component name. So imagine you have a component called
Counter.js you can generate a file called Counter.web.js. When importing Counter the correct file will automatically be imported based on the
platform extension.

Conclusion

React Native Web is interesting as it is possible to share a lot of code between your platforms. However, it will never be completely shareable
between platforms and the need of custom components will still exist. Luckily this is fairly easy to achieve. When you like a clean DOM this is probably not a suitable
solution, because the DOM generated by React Native Web is very polluted. React Native Web is certainly something to keep an eye on, but it seems too
early to use it for most projects.