webpack+React+Sassの環境構築

#webpack+React+Sassの環境構築
##package.jsonの準備
```package.json
{
    "name": "portforio",
    "version": "1.0.0",
    "description": "",
    "main": "main.js",
    "scripts": {
        "build": "webpack --mode=production",
        "build:dev": "webpack --mode=development",
        "watch": "webpack-dev-server --mode=development"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
        "node-sass": "^4.12.0",
        "nodemon": "^1.19.0",
        "jquery": "",
        "react": "",
        "react-dom": ""
    },
    "devDependencies": {
        "@babel/core": "^7.4.5",
        "@babel/preset-env": "^7.4.5",
        "@babel/preset-react": "^7.0.0",
        "babel": "",
        "babel-loader": "",
        "browserify": "^16.2.3",
        "css-loader": "^3.0.0",
        "mini-css-extract-plugin": "^0.7.0",
        "sass-loader": "^7.1.0",
        "style-loader": "^0.23.1",
        "vinyl-source-stream": "^2.0.0",
        "webpack": "",
        "webpack-cli": "^3.3.4",
        "webpack-dev-server": "^3.7.1",
        "webpack-stream": ""
    }
}
```
試行錯誤しながら作っていたので、不要なものもあるかもしれません。
webpackを利用するときは、`mode`を指定しないと怒られるので、実行する際に
`--mode=production`や`--mode=development`で指定をします。

##webpack.config.jsの記述
```webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports =（env, argv) => ({
    entry: path.join(__dirname, 'src/app.js'),
    output: {
        path: path.join(__dirname, 'dist/js'),
        filename: 'bundle.js'
    },
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        watchContentBase: true,
    },
    module: {
        rules: [
            //babel-loader
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-react', '@babel/preset-env']
                        }
                    }
                ],
                exclude: /node_modules/,
            },
            //css/sass-loader
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    /*
                    MiniCssExtractPlugin.loader,
                    */
                    {
                        loader: 'css-loader',
                        options: {
                            url: false
                        }
                    },
                    'sass-loader'
                ],
            },
        ]
    },
    /*
    plugins: [
            new MiniCssExtractPlugin({
            filename: 'style.css'
        }),
    ],
    */
    resolve: {
        modules: [path.join(__dirname, 'src'), 'node_modules'],
        extensions: ['.js', '.jsx']
    }
});
```

###ファイル管理

```webpack.config.js
module.exports =（env, argv) => ({
   entry: path.join(__dirname, 'src/app.js'),
   output: {
        path: path.join(__dirname, 'dist/js'),
        filename: 'bundle.js'
   }
```
`(env, argv) =>`と記述することで、`mode`を取得することができます。
（ここの仕組みは、まだイマイチわかってないです。）
`entry:`で入力元のファイルを指定します。
`path.join()`でパスを結合、第１引数に`__dirname`でファイルのあるディレクトリまでのパスを取得、第２引数に以降のパスを記述します。
似てる関数に`path.resolve()`があります。
`join`は単純に　/　でパス名をくっ付けるのに対して、`resolve`は絶対パスに変換して処理をします。

例えば、

```
path.join('/a', 'b'); //return /a/b
path.resolve('/a', 'b'); //return /a/b

path.join('/a', '/b'); //return /a/b
path.resolve('/a', '/b'); return /b
```

`resolve`の場合、第２引数以降に絶対パスを入れると、パスが上書きされるので注意です。

`output:`で出力先の指定、`filename:`出力ファイル名を指定します。

###ファイル監視機能

```webpack.config.js
devServer: {
        contentBase: path.join(__dirname, 'dist'),
        watchContentBase: true,
    }
```

`webpack-dev-server`は、ファイルの変更を監視出来るモジュールです。
`contentBase`は`output`のパスと同じにします。
`watchContentBase`はファイル監視をするかです。デフォルト値はfalseです。

###JSファイルのトランスパイル

```webpack.config.js
module: {
        rules: [
            //babel-loader
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-react', '@babel/preset-env']
                        }
                    }
                ],
                exclude: /node_modules/,
            },
```

`test:`で対象のファイルを指定します。
`use:`で使用するローダーを指定します。
`loader:`今回は`babel-loader`を使用します。ES6をES5へ変換するローダーです。
`options:` `presets:`プリセットを使用します。今回は`react`（react関連の記述を変換）と`env`（ES5へ変換）を使用します。
`exclude:`で除外するディレクトリを指定できます。node-modulesは忘れずに除外します。

###sassのバンドル

```webpack.config.js
//css/sass-loader
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    /*
                    MiniCssExtractPlugin.loader,
                    */
                    {
                        loader: 'css-loader',
                        options: {
                            url: false
                        }
                    },
                    'sass-loader'
                ],
            },
```
モジュールの使用順は下から上になるため、
`sass-loader`　（sassをcssへ変換）
`css-loader`　（cssをJSへバンドル）
`style-loader`　（ｈｔｍｌへｃｓｓを適用させる）
の順で使用されます。
この場合、CSSはbundle.js内にバンドルされます。

CSSファイルを別に取り出したい場合は、`mini-css-extract-plugin`を使用します。
その場合、`plugins:`にて出力ファイル名を指定します。

```webpack.config.json
plugins: [
            new MiniCssExtractPlugin({
            filename: 'style.css'
        }),
    ],
```