とある API を作っいて、動作確認にしょぼいクライアントアプリを作りたくなった。
- 目標1: まずは Web で試して後から Native アプリ化したい。
 - 目標2: TypeScript で書きたい。
 
Twitter Lite で開発されたという react-native-web を使ってみる。react-native-web とは、react-native に入れ替えると ReactNative アプリが HTML アプリになるという物。同一のコードを携帯でも HTML でも動かそうと思うとまだちょっと手間がかかるようだ。
react-native-web アプリの一番簡単な作り方
react-dom の代わりに react-native-web を使うだけなら非常に簡単。create-react-app がすでに対応している。
まず、create-react-app で普通の React アプリを作る。ちなみに、npx はローカルにインストールされた node コマンドを実行するだけの物だと思っていたら、ローカルにインストールされてない時は勝手にインストールして使い終わったらアンインストールしてくれるという便利機能があった。
npx create-react-app react-native-web-simple
react-native-web をインストール
cd react-native-web-simple
yarn add react-native-web
src/index.js を書き換える
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('App', () => App);
AppRegistry.runApplication('App', {
  rootTag: document.getElementById('root')
});
src/App.js を書き換える
import React, { Component } from 'react';
import logo from './logo.svg';
import { Image, StyleSheet, Text, View } from 'react-native';
const Link = (props) => <Text {...props} accessibilityRole="link" style={StyleSheet.compose(styles.link, props.style)} />
class App extends Component {
  render() {
    return (
      <View style={styles.app}>
        <View style={styles.header}>
          <Image accessibilityLabel="React logo" source={logo} resizeMode="contain" style={styles.logo} />
          <Text style={styles.title}>React Native for Web</Text>
        </View>
        <Text style={styles.text}>
          This is an example of an app built
          with <Link href="https://github.com/facebook/create-react-app">Create React App</Link> and{' '}
          <Link href="https://github.com/necolas/react-native-web">React Native for Web</Link>
        </Text>
        <Text style={styles.text}>
          To get started, remix this starter kit by editing <Link href="https://glitch.com/edit/#!/react-native?path=src/App.js" style={styles.code}>src/App.js</Link>.
        </Text>
      </View>
    );
  }
}
const styles = StyleSheet.create({
  app: {
    marginHorizontal: 'auto',
    maxWidth: 500
  },
  logo: {
    height: 80
  },
  header: {
    padding: 20
  },
  title: {
    fontWeight: 'bold',
    fontSize: '1.5rem',
    marginVertical: '1em',
    textAlign: 'center'
  },
  text: {
    lineHeight: '1.5em',
    fontSize: '1.125rem',
    marginVertical: '1em',
    textAlign: 'center'
  },
  link: {
    color: '#1B95E0'
  },
  code: {
    fontFamily: 'monospace, monospace'
  }
});
export default App;
上記コードは https://glitch.com/edit/#!/react-native から拝借しました。不思議な事に react-native-web をインストールすると react-native を import 出来るようになる。これは webpack の alias という機能を使っていて、あらかじめ create-react-app の生成する webpack に alias の設定が入っているからだった。https://github.com/facebook/create-react-app/pull/407
Native でも Web でも動くアプリを作る。
https://github.com/necolas/react-native-web/blob/master/website/guides/getting-started.md#web-packaging-for-existing-react-native-apps の通りに作業するだけですが、私は初見でかなり戸惑ったので丁寧に書きます。手順としては以下になります。
- 普通に ReactNative のプロジェクトを作る。
 - JavaScript を合体させるために webpack + babel の設定を書く。
- babel-plugin-react-native-web でソースコードで 
react-nativeを import するとreact-native-webを import した事になる。 
 - babel-plugin-react-native-web でソースコードで 
 - ブラウザで表示するために index.html や index.web.js を書く。
 - 微調整。
 
普通に react-native のプロジェクトを作る
brew install node watchman yarn
npm install -g react-native-cli
react-native init ReactNativeTest
cd ReactNativeTest
react-native run-ios
react-native-Web 化に必要なモジュールをインストール
yarn add react-dom react-native-web
yarn add --dev babel-plugin-react-native-web babel-loader url-loader webpack webpack-dev-server webpack-cli
web/webpack.config.js の作成
通常の ReactNative では、Metro というツールでソースコードを合体させますが、react-native-web では webpack + babel を使います。
https://github.com/necolas/react-native-web/blob/master/website/guides/getting-started.md#web-packaging-for-existing-react-native-apps に書いてある通りの内容で web/webpack.config.js を作成します。
index.html の作成
ウェブブラウザがアクセスする HTML を適当に書きます。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>React Native Web</title>
  </head>
  <body>
    <div id="react-app"></div>
  </body>
  <script type="text/javascript" src="bundle.web.js"></script>
</html>
index.web.js の作成
アプリを記述する App.js を HTML 上に設置する部分です。
index.web.js の作成
import App from './src/App';
import { AppRegistry } from 'react-native';
// register the app
AppRegistry.registerComponent('App', () => App);
AppRegistry.runApplication('App', {
  initialProps: {},
  rootTag: document.getElementById('react-app')
});
App.js の移動
react-native init で作ると最上位に App.js が作られますが、webpack に合わせて src に移します。
mkdir src
mv App.js src/App.js
実行
./node_modules/.bin/webpack-dev-server -d --config ./web/webpack.config.js --inline --hot --colors
ブラウザで http://localhost:8080/ を開く。