今時のフロントエンド開発2017 (3. webpack編)

# はじめに
本編では[今時のフロントエンド開発2017 (2. 構築編)](http://qiita.com/Lyude/items/c4250b6be4eeece90348)に続きwebpackを使っていきます。

## おしながき
* [今時のフロントエンド開発2017 (1. 愚痴編)](http://qiita.com/Lyude/items/783a972bace33002455c)
* [今時のフロントエンド開発2017 (2. 構築編)](http://qiita.com/Lyude/items/c4250b6be4eeece90348)
* [今時のフロントエンド開発2017 (3. webpack編)](http://qiita.com/Lyude/items/7b8104418a5dd03c7d30)
* 今時のフロントエンド開発2017 (4. TypeScript編)
* 今時のフロントエンド開発2017 (5. もっと効率よく編)

# webpack

## webpack.config.js
webpackでバンドルするファイルの設定をします。
プロジェクトディレクトリに`webpack.config.js`を作ります。

```
modern-front-end
│
+-- node_modules
| `-- *
|
+-- src
|
+-- package.json
`-- webpack.config.js <
```

`webpack.config.js`に次のように記述します。

```js:webpack.config.js
var path = require('path');

module.exports = [{
    entry: ['./src/app.js'],
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'public')
    }
}];
```

各項目の意味

<dl>
  <dt>entry</dt>
  <dd>
バンドルのエントリポイントとなるファイルのパスを指定します。<br>
この場合は`modern-front-end/src/app.js`がバンドルのエントリポイントになります。
  </dd>

  <dt>output</dt>
  <dd>
ビルド時の出力に関するオプションを指定します。
  </dd>

  <dt>output.filename</dt>
  <dd>
出力するファイル名を指定します。
  </dd>

  <dt>output.path</dt>
  <dd>
出力するディレクトリを絶対パスで指定します。<br>
この場合は`modern-front-end/public/`にビルドしたファイルが出力されます。
  </dd>
</dl>

## webpackのエントリポイントを作成する
`modern-front-end/src/app.js`となるようにファイルを作成します。

```
modern-front-end
│
+-- node_modules
| `-- *
|
+-- src
| `-- app.js <
|
+-- package.json
`-- webpack.config.js
```

次に`app.js`に以下のように処理を記述します。
今回は標準出力をしてみます。

```js:app.js
console.log('hello, world');
```

## HTMLを書く
`modern-front-end/public/index.html`となるようにHTMLを作成します。

```
modern-front-end
|
+-- node_modules
| `-- *
|
+-- public <
| `-- index.html <
|
+-- src
| `-- app.js
|
+-- package.json
`-- webpack.config.js
```

作成したらサクッとHTMLを書いて`bundle.js`を読み込みましょう。
Emmetを使うと今後も楽にマークアップできるのでオススメです。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>modern-front-end</title>
        <script src="./bundle.js"></script>
    </head>
    <body>
        <p>hello, world</p>
    </body>
</html>
```

## npm-scriptsを設定する
npm-scriptsを通してwebpackを実行する準備をします。
package.jsonの`scripts`に`"build": "webpack"`を追記します。

```json:package.json
{
  "scripts": {
    "webpack": "webpack"
  }
}
```

npm-scriptsは`npm run`で実行できます。

## webpackでビルドしてみる
それでは実際にwebpackでビルドしてみます。
プロジェクトディレクトリで次のコマンドを実行してみましょう。

```
npm run webpack
```

以下のようなログが出力されれば成功です。

```
Version: webpack 2.3.2
Child
    Hash: fedbbe24aa69ef7f1937
    Time: 43ms
        Asset     Size  Chunks             Chunk Names
    bundle.js  2.78 kB       0  [emitted]  main
       [0] ./src/app.js 29 bytes {0} [built]
       [1] multi ./src/app.js 28 bytes {0} [built]
```

すると，`modern-front-end/public/`に`bundle.js`というファイルができあがっているのが確認できます。

```
modern-front-end
|
+-- node_modules
| `-- *
|
+-- public
| +-- bundle.js <
| `-- index.html
|
+-- src
| `-- app.js
|
+-- package.json
`-- webpack.config.js
```

ブラウザで`modern-front-end/public/index.html`を開き，デベロッパーツールのコンソールで標準出力できているか確認します。

<img width="275" src="https://qiita-image-store.s3.amazonaws.com/0/128213/ac3f365c-8edc-fa8b-2265-6e4f6b63f3ed.png">

## バンドルファイルを圧縮する
`modern-front-end/public/bundle.js`を開いてみると長々と何か書いてあります。
しかし，改行やらインデントやらでこれでは冒頭に問題としてあげた”[無駄の多いデータ](http://qiita.com/Lyude/items/783a972bace33002455c#%E7%84%A1%E9%A7%84%E3%81%AE%E5%A4%9A%E3%81%84%E3%83%87%E3%83%BC%E3%82%BF)”そのものなので圧縮します。
`bundle.js`の圧縮は`--optimize-minimize`を指定することできます。

次のコマンドを実行しましょう。
`npm run`でオプションを付けるには`--`を間に挟みます。

```
npm run webpack -- --optimize-minimize
```

ビルド後もう一度`bundle.js`を確認すると無駄な改行やインデントが削除されファイルサイズが小さくなったことがわかります。

## デバッグできるようにする
ブラウザのコンソールに表示されているログから`console.log('hello, world');`した箇所をデバッグ画面に表示してみます。

<img width="960" src="https://qiita-image-store.s3.amazonaws.com/0/128213/b104d543-97ca-670a-d3cf-21706b425eb1.png">

JavaScriptを圧縮してしまうと次の画像のようにすべて1行で出力されるのでデバッグができなくなってしまいます。

<img width="960" src="https://qiita-image-store.s3.amazonaws.com/0/128213/b72b2683-4954-05d8-b02e-a0c15cc8d965.png">

そこで，`--devtool source-map`オプションを付けてソースマップを作成できるようにします。
次のコマンドを実行しましょう。

```
npm run webpack -- --optimize-minimize --devtool source-map
```

ビルドが終わると`modern-front-end/public/bundle.js.map`というファイルができます。

```
modern-front-end
|
+-- node_modules
| `-- *
|
+-- public <
| +-- bundle.js
| +-- bundle.js.map <
| `-- index.html
|
+-- src
| `-- app.js
|
+-- package.json
`-- webpack.config.js
```

デベロッパーツールの`Sources`タブの左ペインから`webpack://` `./src` `app.js`の順で開いて確認してみます。

<img width="960" src="https://qiita-image-store.s3.amazonaws.com/0/128213/f912ed58-7914-c6a4-b6d0-317b8c12a04c.png">

とても見やすくなりました。

## 毎回ビルドするのが面倒くさい
毎回ビルドするのが面倒なのでファイルの変更を監視してビルドできるようにします。
`--watch`オプションを付けることで監視状態になります。

```
npm run webpack -- --optimize-minimize --devtool source-map --watch
```

これで`app.js`を更新するたびに自動的にビルドされるようになりました。
抜け出すにはCLIで`Ctrl-C`を押します。

`--watch`はキャッシュを利用した差分ビルドによって，更新のあったファイルのみ変更が加えられるので高速にビルドすることができます。

## コマンドが長くて面倒くさい
コマンドが長いのでnpm-scriptsを使って工夫します。
package.jsonの`scripts`を次のように書き直します。

```json:package.json
{
  "scripts": {
    "start": "webpack --progress --devtool source-map --watch",
    "build": "webpack --progress --optimize-minimize",
  }
}
```

先程までのコマンドとは少し違うので気をつけてください。
`--progress`はビルドの経過を表示するオプションです。

`start`は開発用の設定でソースマップの生成や監視状態でビルドします。
`build`はプロダクション用で圧縮を有効化しています。

`start`は特別で`npm start`と記述するだけで実行できます。
プロダクション用にビルドする場合は`npm run build`を実行します。

## CSSをバンドルする準備
CSSをバンドルするために`webpack.config.js`にローダーを登録します。

```js:webpack.config.js
var path = require('path');

module.exports = [{
    entry: ['./src/app.js'],
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'public')
    },
    module: {
        rules: [{
            test: /\.(css|sass|scss)$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader'
            ]
        }]
    }
}];
```

## SCSSを書く
CSSをバンドルするためにSassを書いていきます。
SassにはSASS記法とSCSS記法がありますが今回はSCSS記法で書いていきます。
ここらへんはお好みでどうぞ。

`modern-front-end/src/scss/style.scss`を作成します。

```
modern-front-end
|
+-- node_modules
| `-- *
|
+-- public
| +-- bundle.js
| +-- bundle.js.map
| `-- index.html
|
+-- src
| +-- scss <
| | `-- style.scss <
| |
| `-- app.js
|
+-- package.json
`-- webpack.config.js
```

`style.scss`に以下のように記述します。

```scss:style.scss
body {
    color: darkcyan;
}
```

このままでは`style.scss`はどこからも参照されていないので，エントリポイントである`app.js`から`style.scss`を参照します。

```js:app.js
var css = {
    style: require('./scss/style.scss')
};

console.log('hello, world');
```

監視状態のまま`webpack.config.js`を変更した場合は反映されないのでビルドし直してください。
ビルドされたらブラウザで確認してみます。

<img width="642" src="https://qiita-image-store.s3.amazonaws.com/0/128213/700f1a95-9012-c62b-2b2e-3ab4eac33dad.png">

`style.scss`に書いた内容が`<style>`で展開されているのがわかります。
画面内の`hello, world`の文字色が変わっていることも確認してください。

## ベンダープレフィックスを付ける
`postcss-loader`と`autoprefixer`を使ってビルド時にベンダープレフィックスを付けるようにします。

```js:webpack.config.js
var path = require('path');

module.exports = [{
    entry: ['./src/app.js'],
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'public')
    },
    module: {
        rules: [{
            test: /\.(css|sass|scss)$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader',
                {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function () {
                            return [
                                require('autoprefixer')
                            ];
                        }
                    }
                }
            ]
        }]
    }
}];
```

ベンダープレフィックスを付けてくれるか確認するために`style.scss`も変更します。
※ブラウザのCSS3対応が進み，以下の例ではプレフィックスがつかないのでその下の [2017/09/20 追記分](https://qiita.com/Lyude/items/7b8104418a5dd03c7d30#20170920-%E8%BF%BD%E8%A8%98%E5%88%86) を試してください。

>```scss:style.scss
>body {
>    color: darkcyan;
>    transition: all .1s ease;
>}
>```
>
>~~ビルドしなおしたらブラウザで確認してみます。~~
>
><img width="960" src="https://qiita-image-store.s3.amazonaws.com/0/128213/b5e0fae4-8b7f-69e4-fd7a-933f584adca1.png">
>
>~~ベンダープレフィックスが自動で付与されていることがわかります。~~

### 2017/09/20 追記分

```scss:style.scss
.example {
    display: flex;
    transition: all .5s;
    user-select: none;
    background: linear-gradient(to bottom, white, black);
}
```

ビルドしなおしてブラウザで確認すると`<head>`タグ内の`<style>`にプレフィックスが付いていることが確認できます。

```html
<style>
    .example {
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        background: linear-gradient(to bottom, white, black);
        transition: all .5s;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }
</style>
```

# url-loaderを使ってみる
url-loaderはCSS中で使用するアセットをBase64エンコードしたdata URIとしてバンドルできるようにします。
指定したファイルサイズより大きい場合は外部ファイルとして読み込みます。

なんでも良いですが例として次の画像をバンドルしてみます。
ファイル名は`qiita.png`とします。

![Qiita](https://qiita-image-store.s3.amazonaws.com/0/128213/8bbfdf9c-c576-cf7f-99fe-c4d8352428bd.png)
qiita.png

`qiita.png`を`modern-front-end/src/img/qiita.png`となるように配置します。

```
modern-front-end
|
+-- node_modules
| `-- *
|
+-- public
| +-- bundle.js
| +-- bundle.js.map
| `-- index.html
|
+-- src
| +-- img <
| | `-- qiita.png <
| |
| +-- scss
| | `-- style.scss
| |
| `-- app.js
|
+-- package.json
`-- webpack.config.js
```

## webpackの設定をする
`webpack.config.js`を以下のように修正します。

```js:webpack.config.js
var path = require('path');

module.exports = [{
    entry: ['./src/app.js'],
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'public')
    },
    module: {
        rules: [{
            test: /\.(css|sass|scss)$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader',
                {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function () {
                            return [
                                require('autoprefixer')
                            ];
                        }
                    }
                }
            ]
        }, {
            test: /\.(jpe?g|png|gif|svg|ico)(\?.+)?$/,
            use: {
                loader: 'url-loader',
                options: {
                    limit: 8192,
                    name: './img/[name].[ext]'
                }
            }
        }]
    }
}];
```

各項目の意味は次のとおりです。

<dl>
  <dt>test</dt>
  <dd>
`.jpg` `.jpeg` `.png` `.gif` `.svg` `.ico`を対象として指定しています。<br>
`(\?.+)?`はクエリパラメータが付いていた場合でもファイルを対象にするために付けています。
  </dd>

  <dt>use.loader</dt>
  <dd>
指定したファイルに対して`url-loader`を使うように設定しています。
  </dd>

  <dt>use.options.limit</dt>
  <dd>
指定したバイト数以内のファイルをバンドルするように設定しています。<br>
指定したバイト数を上回った場合はfile-loaderの機能を利用して外部ファイルとして参照します。<br>
この場合8KB以上のファイルは除外されます。
  </dd>

  <dt>use.options.name</dt>
  <dd>
`use.options.limit`を超えた場合はBase64エンコードされずにリンクを保ったまま出力用のディレクトリにコピーされます。<br>
`use.options.name`はコピーされる場合のファイルパスを指定します。<br>
[name]と[ext]を使うことで元のファイル名と拡張子を維持できます。
  </dd>
</dl>

## SCSSを修正する
`style.scss`を次のように修正します。

```scss
body {
    color: darkcyan;
    transition: all .1s ease;
}

