Vagrant+VirtualBoxでReactの開発環境を作る

## はじめに
Vagrant+VirtualBoxでcentos7の仮想環境を作り、ReactでHelloWorldを表示するまでの手順です。
ゲストOSでReactを動かしますが、ホストOS（ローカル環境）のVSCodeからもソースを編集したいため、Vagrantの共有フォルダを設定して、共有フォルダ配下にReactの作業ディレクトリを作成します。

## 前提
下記がインストール済みであること。
* Vagrant
* VirtualBox

## 環境
* macOS Big Sur
* Vagrant            2.2.14
* VirtualBox         6.1.16

## ディレクトリ構成
### ホストOS側
仮想環境用のディレクトリを`centos7_react`とする。

```
centos7_react
 ├── data  （← ゲストOSとの共有フォルダ）
 |    └── (配下の構成はゲストOSのdataディレクトリ配下と同じなので省略)
 └── Vagrantfile

```

### ゲストOS側
`home/vagrant/data`がホストOSとの共有フォルダ。ここにReactの作業ディレクトリを作る。
dataディレクトリ配下は、最終的に以下のようになる。

```
data  （← ホストOSとの共有フォルダ）
 └── react-sample  （← Reactの作業ディレクトリ）
      ├── node_modules
      ├── package-lock.json
      ├── package.json
      ├── webpack.config.js
      └── src
           ├── index.html
           └── js
                └── client.js
```

## 構築手順
### 【ホストOS側】
#### ■centos7のbox追加
```
$ vagrant box add centos/7
```
以下では「3」を入力

```
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) hyperv
2) libvirt
3) virtualbox
4) vmware_desktop
```
> *上記コマンド実行時、私の環境ではセキュリティソフトの影響で、
> `The box 'centos/7' could not be found or could not be accessed in the remote catalog. If this is a private ・・・・・`
> のようなエラーが出たため、下記のように --insecure をつけて実行しました。*
> 
> ```
> $ vagrant box add centos/7 --insecure
> ```

<br>

#### ■仮想環境用のディレクトリを作成
```
$ mkdir -p centos7_react/data
$ cd centos7_react
```
<br>

#### ■Vagrant初期化
Vagrantfileが生成される。

```
$ vagrant init centos/7
```

<br>

#### ■生成されたVagrantfileの変更
`centos7_react/Vagrantfile`内の以下2箇所を変更。

* 変更１
`# config.vm.network "private_network", ip: "192.168.33.10"`
↓
`config.vm.network "private_network", ip: "192.168.33.10"`

* 変更2
`# config.vm.synced_folder "../data", "/vagrant_data"`
↓
`config.vm.synced_folder "./data", "/home/vagrant/data"`


<br>

#### ■ファイル共有のためプラグイン追加
```
$ vagrant plugin install vagrant-vbguest
```

<br>

#### ■vagrant起動
```
$ vagrant up
```

> vagrant up実行で
> ` The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!
・・・・・`
> のエラーが出た場合、一旦ゲストOSにログインしてyum update
>
> ```
># 仮想マシンにログイン
>$ vagrant ssh
>
># 仮想マシン上でyum update
>$ sudo yum update -y
>
># 一旦、仮想マシンからexit
>$ exit
>
># 仮想マシンの再起動
>$ vagrant reload
>```

<br>

### 【ゲストOS側】
#### ■仮想マシンにログイン
```
$ vagrant ssh
```

<br>

#### ■Node.jsのインストール
ここでは`v15.x`をインストールする。Node.jsのリポジトリは[こちらを参照。](https://github.com/nodesource/distributions/blob/master/README.md)

```
$ sudo -i
$ curl -sL https://rpm.nodesource.com/setup_15.x | bash -
$ yum install -y nodejs

# rootユーザをexit
$ exit
```
確認

```
$ node -v
v15.4.

$ npm -v
7.0.15
```

<br>

#### ■vagrantの共有ディレクトリに移動
```
cd ~/data
```
この時点のカレントディレクトリ

```
$ pwd
/home/vagrant/data
```

<br>

#### ■共有ディレクトリ`/home/vagrant/data`配下にreact用作業ディレクトリを作成
```
$ mkdir react-sample
$ cd react-sample
$ mkdir -p src/js
```
<br>
**_※以降の手順は全て作業ディレクトリ（`/home/vagrant/data/react-sample`）で実行_**


<br>

#### ■ npm環境の初期化
package.jsonが生成される。

```
$ npm init -y
```

<br>

#### ■webpackなど必要なパッケージをインストール
```
$ npm install --save-dev webpack webpack-cli webpack-dev-server
$ npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader
$ npm install --save-dev react react-dom

$ sudo npm install -g webpack webpack-cli
```

<br>

#### ■以下のファイルを作成

```./src/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>React sample</title>
  </head>

  <body>
    <div id="app"></div>
    <script src="client.min.js"></script>
  </body>
</html>
```

```./src/js/client.js
import React from "react";
import ReactDOM from "react-dom";

class Layout extends React.Component {
  render() {
    return (
      <h1>Hello world!</h1>
    );
  }
}

const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
```

```./webpack.config.js
var debug   = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path    = require('path');

module.exports = {
  context: path.join(__dirname, "src"),
  entry: "./js/client.js",
  module: {
    rules: [{
      test: /\.jsx?$/,
        exclude: /(node_modules|bower_components)/,
        use: [{
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react', '@babel/preset-env']
          }
        }]
      }]
    },

    devServer: {
      contentBase: __dirname + "/src/",
      host: "0.0.0.0"  //devServerのhost: "0.0.0.0"を追加しないと、ホストOSからゲストOSの8080ポートにアクセスできない
    },

    output: {
      path: __dirname + "/src/",
      filename: "client.min.js"
    },
    plugins: debug ? [] : [
      new webpack.optimize.OccurrenceOrderPlugin(),
      new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }),
    ]
};
```

<br>

#### ■環境変数を設定
**※これが無いと、`webpack serve`した後でソースを変更した時にhot-reloadされない**

```
$ export CHOKIDAR_USEPOLLING=true
```

<br>

#### ■webpackの簡易サーバ起動
```
$ webpack serve
```
<br>
ブラウザで`http://192.168.33.10:8080/`にアクセスすると「Hello world!」が表示される。
> <img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659480/93f37007-8680-b728-91bc-8f0fd1cce810.png">

<br>
ソースを変更すると、自動的に再コンパイルされて画面がリロードされる。
ちなみに、`webpack serve`はビルド後のファイル(ここでは`src/client.min.js`)が作業ディレクトリ上には生成されない。メモリ上に保持している？？
<br>
↓↓↓ ローカル環境で`src/js/client.js`の`<h1>Hello world!</h1>`を`<h1>Hello world2!</h1>`に変更すると自動で反映される。
> <img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659480/7de41514-2fd7-b0eb-eb52-4d196a65ce36.png">

<br>

## 参考にさせていただきました
[今から始めるReact入門 〜 React の基本](https://qiita.com/TsutomuNakamura/items/72d8cf9f07a5a30be048)