とある 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/ を開く。