p:before {
    display: inline-block;
    width: 1em;
    height: 1em;
    background-image: url("../img/qiita.png");
    background-size: contain;
    content: "";
}
```

## 確認する
ビルドしたらブラウザをリロードして<img height="20" src="https://qiita-image-store.s3.amazonaws.com/0/128213/6ababac6-fe7f-3d46-f515-4bfa5a5d7885.png">と表示されていることを確認します。
正しく表示されていることを確認したらデベロッパーツールの`Network`を確認します。

<img width="960" src="https://qiita-image-store.s3.amazonaws.com/0/128213/8e0d0a3c-c1c3-1ffd-8292-3b7df35b211d.png">

`data:image/png;`から始まる名前のリクエストが確認できます。
よく見てみると`Size`が`(from memory cache)`になり，`Time`が`0 ms`になっています。
ちなみに，data URIによるリクエストを除外して外部へのリクエストだけを表示するには赤枠で囲った`Hide data URLs`をチェックします。

次に`<style>`に展開されたCSSも確認してみます。

<img width="642" src="https://qiita-image-store.s3.amazonaws.com/0/128213/af8cad23-8374-3d59-b10e-238bd2b27abe.png">

`qiita.png`への参照がurl-loaderによってBase64エンコードされていることが確認できます。
Base64エンコードされた画像はブラウザがデコードして画面上に表示します。
ですので，新しくネットワークを介したリクエストが発生しなくなり，`Size`はメモリキャッシュから読み込むため`Time`は0ミリ秒になります。

もう少し細かく追ってみます。
デベロッパーツールの`Sources`から`qiita.png`を確認してみます。

<img width="792" src="https://qiita-image-store.s3.amazonaws.com/0/128213/e2c06317-8f8f-38ca-2789-017dc884a8cc.png">

画像は`bundle.js`に含まれているため実際には存在しませんが，ソースマップを有効にしている場合は`qiita.png`がどのように扱われているかを確認することができます。

# file-loaderを使ってみる
file-loaderはファイルをバンドルせずに外部ファイルの参照を保つためのローダーです。

## Font Awesomeで試す
Font AwesomeはAwesomeなアイコンフォントです。
file-loaderを使ってFont Awesomeを使ってみましょう。

まずは次のコマンドでFont Awesomeをインストールします。

```bash
$ npm install -save font-awesome
```

ソースコードから利用するパッケージなので`--save`オプションにしました。
`package.json`を見るとfont-awesomeの依存関係が`dependencies`になっているのがわかります。

```json:package.json
{
  "name": "modern-front-end",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack --optimize-minimize --devtool source-map --watch",
    "build": "webpack --optimize-minimize --devtool source-map"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "font-awesome": "^4.7.0"
  },
  "devDependencies": {
    "autoprefixer": "^6.7.7",
    "css-loader": "^0.27.3",
    "file-loader": "^0.10.1",
    "node-sass": "^4.5.1",
    "postcss-loader": "^1.3.3",
    "sass-loader": "^6.0.3",
    "style-loader": "^0.16.0",
    "ts-loader": "^2.0.3",
    "url-loader": "^0.5.8",
    "webpack": "^2.3.2"
  }
}
```

## Font Awesomeを読み込む
`webpack.config.js`を以下のように修正します。

```js:webpack.config.js
var path = require('path');

