Webpackをシンプルに理解しよう

# はじめに

ねぇまってむり 
webpackでこれ以上消耗するの
つらいょ

というみなさんへ
**これを期に 理解しましょう webpack**

> 今回の記事は webpack の公式ドキュメント[https://webpack.js.org/](https://webpack.js.org/)[ (CC BY 4.0) ](https://creativecommons.org/licenses/by/4.0/)から内容をたくさん引用しています。ありがとう Webpack チーム!

# 本題に入る前に

何故webpackを使うのかを考えてみましょう:thinking:
こういうのは何故必要かも理解しておくと有り難みが増すんやで。

## はるか昔の javascript

有史以前、ブラウザでJavaScriptを実行する方法は2つありました:point_up_2:

まず１つ目としてスクリプトタグで各機能ごとに切り分けたファイルを読み込む方法があります。しかし大量のスクリプトをロードするとネットワークのボトルネックが発生する可能性があるため、この方法ではスケーリングが困難であると考えられました。
 2番目の選択肢は、すべてのプロジェクトコードを含む大きな .jsファイルを使うことです。しかしこの方法もスコープ、サイズ、読みやすさ、そして保守のしやすさに問題がありました。

## IIFE's - 即時関数

`即時関数`は大規模プロジェクトのスコープの問題を解決しました。
スクリプトファイルが即時関数によってラップされている場合は、スコープの競合を気にせずにファイルを安全に連結、結合ができるのです:sunglasses:

即時関数が一世を風靡しMake、Gulp、Grunt、Broccoli、Brunchなどのツールにつながりました。

しかしこれらのツールも１つのファイルの変更で毎回ビルドし直すというバリだるい問題がありました:sweat:

> 即時関数でまるごと関数をラップしているライブラリ例としてこちら [howler.js](https://github.com/goldfire/howler.js) を御覧ください。src/howler.core.jsは即時関数で丸ごとラップされています。

## Node.jsの登場

`Node.js`はブラウザ環境外のコンピュータやサーバーで使用できるJavaScriptランタイムです。

さらに`CommonJS`が登場し、 `require`を導入しました。requireにより必要な各モジュールをインポートすることでスコープの問題を解決しました。

しかしCommonJSは独自仕様だったためブラウザサポートはまだありません、というかもうサポートしないでしょう:joy:
今後は`import`, `export`に代表されるECMAScript Modulesが標準になる予定です。しかしこちらもブラウザのサポートは不完全です。
ブラウザでも`require`, `import`を使いたい、その声に応えるために`モジュールバンドラー`が誕生しました:baby:

## モジュールバンドラー

ブラウザで`require`はサポートされないと分かった結果Browserify、RequireJS、SystemJSなどの**モジュールバンドラー**が作成されました。
モジュールバンドラーの役割は、機能ごとに分割されたソースファイルをNode.jsを使って一纏めのバンドルファイルにすることです。
そしてバンドルファイルをスクリプトタグを使って読み込みます。
モジュールバンドラーのおかげで`require`や`import`を間接的にブラウザで使えるようになりました:sunglasses:

# Webpack

`Webpack`はBrowserify、RequireJS、SystemJSなどの仲間のモジュールバンドラーです。
モジュールバンドラーの中ではデフェクトスタンダードになりつつあります、多分。
Webpack使えても損はないだろうし、ま、多少はね？

## webpack.config.js

webpackを理解すると言うことは`webpack.config.js`を理解することと言っても過言ではありません。
しかしwebpack.config.jsは初見だとなかなか読めないです。
なのでwebpack.config.jsを読む場合は以下の5つに注目してください。これさえ押さえておけば何となく読めるようになります。

1. Mode
2. Entry
3. Output
4. Loader
5. Plugin

Webpack.config.jsを何となく読めるようになったらwebpackの入門は終了です。

### Mode

Webpack.config.jsの`mode`パラメータを`development`、 `production`または`none`のいずれかに設定することで、それぞれの環境に対応して最適化することができます。 デフォルト値は `production`です。


```javascript:webpack.config.js
module.exports = {
  mode: 'production'
};
```

簡単に説明すると開発版と製品版を切り替える為に使います。
こちらの記事が分かり易かったです。
[webpackで開発用/本番用の設定を分ける](https://qiita.com/teinen_qiita/items/4e828ac30221efb624e1)

### Entry

webpackがバンドルするためのエントリーポイント（一番はじめに読み込むファイル）を指定します。


``` js
module.exports = {
  entry: './path/to/my/entry/file.js'
};
```

### Output

作成したバンドルをどこに出力するか、およびこれらのファイルの命名方法をwebpackに指示します。 デフォルトのメインの出力ファイルは `./dist/main.js`です。


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

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};

//  dist/my-first-webpack.bundle.jsというバンドルファイルが出力されます。
```

### Loader

Loaderの概念はwebpackを理解する時に最優先で覚えるべきです。
**何も設定がない場合webpackはJavaScriptとJSONファイルしか理解できません(超大事)。** 
jsファイル内でcssファイルをimportしたい場合などはLoaderを指定する必要があります。
Loaderを指定することで様々な種類のファイルを使用可能なモジュールに変換します。

Loaderはmoduleプロパティのrules内で配列で指定します。
1. `test`プロパティはどのファイルを変換するべきかを正規表現で識別します。
2. `use`プロパティは、正規表現に引っかかったファイルがどのローダーを使って変換を行うべきかを示します。


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

module.exports = {
  output: {
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
       { test: /\.css$/, use: 'css-loader' },
       { test: /\.ts$/, use: 'ts-loader' }
    ]
  }
};
```

上記例では、.cssと言う拡張子のファイルをimportする場合はcss-loaderを使えとwebpackに伝えています。


### Plugins

プラグインはかなり奥が深いので何となくの理解で大丈夫です。
プラグインが何なのかと言うとローダー以外の全部です。バンドルの最適化、アセットの管理、環境変数の注入などなど出来ることは非常に幅広いです。
そもそもwebpack自体がwebpack.config.jsの __プラグインシステムと同じもの__ の上に構築されているらしいです:thinking:

プラグインを使うには、プラグインを`require()`して `plugins`プロパティの配列に追加する必要があります。 ほとんどのプラグインはオプションを通じてカスタマイズ可能です。 プラグインは`new`演算子でインスタンスを作成する必要があることに注意してください。


```javascript:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins

module.exports = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};
```

上の例では、 `html-webpack-plugin`は自動的にすべてのバンドルが注入されたHTMLファイルを生成します。

# 終わりに

他にもwebpack.config.jsで指定できるプロパティはたくさんあります。さらにcuiでどのように実行するのかも覚えるべきです。
ですが、この記事に書いてあることが理解できれば何となーくwebpack.config.jsが読めていい感じになるんじゃないでしょうか:pray:
最後に宣伝なのですが[こんなサイト](https://jtfal.com/docs/webpack/concepts)もやっているので暇があればみてください。