webpack初心者がJavaScriptをビルドするまでの手順

覚えたことは随時追記していきます。

## webpackのインストール

package.jsonがなければ、作る。

```
$ npm init -y
```

webpackをローカルにインストール

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


## インストールしたので設定

**Concepts**
https://webpack.js.org/concepts/

**Configuration**
https://webpack.js.org/configuration/

設定周りのドキュメントを見ながら、webpack.config.jsを作ります。
まずはシンプルにapp/entry.jsを依存を解決してビルドするようにしてみます。
出力先はbuild/bundle.jsにします。

```app/entry.js
(function() {

  var hello = require('./hello.js');

  hello(); //-> Hello Webpack!!

})();
```
```app/hello.js
module.exports = function() {
	console.log('Hello Webpack!!');
};
```
```build/index.html
<html lang="ja">
<head>
	<meta charset="utf-8">
	<title>Hello Webpack!!</title>
</head>
<body>
	<script src="build/bundle.js"></script>
</body>
</html>
```


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

module.exports = {

  //エントリポイントのJavaScript
  entry: './app/entry.js',

  output: {
    //出力先のフォルダ
    path: path.resolve(__dirname, 'build'),
    //出力先のファイル名
    filename: 'bundle.js'
  }
};
```

## 設定したので実行

以下のコマンドを実行します。

```
$ ./node_modules/.bin/webpack
```

するとこのような実行結果が表示されました。

```
Hash: ce967430993bfda874d6
Version: webpack 2.2.1
Time: 61ms
    Asset     Size  Chunks             Chunk Names
bundle.js  2.75 kB       0  [emitted]  main
   [0] ./app/hello.js 67 bytes {0} [built]
   [1] ./app/entry.js 92 bytes {0} [built]
```

build/index.htmlにアクセスしてブラウザで確認するとconsoleに`Hello Webpack!!`と出ています。ビルドに成功したようです。
ところで、`$ ./node_modules/.bin/webpack`のコマンドは長すぎるので打つのが面倒ですよね。

package.jsonに下記のように書き足して`$ npm run build`でビルドできるようにします。

```package.json
{
  ...(省略)...
  
  "scripts": {
    "build": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  
  ...(省略)...
}
```
以下のコマンドを実行してみましょう。

```
$ npm run build
```

## 複数のファイルをビルドしたい
エントリポイントのJavaScriptはサイトを通して1つとは限らないので、複数のファイルに分けてビルドしたいこともあると思いますが、下記のwebpack.config.jsを編集することで複数のビルド結果を得ることができます。

```webpack.config.js

var path = require('path');

module.exports = {

  //エントリポイントのJavaScript
  entry: {
    build1: './app/entry.js',
    build2: './app/entry2.js'
  },

  output: {
    //出力先のフォルダ
    path: path.resolve(__dirname, 'build'),
    //出力先のファイル名
    filename: '[name].js'
  }
};
```

ビルドを実行すると、build2.jsとbuild1.jsとentryオプションに指定したオブジェクトのキーと同じ名前で結果が出力されています。

```build結果
Hash: 09ace678d214fee684bc
Version: webpack 2.2.1
Time: 104ms
    Asset     Size  Chunks             Chunk Names
build2.js  2.75 kB       0  [emitted]  build2
build1.js  2.75 kB       1  [emitted]  build1
   [0] ./app/hello.js 67 bytes {0} {1} [built]
   [1] ./app/entry.js 92 bytes {1} [built]
   [2] ./app/entry2.js 92 bytes {0} [built]
```

## npm installしたモジュールをrequireしたい
特に何もせずともデフォルトで探ってよしなにやってくれるようです。

## JavaScriptを圧縮したい
webpackモジュールの中にある、UglifyJsPluginを利用して圧縮します。
[uglify-save-license](https://github.com/shinnn/uglify-save-license)を使いライセンス文を残し、sourcemapの出力も行います。


```webpack.config.js

var path = require('path');
var webpack = require('webpack');
var saveLicense = require('uglify-save-license');

module.exports = {

  //エントリポイントのJavaScript
  entry: {
    bundle: './app/entry.js'
  },

  output: {
    //出力先のフォルダ
    path: path.resolve(__dirname, 'build'),
    //出力先のファイル名
    filename: '[name].js'
  },

  plugins: [
    //JavaScriptを圧縮する
    new webpack.optimize.UglifyJsPlugin({
      //source mapを出力する
      sourceMap: true,
      //License文のコメントは残す
      comments: saveLicense
    })
  ],

  //出力するsource mapのスタイル
  devtool: '#source-map'
};

```


## ES6で書きたい
JavaScriptをlet,const,arrow function,classなど素敵な構文があるES6で記述したくなってきますよね。Babelを使ってトランスパイルしてみましょう。

まずはBabelを入れます。

```
$ npm install babel-core babel-loader babel-preset-es2015
```

webpack.config.jsにbabel-loaderの設定を追加します。

```webpack.config.js
var path = require('path');
var webpack = require('webpack');
var saveLicense = require('uglify-save-license');

module.exports = {

  //エントリポイントのJavaScript
  entry: {
    bundle: './app/entry.js'
  },

  output: {
    //出力先のフォルダ
    path: path.resolve(__dirname, 'build'),
    //出力先のファイル名
    filename: '[name].js'
  },

  plugins: [
    //JavaScriptを圧縮する
    new webpack.optimize.UglifyJsPlugin({
      //source mapを出力する
      sourceMap: true,
      //License文のコメントは残す
      comments: saveLicense
    })
  ],

  //出力するsource mapのスタイル
  devtool: '#source-map',


  module: {
    rules: [

      { //babel用の設定
        test: /\.js$/,
        exclude: /node_modules/, //node_modules以下は対象から外す
        loader: 'babel-loader'
      }
    ]
  }
};

```

babel自体の設定は、.babelrcに書き出してしまいます。
webpack2ではES2015(ES6) Modulesを解釈できるようになったのでBabel側の方を止めます。
参考: [Migrating to Webpack 2](http://javascriptplayground.com/blog/2016/10/moving-to-webpack-2/#stop-babel-from-compiling-es2015-modules)


```babelrc.js
{
  "presets": [
    [
      "es2015", {
        "modules": false
      }
    ]
  ]
}
```

webpackをインストールした時に作ったJSを編集して確認してみます。

```entry.js
import Hello from './hello';

(function() {

  var hello = new Hello();

  hello.say(); //-> Hello Webpack!!

})();
```
```hello.js
export default class Hello {
  say() {
    console.log('Hello Webpack!!');
  }
}
```

index.htmlを開いて、コンソールに「Hello Webpack!!」と表示されていればOK。
とりあえず最低限は以上として、あとはgulp連携して使うなり、このままwebpack単体で改造を進めて使うなりしたら良いかなと思います。自分用のメモですが誰かのお役に立てば嬉しいです。

ここまでのものはGithubに上げておきます。
https://github.com/bukurocci/webpack-practice


## 参考
- [uglify-save-license](https://github.com/shinnn/uglify-save-license)
- [Migrating to Webpack 2](http://javascriptplayground.com/blog/2016/10/moving-to-webpack-2/#stop-babel-from-compiling-es2015-modules)