最小構成で始める@ionic/react

# はじめに

今年のはじめにIonic 4がリリースされました。
Ionic 4では、UIコンポーネントがWebComponentsで再実装されたことにより、ReactやVueでもIonicが利用できるようにななっています。
ということで、早速React版の [@ionic/react](https://www.npmjs.com/package/@ionic/react) を動かしてみたいと思います。
（バージョン4.8.0-rc.0で動作確認しました。）

@ionic/react を利用するためにはWebpackでいくつかの設定が必要です。
Ionic CLIやcreate-react-appを利用することで、それらが設定済みの状態で@ionic/reactの利用ができます。
（どちらも内部的には [react-scripts](https://www.npmjs.com/package/react-scripts) を使用しています。）

しかし、それらの環境では不必要なパッケージもたくさん導入されてしまうでしょう。
ビルド環境を自分でカスタマイズしたい人や、既存のReactアプリにIonicを組み込みたい人向けに、最小構成で@ionic/reactが動く環境を作ってみます。

# パッケージのインストール

以下のようにパッケージを初期化し、必要なパッケージをインストールします。

```shell-session
$ npm init -y
$ npm i @ionic/react react react-dom react-router@4 react-router-dom@4
$ npm i -D @babel/core @babel/preset-react @svgr/webpack babel-loader css-loader style-loader url-loader webpack webpack-cli webpack-dev-server
```

# Webpackの設定

以下のように `webpack.config.js` を書きます。

```webpack.config.js
const path = require('path')

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react']
          }
        },
        include: [
          path.resolve(__dirname, 'src')
        ]
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          }
        ]
      },
      {
        test: /\.svg$/,
        use: [
          '@svgr/webpack',
          'url-loader'
        ]
      }
    ]
  },
  entry: {
    bundle: './src/index'
  },
  output: {
    path: path.join(__dirname, 'public'),
    filename: '[name].js'
  },
  devServer: {
    historyApiFallback: true,
    contentBase: path.join(__dirname, 'public')
  },
  mode: process.env.NODE_ENV || 'development'
}
```

# アプリの実装

こんな感じでアプリを実装します。
説明を簡単にするために1ファイルだけの簡単なものです。
Reactに使い慣れた方であれば普通のコンポーネントライブラリとして利用できるでしょう。

```jsx:src/index.js
import '@ionic/core/css/core.css'
import '@ionic/core/css/ionic.bundle.css'

import React from 'react'
import { render } from 'react-dom'
import {
  BrowserRouter as Router,
  Route,
  Switch
} from 'react-router-dom'
import {
  IonApp,
  IonContent,
  IonFab,
  IonFabButton,
  IonHeader,
  IonIcon,
  IonItem,
  IonList,
  IonTitle,
  IonToolbar
} from '@ionic/react'
import { add } from 'ionicons/icons'

const MainPage = () => {
  const [items, setItems] = React.useState(['A', 'B', 'C'])

  return <>
    <IonContent>
      <IonList>
        {
          items.map((item, i) => {
            return <IonItem key={i}>{item}</IonItem>
          })
        }
      </IonList>
    </IonContent>
    <IonFab vertical='bottom' horizontal='end' slot='fixed'>
      <IonFabButton
        onClick={() => {
          const newItems = Array.from(items)
          newItems.push('new item')
          setItems(newItems)
        }}
      >
        <IonIcon icon={add} />
      </IonFabButton>
    </IonFab>
  </>
}

const App = () => {
  return <Router>
    <IonApp>
      <IonHeader>
        <IonToolbar>
          <IonTitle>Hello @ionic/react</IonTitle>
        </IonToolbar>
      </IonHeader>
      <Switch>
        <Route path='/' component={MainPage} />
      </Switch>
    </IonApp>
  </Router>
}

render(<App />, document.getElementById('content'))
```

HTMLファイルはこんな感じです。

```public/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width">
<title>@ionic/react minimum start</title>
</head>
<body>
<div id="content"/>
<script src="bundle.js"></script>
</body>
</html>
```

以下のコマンドで実行します。

```shell-session
$ npx webpack-dev-server
```

http://localhost:8080/ にアクセスすると以下のように表示されます。
（Chromeのモバイルエミュレーションでの画面です。）

![Screen Shot 2019-06-07 at 4.26.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4249/32983745-3fca-0099-8337-51b547bfc2e5.png)

# おわりに

最後に、わかった範囲で @ionic/react を正しく動かすためのポイントをまとめます。

* `@ionic/core/css/core.css` と `@ionic/core/css/ionic.bundle.css` を読み込む
    * 今回は `style-loader` と `css-loader` を使用しましたが、結果的に必要なcssが読み込めれば手段は何でもOKです
* `ionicons` 内のSVGファイルを正しく読み込む
    * `IonIcon` の動作に必要です
    * `@svgr/webpack` と `url-loader` を使うことで、importしたSVGがData URI形式で扱われます
    * `file-loader` でも代替可能ですが、全てのSVGファイルがアセットとして書き出されます

もっと良い方法があったら教えてください。


Ionicは元々Angularをベースに作られていました。
Ionic 4では、これぐらいの最小限のReactプログラムでIonicを利用できるようになっていて素晴らしいですね。

# 参考情報

* [Ionic 4 リリース！！: Ionic for Everyone](https://www.rdlabo.jp/article/1026)
* [Ionic CLIでReactが使えるようになりました](https://qiita.com/rdlabo/items/dd1c318217cda5b37b4b)