はじめてのWebpack設定 本番用 開発用

#はじめに
個人開発を作成した時に、webpack設定の学習も兼ねて組み込んでみました。
今回は、組み込んだ内容を中心に解説していきます。
バージョンは`webpack4.44.2`を使用しました。

#webpackとは
webpackとは、複数のJSファイルを一つのモジュールバンドラ（ファイル）にまとめることを指します。
JSファイルだけでなく、CSSや画像ファイルもモジュールバンドラにまとめることが出来ます。

![https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS6Wwa5VeyiwF0GLUaAwYhVJJ_kF-XWRY4y7A&usqp=CAU](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS6Wwa5VeyiwF0GLUaAwYhVJJ_kF-XWRY4y7A&usqp=CAU)

## 用途・メリット
- 用途
　・BabelでJavaScriptをトランスパイルできる
　・CSSのコンパイル
　・画像圧縮
　などなど、プラグインを使用することでパフォーマンスの最適化に繋がる。

- メリット
　色々な参考記事をみて、僕の主観的なメリットとしては
　・ファイルサイズが少ないことで、通信量や保守性が上がる。
　・ライブラリの依存関係を解決して出力してくれる。
　・不要なコードや無駄のファイルを圧縮して、ファイルサイズを軽くする。

`react`や`vue`などのフレームワークを使用していると、コンポーネント毎のファイルが増えると思います。そのファイル数を、一まとめにし以上の用途やメリットがあげられるかと思います。

## 使用する上で気をつけたこと。。
今回は、本番用と開発用を`webpack-merge`で分けて作業しました。
また、作業する上で以下のインストールしたものを使用しました。

### インストールしたもの
- webpack v4.44.2
- webpack-cli v3.3.12
　　∟webpackコマンドでwebpackを使用するため

- webpack-dev-server v3.11.0 
　　∟ブラウザに表示し、ファイルの変更を監視

- weboack-merge v5.7.3
　　∟開発用と本番用に分けることができる

- clean-webpack-plugin v3.0.0
　　∟不要なファイルを削除

- html-webpack-plugin v4.5.0
　　∟自動でバンドルされたファイルをhtmlに読み込む（開発途中で変更された時に、自動でかえてくれる）

- image-webpack-plugin v6.0.0
　　∟画像を圧縮

- tester-webpack-plugin v4.2.3
　　∟console.logを本番用のバンドル時に削除

- file-loader v6.1.1
　　∟画像（jpg,pngなど）を出力

- style-loader v1.3.0
　　∟CSSを出力

- css-loader v4.3.0
　　∟CSSをcommonJSに変換

- ts-loader v7.0.5
　　∟TypeScriptをトランスコンパイル、また静的コード分析・ES2015以降の構文に変換

### ディレクトの構成

簡単なディレクトリの構成が以下になります。

```
┣━ /build
┃    ┣━ /images
┃    ┣━ /js
┃    ┃   ┗━ bundle.js
┃    ┗━ index.html
┣━ /public
┃    ┗━ index.html
┣━ /src
┃    ┣━ index.html
┃    ┗━ index.tsx ------エントリーポイント
┃
┣━ package.json
┣━ package-lock.json
┣━ webpack.common.js 
┣━ webpack.dev.js
┗━ webpack.prov.js
```

### package.jsonのscripts管理

`--config webpack.[dev or prod].js`を指定する。また、`webpack-dev-server`を使用する際は、`webpack-dev-server`を書き込む

```json:package.json
"scripts": {
    "start": "webpack-dev-server --config webpack.dev.js",
    "test": "jest",
    "build": "webpack --config webpack.prod.js"
  },
```

##共通設定 webpack.common.js
本番用と開発用に共通するファイルを`webpack.common.js`として作成します。

```javascript:webpack.common.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");

module.exports = () => {
  return {
    entry: {
      bundle: "./src/index.tsx", //エントリーポイント
    },
    output: {
      path: path.resolve(__dirname, "build"), // バンドルファイルの指定
      filename: "js/[name].js", // nameはentryで指定したファイル名を作成
    },
    resolve: {
      extensions: [".ts", ".js", ".tsx", ".jsx"], //　コンパイルする言語指定
    },

    module: {
      rules: [
          test: /\.css$/i,
          use: [
            // cssを出力するローダー
            "style-loader",
            // css をcommonJSに変換するローダー
            "css-loader",
          ],
        },
        {
          test: /\.tsx?$/,
          loader: "ts-loader",　// TSでトランスコンパイル
          include: path.resolve(__dirname, "src"),
          exclude: /node_module/,
        },
        {
          test: /\.(jpg|png)$/,　// 画像（jpg or png）を出力するローダー
          use: [
            {
              loader: "file-loader",
              options: {
                name: "[name].[contenthash].[ext]",
                outputPath: "images",
                publicPath: "/images",
              },
            },
            "image-webpack-loader", //画像を圧縮
          ],
        },
      ],
    },
    devtool: "source-map",
    plugins: [
      new HtmlWebpackPlugin({ template: "./src/index.html" }),
      new CleanWebpackPlugin(),
    ],
    //パフォーマンスヒントの表示方法を構成する
    performance: { hints: false },　// 250kBを超えるアセットなので、perfomaneceを追加
  };
};


```


###開発用 development
共通設定`webpack.common.js`を使用ため、`webpack-merge`を読み込む。
開発用なので、`mode`は`development`を指定。

```javascript:webpack.dev.js

const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const path = require("path");

module.exports = merge(common(), {
  mode: "development",
  // webpack-dev-serverの設定
  devServer: { 
    open: true, // ブラウザに表示するためtrueへ 
    contentBase: path.resolve(__dirname, "public"), // publicディレクトリのサーバーを開く
    port: "9000", // サーバーのポート番号
    historyApiFallback: true,// 存在しないパスをリクエストされた場合に、404を返さずにファイルを戻す
  },
  devtool: "cheap-module-eval-source-map",　// ビルドの速度とデバックの品質を保つ
});
```
devtoolのソースマップについては、様々な設定があり種類毎にビルドの速度やデバックに品質が異なります。
今回は無難に、`cheap-module-eval-source-map`を使用しました！
ちなみに[公式サイト](https://webpack.js.org/configuration/devtool/)はこちらです。

###本番用 production
本番用なので、`mode`は`priduction`を指定。

```javascript:webpack.prod.js

const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const TerserPlugin = require("terser-webpack-plugin");

module.exports = merge(common(), {
  mode: "production",
  //terser-webpack-pluginの設定
  optimization: {
    minimizer: [
      new TerserPlugin({
        extractComments: false, //falseでライセンスコメントを抽出し削除。 trueだと抽出したファイルを生成する
        terserOptions: {
          compress: {
            drop_console: true, //trueでconsole.logの削除
          },
        },
      }),
    ],
  },
});

```

#参考記事
技術記事[https://zenn.dev/nozomi_iida/articles/a4c75f79b754e9](https://zenn.dev/nozomi_iida/articles/a4c75f79b754e9)
公式[https://webpack.js.org/](https://webpack.js.org/)

#感想
ポートフォリオを作成する中で一から開発環境を作成することに意識し、webpackの重要性と役割を勉強しながらポートフォリオに組込み、作成しました。開発における品質を高めてくれることを実感しましたし共同開発時にとても役立つと思いました。次は`webpack v5`に挑戦してみたいです！