module.exports = [{
    entry: ['./src/app.js'],
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'public')
    },
    module: {
        rules: [{
            test: /\.(css|sass|scss)$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader',
                {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function () {
                            return [
                                require('autoprefixer')
                            ];
                        }
                    }
                }
            ]
        }, {
            test: /\.(jpe?g|png|gif|svg|ico)(\?.+)?$/,
            include: [
                path.resolve(__dirname, 'src', 'img')
            ],
            use: {
                loader: 'url-loader',
                options: {
                    limit: 8192,
                    name: './img/[name].[ext]'
                }
            }
        }, {
            test: /\.(eot|otf|ttf|woff2?|svg)(\?.+)?$/,
            include: [
                path.resolve(__dirname, 'node_modules')
            ],
            use: {
                loader: 'file-loader',
                options: {
                    name: './fonts/[name].[ext]'
                }
            }
        }]
    }
}];
```

Font Awesomeのスタイルシートを参照するために`app.js`を次のように修正します。

```js:app.js
var css = {
    fontAwesome: require('font-awesome/scss/font-awesome.scss'),
    style: require('./scss/style.scss')
};

console.log('hello, world');
```

ここで書いている`font-awesome`は相対パスではありません。
npmによって`font-awesome`に対してパスが通っているのでパッケージ名として記述しています。
区別するために相対パスは常に`./`を付けておくと良いでしょう。

続けて`index.html`でFont Awesomeを使ってみます。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>modern-front-end</title>
        <script src="./bundle.js"></script>
    </head>
    <body>
        <p>
            <i class="fa fa-font-awesome" aria-hidden="true"></i>hello, world
        </p>
    </body>
</html>
```

