React + Webpack4 + Babel7 + TypeScriptで環境構築

#はじめに
Reactの環境構築で少し苦戦したので備忘録的な形で残したいと思い、記事にしました。
以下、今回の記事で作った環境をリポジトリにも反映しているのでよかったらこちらも参考にしてください。
https://github.com/stkzk3110/react-test-app
#環境概要

```terminal
$ node -v
v10.15.1
$ npm -v
v6.7.0
$ webpack -v
v4.29.6
```

#手順
1.プロジェクトを作りたいディレクトリまで移動し、```npm init -y```で```package.json```を新規作成。

```terminal
$ mkdir react-test-app
$ cd react-test-app/
$ npm init -y
```

2.index.htmlを作成。

```terminal
$ mkdir dist
$ cd dist/
$ touch index.html
```

```dist/index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Hello, React!</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="./bundle.js"></script>
  </body>
</html>
```

3.webpackのセットアップ
package.jsonにnpm scriptの設定を追加。
```npm run スクリプト名```で実施可能。(今回の場合は、```npm run start```で実施可。)

```terminal
$ npm install --save-dev webpack webpack-dev-server webpack-cli
+ webpack-cli@3.3.0
+ webpack-dev-server@3.2.1
+ webpack@4.29.6
```

```package.json
  "scripts": {
    ...
    "start": "webpack-dev-server --config ./webpack.config.js --mode development"
  },
　...
```
```terminal
$ touch webpack.config.js
```

```webpack.config.js
  module.exports = {
  entry: './src/index.js',
  output: {
    path: __dirname + '/dist',
    publicPath: '/',
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: './dist'
  }
};
```

```terminal
$ mkdir src
$ cd src
$ touch index.js
```

```src/index.js
console.log('Hello, React!');
```

```terminal
$ npm start
```

```localhost:8080```を開いて、デベロッパーツールを開くとconsoleに```Hello, React!```が表示されているのが確認できる。

4.Babelのセットアップ

```terminal
$ npm install --save-dev @babel/core @babel/preset-env
+ @babel/core@7.4.3
+ @babel/preset-env@7.4.3

$ npm install --save-dev babel-loader
+ babel-loader@8.0.5

$ npm install --save-dev @babel/preset-react
+ @babel/preset-react@7.0.0
```
```package.json
　...
  "babel": {
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react"
    ]
  },
  "devDependencies": {
  ...
```

```webpack.config.js
  ...
  entry: './src/index.js',
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      }
    ]
  },
  resolve: {
    extensions: ['*', '.js', '.jsx']
  },
  ...
```

5.WebpackでのReactのセットアップ、Babelでのプロジェクト構築

```terminal
$ npm install --save react react-dom
+ react@16.8.6
+ react-dom@16.8.6
```
```src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

const title = 'Hello, React!';
ReactDOM.render(
  <div>{title}</div>,
  document.getElementById('app')
);
```
```terminal
$ npm start
```

6.TypeScriptの導入
少し修正量が多いので今回、変更後のソースを公開しますのでそちらを参考にしてみてください。

```terminal
$ npm install --save @types/react @types/react-dom
+ @types/react-dom@16.8.3
+ @types/react@16.8.12
$ npm install --save-dev typescript awesome-typescript-loader source-map-loader
+ source-map-loader@0.2.4
+ typescript@3.4.2
+ awesome-typescript-loader@5.2.1
```

```terminal
$ touch tsconfig.json
$ cd src
$ mkdir components
$ cd components
$ mv index.js index.tsx
$ touch App.tsx
```

```tsconfig.json
{
    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es6",
        "jsx": "react"
    },
    "include": [
        "./src/**/*"
    ]
}
```
```webpack.config.js
const path = require('path');

module.exports = {
    entry: './src/index.tsx',
    module: {
        rules: [
            {
                test: /\.tsx$/,
                use: [{
                    loader: 'awesome-typescript-loader'
                }]
            },
            {
                test: /\.(js)$/,
                exclude: /node_modules/,
                use: [{
                    loader: 'source-map-loader',
                    options: {
                        enforce: 'pre',
                        presets: ['@babel/preset-env', '@babel/preset-react']
                    }
                }]
            }
        ]
    },
    resolve: {
        modules: [
            "node_modules",
            path.resolve('./src'),
        ],
        extensions: ['.tsx', '.js', '.ts', 'json']
    },
    output: {
      path: path.resolve(__dirname, 'dist'),
      publicPath: '/',
      filename: 'bundle.js'
    },
    devtool: "source-map",
    devServer: {
      contentBase: './dist'
    }
  };
```
```tsx:src/index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';

import { App } from './components/App';

ReactDOM.render(
  <App compiler="TypeScript" framework="React" />,
  document.getElementById('app')
);
```
```tsx:src/components/App.tsx
import * as React from "react";

export interface AppProps { compiler: string; framework: string; }

export class App extends React.Component<AppProps, {}> {
  render() {
      return <h1>Hello {this.props.compiler} and {this.props.framework}!</h1>;
  }
}
```

```terminal
$ npm start
```

これで問題なければ環境構築完了となります。
楽しいReactライフをお送りください。

#補足
TypeScriptの部分は公式ドキュメントに加えてエラー対応が入っているため、変更量が多くなってるのと不要な処理を含んでる可能性もあるのでその点ご容赦ください。

#参考
[React + Webpack 4 + Babel 7 Setup Tutorial](https://www.robinwieruch.de/minimal-react-webpack-babel-setup/)
ReactとWebpackとBabelは、ほぼこれを参考にさせていただきました。

[React & Webpack](https://www.typescriptlang.org/docs/handbook/react-&-webpack.html)
TypeScriptは公式ドキュメントを参考にしました。

[Configuration](https://webpack.js.org/configuration/)
webpack.config.jsの書き方については、ここを参考にしました。