React開発環境のセットアップで挫折し、create-react-appに救われた件


## 概要

これまでUIにはPC用でも [jQuery Mobile](https://jquerymobile.com/) を利用していたのですが、最近はあまり更新されていないようで、将来がちょっと不安。

そこで前から興味のあった [React](https://facebook.github.io/react/) を試してみることにしました。最初は調子よかったのですが… 途中から環境設定の泥沼にハマり、最後は create-react-app に落ち着くまでを簡単にまとめてみました。

同じ苦労をした方であれば、共感をもって読んでもらえるかも、と期待しております。

## Reactを普通に使ってみる

まずはいつも通り、jQuery なんかと同じ感覚でJSファイルを読み込み、h1要素を追加してみた。以下のようなhtmlを作成してブラウザで表示。

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React sample 1</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
</head>
<body>
  <div id="root"></div>

<script>
ReactDOM.render(
  React.createElement('h1', null, 'Hello, React world!'),
  document.getElementById('root')
);
</script>
</body>
</html>
```

うん、普通に表示される。特に癖もなく使い易いライブラリな印象。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/b5bb3688-ae61-9b04-40ac-27b912d25971.png)

## JSX表記を試してみる

このままだと jQuery との差がわからないので、JavaScriptにXML(xhtml)表記が混在するJSXとやらを試してみた。

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React sample 1</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.js"></script>
<script type="text/babel">
ReactDOM.render(
  <h1>Hello, React world!</h1>,
  document.getElementById('root')
);
</script>
</head>
<body>
  <div id="root"></div>
</body>
</html>
```

JavaScriptにいきなりXML表記のタグが混じっています。ちょっと見慣れない表記ですが、シンプルに書けて良いですね。

ただここで、Babel の browser.js がさっと見つからず、ちょっと迷いました。最新版のパッケージには含まれていないらしく、少し古いバージョンを探して利用。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/b5bb3688-ae61-9b04-40ac-27b912d25971.png)

よっしゃいけた！

ここで安心して React を理解した気になっていたのですが、ここで既に罠にハマっていたのです。browser.js がなぜ廃止され、最新のパッケージからは削除されているのか、その意味をよーく考えてみるべきでした。

ちょっとだけ、イヤーな予感はしてたんですよ、ええ。

## Material-UIを試してみる

React だけだとUIパーツは自分で作成する必要がありそうなので、[Material-UI](http://www.material-ui.com/) もあわせて試してみます。

material-ui モジュールを導入し、まず、さきほどのサンプルに1行加えてみます。

```js
import Avatar from 'material-ui/Avatar';
```

と、Uncaught ReferenceError: require is not defined というエラーが発生して止まってしまいました。ブラウザ表示もされません。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/2bb3d46a-9392-1d68-8c02-88c85e47ef1e.png)

require なんて使ってたっけ？たぶん Babel が import文を変換したんだろうな… と思いましたが、ここで困りました。そもそもブラウザ環境のJavaScriptに require なんて実装されていましたっけ？

ここから泥沼にハマりこみます。

## 悪あがき

ブラウザには importもrequreもない、あるのは &lt;script&gt; タグだ！と強引に Material-UI のパーツ用JSを読み込ませてみます。

exports と require() が無い！と怒られるので、ダミー定義までしてしまいます。ええ、もうヤケです。

```html
<script>
var exports = {};
function require() {
  console.log("require: " + JSON.stringify(arguments));
}
</script>
<script src="js/Avatar.js"></script>
```

結果、以下のようなコンソール表示とエラーになりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/5e80dbb7-c58b-2f75-4604-b111aa9c5b62.png)

そうか、内部でいろいろ呼んでいるのね、って感じ。これらを全部 &lt;script&gt; で読み込んでおけば動くのかもしれませんが… ちょっと試したいだけなのにその苦労はちょっと…

ここでやっと、React はJSファイルを数個読み込めば使えるような、お手軽なライブラリではないんだ、と気がつきました。Webpackだかなんだか、ビルド環境を構築しておいて、事前にビルドするタイプのマジなやつやん、ってことに…

## そして泥沼

さーどうしましょ、と半日ほど迷走しまして。

* 諦めてjQuery Mobileに戻ろうか<br/> => Mobileが更新されておらず最新のjQueryでエラーが発生<br/><br/>
* ちゃんとビルド環境を構築しようか<br/> => Babel/Webpack関連の情報が多すぎて調べているうちに寝てしまう<br/><br/>
* 動いてる環境を参照して無茶を継続<br/> => 各種ビルドスクリプトが複雑で、読んでるうちにやはり寝てしまう