ビルドすると`modern-front-end/public/fonts/`にフォントファイルがコピーされます。

```
modern-front-end
|
+-- node_modules
| `-- *
|
+-- public
| +-- fonts <
| | +-- fontawesome-webfont.eot <
| | +-- fontawesome-webfont.svg <
| | +-- fontawesome-webfont.ttf <
| | +-- fontawesome-webfont.woff <
| | `-- fontawesome-webfont.woff2 <
| |
| +-- bundle.js
| +-- bundle.js.map
| `-- index.html
|
+-- src
| +-- scss
| | `-- style.scss
| |
| `-- app.js
|
+-- package.json
`-- webpack.config.js
```

画面を確認して<img height="20" src="https://qiita-image-store.s3.amazonaws.com/0/128213/cd3f4166-67b4-a0a9-fc04-9e4ff1a7f3cd.png">と表示されていれば読み込めています。
続けてデベロッパーツールの方も確認してみます。

<img width="960" src="https://qiita-image-store.s3.amazonaws.com/0/128213/d1e1c133-4baa-e57f-c943-7ae0b35627bd.png">

`fontawesome-webfont.woff2`が読み込まれているのが確認できます。

## 同じ拡張子のファイルが存在する場合
Font Awesomeを使う際に`webpack.config.js`で画像を指定している`test: /\.(jpe?g|png|gif|svg|ico)(\?.+)?$/`とフォントを指定している`test: /\.(eot|otf|ttf|woff2?|svg)(\?.+)?$/`で`.svg`ファイルの指定が重複しています。
指定した内容が重複すると片方の設定しか反映されず意図した動作をしません。

