webpack入門1 ~Getting started~

## はじめに
webpackについて詳しく知らないし使ったことがないというスタートです。
ゴールは

* webpackが何かを知る
* webpackでできることを知る
* チュートリアル

といった内容でそのメモになりますので、さらっと表面的なことだけ知っているけど使ったことない、これから使ってみようと思っている方向けです。もし間違い等ありましたらご指摘ください。

※webpackについてはv3を使用します。

## webpackとは
機能ごとに分割されたモジュールなど複数のjsファイルをまとめてファイルに出力するツールです。こういった機能を持つツールをモジュールバンドラーと呼ぶみたいです。


## webpackでできること
* ES6, CommonJSなどで書かれた複数のモジュールたちをまとめることができる
* 実行時非同期でロードされる単一 or 複数のまとまりを作ることができる(初期ロード時間を減らす）
* コンパイル時依存関係を解決し、実行サイズを小さくすることができる
* loaderという機能があってコンパイル前に処理を行うことができ、Typescriptをjsに変換したりjs以外の静的リソースをバンドルすることができる

主にこんなところかなと思います。
バンドルすることはもちろんですが、よくある使われ方としては、babelをloaderとして使い、EC6で書かれたコードをトランスパイルすることでしょうか。最新の記述方法で書かれたコードに対応していないブラウザもまだまだ存在することを考慮し、対応するようなコードに自動変換してくれるわけです。


## チュートリアル
以下に沿って進めていきます。
https://webpack.js.org/guides/getting-started/#basic-setup

公式ではnpmを使用していますが、今回はyarnを使います。

yarn 1.0.1
webpack 3.5.6

です。

### Basic Setup
まずは準備します。

```bash
$ mkdir webpack-demo && cd webpack-demo
$ yarn init
```

次にwebpackをインストールします。
グローバルではなくこのPJのみに有効となるようローカルインストールを選択します。

```bash
$ yarn add webpack --dev
```

次にjsとhtmlファイルを追加していきます。

```src/index.js
function component() {
  var element = document.createElement('div');

  // Lodash, currently included via a script, is required for this line to work
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());
```

```index.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>
```

ブラウザで見てみた時、`Hello webpack`と表示されていれば成功です。

```bash
$ open index.html
```


### Creating a Bundle
前項で追加したコードに手を加えます。具体的には以下です。

* index.htmlの中で参照していたlodashをyarnを使ってインストール
* src/index.js
  * インストールしたlodashを使うように変更
* index.html
  * distディレクトリを作ってwebpack-demo直下からdist以下に移動
  * scriptタグでlodashを参照していたところを削除
  * scriptタグでbundleしたjsファイルを参照するよう変更

```src/index.js
import _ from 'lodash';

function component() {
  var element = document.createElement('div');

  // Lodash, now imported by this script
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());
```

index.htmlについてはまずはファイル移動

```bash
$ mkdir dist && mv index.html ./dist
```

```dist/index.html
<html>
  <head>
    <title>Getting Started</title>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>
```

次にwebpackを使ってbundleします。

```bash
$ ./node_modules/.bin/webpack src/index.js dist/bundle.js
Hash: b78ba88800fb17fdfd02
Version: webpack 3.5.6
Time: 603ms
    Asset    Size  Chunks                    Chunk Names
bundle.js  544 kB       0  [emitted]  [big]  main
   [0] ./src/index.js 256 bytes {0} [built]
   [2] (webpack)/buildin/global.js 509 bytes {0} [built]
   [3] (webpack)/buildin/module.js 517 bytes {0} [built]
    + 1 hidden module
```

実行するとdist以下にbundle.jsというファイルが出力されます。
openでdist/index.htmlを開いて見て無事開ければ成功です。

### Modules
`import`と`export`はES2015の記述方法だから古いブラウザには対応していないが、トランスパイルされたとあります。
実際にdist/bundle.jsを見てみると・・・

```dist/bundle.js
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash__ = __webpack_require__(1);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__);


function component() {
  var element = document.createElement('div');

  // Lodash, now imported by this script
  element.innerHTML = __WEBPACK_IMPORTED_MODULE_0_lodash___default.a.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());
```

上記のようにsrc/index.jsがトランスパイルされていました。
ただし、webpackは`import`と`export`以外の記述方法はトランスパイルしないとも書かれています。それ以外の記法をトランスパイルしたいならbabelなどのトランスパイラを使う必要があるというわけです。


### Using a Configuration
先ほどは以下のようにbundle元のファイルと出力ファイルを直接指定しました。

```bash
$ ./node_modules/.bin/webpack src/index.js dist/bundle.js
```

これをより実践で使えるように設定ファイルで管理するようにします。
まずは、webpack-demo直下に`webpack.config.js`を追加します。
その中身に以下を追加。

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

module.exports = {
  // bundleしたいファイルを指定
  entry: './src/index.js',

  // 出力先のディレクトリとファイル名を指定
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
```

設定ファイルを指定してbundleします。

```bash
$ ./node_modules/.bin/webpack --config webpack.config.js
```

### NPM Scripts
今まで実行してきたwebpackの実行をnpm経由で実行するための設定です。
package.jsonの`scripts`に追加します。

```package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "webpack"
  },
  "devDependencies": {
    "webpack": "^3.5.6"
  }
}
```

実行します。

```bash
# npmを使っている場合
$ npm run build

# yarnを使っている場合
$ yarn run build
yarn run v1.0.1
$ webpack
Hash: b78ba88800fb17fdfd02
Version: webpack 3.5.6
Time: 460ms
    Asset    Size  Chunks                    Chunk Names
bundle.js  544 kB       0  [emitted]  [big]  main
   [0] ./src/index.js 256 bytes {0} [built]
   [2] (webpack)/buildin/global.js 509 bytes {0} [built]
   [3] (webpack)/buildin/module.js 517 bytes {0} [built]
    + 1 hidden module
✨  Done in 1.31s.
```

以上です。
実際にプロジェクトで使用する時はこの実行方法を取ると良さそうです。


### Conclusion
次はAssetの管理をやってみようとありますが、jsファイルのbundleとしてのチュートリアルは一旦これで終わりです。

## おわりに
今回webpackでjsファイルをbundleしてみたわけですが、イメージを掴むことはできました。それに加え、webpackとbabelの関係を改めて知ることができたことが収穫でした。webpackとbabelを導入すればより良い記法を積極的に取り入れられそうなのがいいですね。

しかし、実際のプロジェクトで使うには、js以外のbundleやディレクトリ指定でのbundleなど設定の仕方についても知る必要があると思います。まだまだ勉強の日々が続きますorz