# KT#005-yoshiki (俺が) 今から学ぶ Webpack
###### tags: `web` `JavaScript`
<img src="https://i.imgur.com/qCzmuup.png" width="300px">
## 目的
webpack について完全に理解する。

## 導入
### JavaScript におけるビルド
「いや、JavaScript はコンパイルいらないから、ビルドいらないだろww」 と思ってる方へ
現在の基本的なフロントエンド開発では、HTML ファイルが読み込む JavaScript ファイル (いわゆる生 JS) で直接編集することは非効率であることが多いです
そのため、開発を容易にするために JS にもビルドという概念が存在していることを予めご認識ください
個人的な意見として JS のビルドは以下の 2 種類に分かれていると思っています
- **バンドル** : 複数の JS/アセットファイルを変化し、1 つにまとめること
- **コンパイル** : 自分が書いたコードを色んな環境 (IE, Chrome, Firefox 等) で動くように変換すること
(vue-cli や create-react-app では、これらの環境を自動で用意してくれている)
### 知るモチベーション
では、vue-cli が自動で用意してくれるなら、Vue を利用する限り知る必要ないのではないかという話になる
個人的には vue-cli を利用している限り知る必要はないと思う
しかし、Vue プロジェクトのビルドは必ずしも vue-cli を利用する必要はない
また、webpack は現在 JS のバンドルツールとしてデファクトスタンダードとなっている
なので、Vue を利用するにも webpack のレイヤーを意識する機会はありえるし、Vue から離れたとしても利用する機会はある
*(個人的に React のビルドをカスタマイズしたく、学びたかったのが正直でかい)*
### バンドルの必要性
HTML 側で複数の JS をロードすると、ロードの度にリクエストが発生してしまう
なので、基本的には一つの JS にまとめていきたい
一方、開発目線に立つと、1 つの JS ファイルに書き続けるのは大変
開発時は複数の JS ファイルとして開発をして、webpack を通じて一つの JS にバンドル化できる!
## webpack の気持ちになるですよ
### webpack のない世界
webpack のない開発を簡単に理解
```text
webpack-demo
├── index.html
├── package-lock.json
└── src
└── index.js
```
`index.html`
(インポートしている `lodash` は jQuery みたいなものだと思ってください)
```html
<!doctype html>
<html>
<head>
<title>Getting Started</title>
<script src="https://unpkg.com/lodash@4.16.6"></script>
</head>
<body>
<script src="./src/index.js"></script>
</body>
</html>
```
`index.js`
```js
function component() {
const element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
```
webpack を知らない人
「lodash 使いたいから <script> タグでインポート!」
「ロジックは index.js にまとめて書くでしょ、join 関数ほいほい、あぁ lodash 便利」
、
、
、
このコード違和感ないですか?
webpack を知ってる人からすれば以下の違和感を感じます
- index.js には lodash という文字すらがなく、依存関係がわからない
- lodash のために、1 回 HTTP リクエストが発生
- lodash が読み込めない瞬間にアプリケーション崩壊
### welcome to webpack world
まずは、webpack を npm からインストールする
今回のプロジェクトでは lodash を使うらしいので、lodash もこのタイミングでインストール
```sh
$ mkdir webpack-demo
$ cd webpack-demo
$ npm init -y
$ npm install webpack webpack-cli --save-dev
$ npm install lodash --save
```
※ --save-dev オプションを付与することで、開発環境用のパッケージとしてインストールします
webpack 用にディレクトリ構造を少し変更
dist/ 以下にバンドルした JS が出力されます
```text
webpack-demo
├── dist/
│ └── index.html
├── node_modules/
├── package-lock.json
└── src/
└── index.js
```
ファイルも webpack を意識して変更
`index.html`
```html
<!doctype html>
<html>
<head>
<title>Getting Started</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>
```
`index.js`
```js
import _ from 'lodash';
function component() {
const element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
```
お分かりいただけただろうか、、、?
- index.js で lodash を import できる (この記法は基本的に webpack なしでは使えません)
- index.html で lodash 読まなくていい
いざ、バンドル!
```sh
$ npx webpack
Hash: 54477d4081095e0fd28b
Version: webpack 4.43.0
Time: 2296ms
Built at: 2020-05-01 0:31:20
Asset Size Chunks Chunk Names
main.js 72.1 KiB 0 [emitted] main
Entrypoint main = main.js
[1] ./src/index.js 217 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
+ 1 hidden module
```
※ npx コマンドで npm 経由でローカルにインストールされた CLI ツールを実行できます
index.html にアクセス → 正常に動いている!
*(ちなみにこの状態で main.js 見ても、人知を超えた JS が見れるだけです)*
### ちょっとだけ設定を変える
webpack はほとんどのプロジェクトでデフォルトの設定で運用可能 (設定ファイルは必要なし)
ただ、当然 webpack に様々なカスタマイズを加えることも可能
基本的に、webpack.config.js に記述する
webpack.config.js
```js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
};
```
entry はまぁエントリーポイントだよね
output プロパティはまぁ、出力だよね
filename は最終的な出力ファイルだよね
path は出力ファイルのパスだよね
## その他の設定
### 色々な loader
これまで、JS ファイルの話しかしていないが実は loader という機能があって、JS ファイル以外もバンドル化可能
よく使われるのは、css-loader, image-loader など
< https://webpack.js.org/guides/asset-management/ >
Vue を利用している人は、`.vue` ファイルが JS ファイルや CSS ファイルにビルド時に勝手に変換される様子をみてきたでしょう
これは、webpack 用に vue-lodaer という loader があるからである
< https://webpack.js.org/concepts/loaders/ >
Vue で書かれた独自の記法は vue-loader によって解釈され、JS/CSS ファイルとして出力される
### 開発系の設定
バンドル後は前述の通り、基本的に 1 つの JS ファイルに出力される
では、 「どの JS ファイルでエラーしたかわからんやないかい」 を解決するツールがある
開発用にバンドルの設定を用意しておき、本番用と分けることもできる
< https://webpack.js.org/guides/development/ >
### キャッシュ
例えばアプリをアップデート→デプロイしたとき、変更が行われなかった部分はブラウザのキャッシュが機能してほしいし、更新したファイルは即座に反映されてほしい
しかし、ファイル名が同一である場合に、ユーザーのブウウザの設定では、古いファイルが読み込まれる可能性がある
webpack ではバンドルのアウトプットファイル名にハッシュ値を入れて、キャッシュをコントロールするオプションがある
< https://webpack.js.org/guides/caching/ >
### PWA ソリューション
PWA 用に Service Worker が実行する JS コードをビルド可能
< https://webpack.js.org/guides/progressive-web-application/ >
## 余談
vue-cli がラップしてるので、あまり意識することはないが一応好きなバンドルをやってくれるように設定が可能
https://cli.vuejs.org/guide/webpack.html#simple-configuration