結局、諦めて寝てしまいました…

## create-react-app

そして翌日、ググって見つけたのが [コマンド一発でReactの開発環境を構築してくれるFacebook製ツール「create-react-app」](https://mae.chab.in/archives/2910) の記事。

React の本家が作成したツールということで、さっそく導入してみました。create-react-app react-sample でプロジェクトを作成。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/26130cb7-ef95-2023-1eba-d639ec110dd3.png)

ファイルのダウンロードがしばらく続き、以下のような親切なメッセージが表示されて完了します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/70a73c61-ce44-a90c-49f1-e12e029fe6e4.png)

メッセージに従って npm start を実行すると、ブラウザが自動起動して、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/c042f4b1-5306-982a-c6b1-20d9e624ef28.png)

メッセージに従って src/App.js に数行加えてみると…

```html
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <p className="App-body">
          Yes, my mother.
        </p>
      </div>
    );
  }
}

export default App;
```

ファイルをセーブしただけでWebページが更新された！うーむ、昨日の苦労が嘘のようだ。楽園はここにあったのか…

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/d3bc4fad-7191-88f7-b779-546eacc89ec1.png)

## Material-UIに再挑戦

この流れならば、いけるかもしれません。react-test フォルダで npm install material-ui --save とタイプし、モジュールを導入します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/dd88781e-c3ca-db68-cd96-d580ac6e56cd.png)

ちょっと警告は出たものの導入できたっぽいので、公式ページの [Chipサンプル](http://www.material-ui.com/#/components/chip) を参考にして、独自追加部分を以下に変更。

```html
        <div style={this.styles.wrapper}>
          <Chip>Chip test</Chip>
        </div>
```

これでセーブしたところ、ちゃんとエラーが発生してひと安心。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/f86df25f-6240-e63f-095e-2eef1b0edf1d.png)

コードにimport文を追加して、再度トライ！

```js
import Chip from 'material-ui/Chip';
```

コンパイルは成功！しかし画面にはエラーが。しかもやたら見易くてわかりやすい表示で。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/43865f8e-00ed-9f48-5ef1-52f11ece81be.png)

他にもテーマ関係のエラーが出ていたので、デフォルトのテーマらしきものを読み込み、

```js
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
```

htmlの追加部分を以下のように修正。

```html
        <MuiThemeProvider>
          <Chip>Chip test</Chip>
        </MuiThemeProvider>
```

これでようやく！Material-UIのパーツが表示されました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/629ad40e-cf32-36a1-2654-114d0d0ceb24.png)

更に削除用のコールバック(アラート出すだけ)を追加し、最終的なテストページは以下になりました。

```html
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Chip from 'material-ui/Chip';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <MuiThemeProvider>
          <Chip
            onRequestDelete = {() => alert("delete")}
          >Chip test</Chip>
        </MuiThemeProvider>
      </div>
    );
  }
}

export default App;
```

## ビルドアップ！バンバンババン！

鋼鉄ジーグ、古いですね。

さて、npm start すると表示される npm run build を試してみましょう。実行すると以下のように表示されました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/6df09f4d-e0d8-14c1-7c9f-f4949fd6398e.png)

build というフォルダが自動生成されて、公開に必要そうなファイルがまとめられています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/d08bd978-c552-377f-0790-0b98f1c3cfa6.png)

またまた親切なアドバイスが表示されたので、簡易Webサーバー的なコマンド [serve](https://www.npmjs.com/package/serve) を使用してみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/506d4da3-6233-4e55-a7ce-9db23683a848.png)

無事に起動できたようなので、ブラウザで確認します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/e39435a8-18f4-6e89-4e24-b3a4e4c96d2d.png)

おお、良いカンジです。この環境で開発を進め、完成したら npm run build して、build フォルダ以下を公開すればok、と。なるほど良くできてます！

## まとめ

今回得られた結果はこちら。

* 新しいものに挑戦する際、ちゃんと初心に戻って整備された道を進むべし
* 偉大な先駆者たちの好意に甘えるべし

そして悔しまぎれの言い訳がこちら。

* 道を踏み外したから有難味がよくわかった
* なんとなくだが内部の動きがみえた気もする

ではまた！