例えば，この場合は画像として用意した`.svg`ファイルも`modern-front-end/public/fonts/`にコピーされてしまいます。
このような場合はurl-loaderやfile-loaderを使う際に`include`という項目を追加します。

`include`は`test`で指定するファイルの場所を限定する場合に使用します。
画像を指定している側の`include`は`modern-front-end/src/img/`内から参照し，フォントを指定している`include`は`modern-front-end/node_modules`内から参照しています。
こうすることで`modern-front-end/src/img/`に置いた`.svg`は`modern-front-end/public/img/`にコピーされ，Font Awesomeで使用するフォントは`modern-front-end/public/fonts/`にコピーされます。

# webpack-dev-serverを使ってみる
webpack-dev-serverはローカルサーバーを使ってビルドと同時にブラウザの画面更新を行ってくれるパッケージです。
webpack-dev-server-を使うことでエディターとブラウザを行ったり来たりしては更新するといった手間が省けます。
さらに，Hot Module Replacementと呼ばれる機能を使って画面全体ではなくビルドした部分だけ更新することもできます。

## webpack-dev-serverインストールする
次のコマンドでwebpack-dev-serverをインストールします。

```bash
$ npm install --save-dev webpack-dev-server
```

## `webpack.config.js`を書き換える
`webpack.config.js`に`devServer`プロパティを追記してwebpack-dev-serverの設定をします。

```js:webpack.config.js
var path = require('path');

module.exports = [{
    entry: ['./src/app.js'],
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'public')
    },
    devServer: {
        contentBase: path.resolve(__dirname, 'public')
    },
    module: {
        rules: [{
            test: /\.(css|sass|scss)$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader',
                {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function () {
                            return [
                                require('autoprefixer')
                            ];
                        }
                    }
                }
            ]
        }, {
            test: /\.(jpe?g|png|gif|svg|ico)(\?.+)?$/,
            include: [
                path.resolve(__dirname, 'src', 'img')
            ],
            use: {
                loader: 'url-loader',
                options: {
                    limit: 8192,
                    name: './img/[name].[ext]'
                }
            }
        }, {
            test: /\.(eot|otf|ttf|woff2?|svg)(\?.+)?$/,
            include: [
                path.resolve(__dirname, 'node_modules')
            ],
            use: {
                loader: 'file-loader',
                options: {
                    name: './fonts/[name].[ext]'
                }
            }
        }]
    }
}];
```

## npm-scriptsを書き換える
開発ビルドでwebpack-dev-serverを使うように`package.json`を編集します。

```json:package.json
{
  "scripts": {
    "start": "npm run serve",
    "build": "webpack --progress --optimize-minimize",
    "serve": "webpack-dev-server --hot --inline --devtool source-map"
  }
}
```

Hot Module Replacementを無効にしたい場合はnpm-scriptsの`--hot`オプションを削除します。

## 確認する
`npm start`を実行してwebpack-dev-serverを立ち上げます。
ビルドできたらブラウザで`http://localhost:8080/`にアクセスします。
正しく表示されていれば，差分ビルドするたびにブラウザ上の画面も自動的に更新されます。

正しく表示されない場合は`modern-front-end/public/`に`index.html`が存在するか確認してください。
`webpack.config.js`の`devServer.contentBase`で指定した場所にHTMLが存在しないと表示することができません。

## webpack-dev-serverの動き
webpack-dev-serverはビルドしたファイルはメモリ上に展開するので出力用ディレクトリにファイルは出力されません。
また，ビルド後のファイルが出力用ディレクトリに存在している必要もありません。
これらのことは`index.html`以外のファイルを`modern-front-end/public/`から削除しても正常に表示されることからわかります。

`bundle.js`やその他アセットのURLについては，`webpack.config.js`の`output.path`で指定した場所と相対的に同じ位置になります。
つまり，`output.path`で指定した`modern-front-end/public/`と`http://localhost:8080/`が同じ位置になります。
`bundle.js`ですと`modern-front-end/public/bundle.js`は`http://localhost:8080/bundle.js`になります。

詳細は[ドキュメント](https://webpack.github.io/docs/webpack-dev-server.html)に書かれているので一度目を通してみてください。

# ちょっと考察

## バンドルするファイル
url-loaderでバンドルするファイルですが，Font Awesomeなどのフォントファイルは`bundle.js`に含めないほうが良いです。
フォントファイルはブラウザによって読み込める種類が異なるので`.eot`や`.woff`などが用意されています。
つまり，フォントファイルは1回のセッションにつきすべてが読み込まれるわけではないので，すべて含めてしまうと読み込まれることのないファイルの分だけ`bundle.js`のファイルサイズが大きくなってしまいます。
こういったバンドルしないものは`file-loader`を指定してしまった方が良いです。

画像などのメディアをBase64エンコードすると元のデータに比べファイルサイズが30~40%ほど増加すると言われていますが，サーバー側でレスポンスをgzipで圧縮して転送するようになっていればこの増加分は2~3%まで減らすことができます。

容量の大きなファイルをバンドルしてしまうとバンドルファイル自身のファイルサイズが増えてしまうので，なんでもかんでもバンドルせずによく考えることを心がけましょう。

Hot Module Replacementや`index.html`を開発用ディレクトリに含めるかどうかは予め開発方針を決めて選択すると良いでしょう。