【意訳】Webpackの混乱ポイント

この記事は[Webpack — The Confusing Parts](https://medium.com/@rajaraodv/webpack-the-confusing-parts-58712f8fcad9#.e4jqmh1oj)を、[筆者の許諾を得て](https://twitter.com/rajaraodv/status/720117534872203264)意訳しています。


何か誤りがありましたら、ご指摘いただけると幸いです。

----
(以下、訳)

ReactとReduxで作られたアプリケーションにとって、Webpackは最先端を行くモジュールバンドラです。Angluar2やその他のフレームワークを使っている人々は、たいへんWebpackのお世話になっていることでしょう。

私が初めてWebpackの設定ファイルを見た時、それはさながら宇宙人のようで非常にわかりづらく見えました。しばらく試しているうちに、今では次のように考えるようになりました。Webpackは単に独特のシンタックスと新しい哲学を持っており、それがとっつきにくさの原因になっているのだと。偶発的とはいえ、これらの哲学は、Webpackの人気を押し上げた原因の１つでもあります。

__Webpackのとっつきにくさを受けて、私はいくつかの記事を書こうと思いました。これらの記事を読んで、人々がカンタンにWebpackに入門して強力な機能を使えるようになれれば幸いです。さて、最初の記事を書いていきます。__

## Webpackのコア哲学

Webpackの２つのコア哲学とは

1. __全てはモジュールである。__― JSファイルをモジュール化できるように、その他のCSSや画像やHTMLだってモジュールになりうるのです。つまり、```require("myJSfile.js")```や```require("myCSSfile.css")```といった記述ができます。この意味するところは、どんなファイルだって小さくて管理しやすい部品に分割したり、再利用したりことができるということです。
2. __”ほしいもの”を”ほしいとき”に。__―従来のモジュールバンドラは、全てのモジュールを、"bundle.js"のような１つの巨大なファイルとして出力します。しかし現実世界のアプリケーションでは、この"bundle.js"の容量は10MB〜15MBになってしまい、ロードに永久の時間がかかってしまいます。Webpackはコード分割を行って、複数の"bundle"ファイルを生成するようなたくさんの機能があります。また、_欲しい時に欲しいものだけを_ロードするためにアプリケーションのパーツを非同期的にロードすることもできます。

それでは、たくさんの”わかりづらい”側面について見ていきましょう。

## 1. 開発環境 vs 本番環境
最初に知るべきことは、Webpackには__膨大な数の機能__があるということです。そのうちのいくつかは”開発環境専用”で、いくつかは”本番環境専用”で、いくつかは”開発環境と本番環境”の両方で使用可能です。

> 適宜、画像を拡大して読んでみてください。

![webpack1.png](https://qiita-image-store.s3.amazonaws.com/0/77614/8951bb12-c74a-e04b-e878-5411c0a385f0.png)

> <sub>通常のプロジェクトにおいては、とてもたくさんの機能を使うので、普通は２つの大きなWebpack設定ファイルを使うことになります。</sub>

バンドルファイルを生成するには__package.json__に以下のように記述します。

```package.json
 “scripts”: {
  //npm run build to build production bundles
  “build”: “webpack --config webpack.config.prod.js”,
  //npm run dev to generate development bundles and run dev. server
  “dev”: “webpack-dev-server”
 }
```

## 2. Webpack CLI VS Webpack-dev-server

Webpackをはじめとするモジュールバンドラは、２つのインターフェイスを提供することをぜひ知っておいてください。

1. Webpack CLIツール ― デフォルトのインターフェイス（Webpack自身の一部としてインストールされます）
2. webpack-dev-serverツール ― Node.js製のサーバ（別途インストールする必要があります）

### Webpack CLI（本番ビルド向き）

このツールはCLI経由、あるいはWebpack設定ファイル（設定ファイルデフォルト名：webpack.config.js）経由でオプションを渡します。それらはバンドル時にWebpackに渡されます。

> Webpackを学習する初期段階においては、CLIから始めるのもよいでしょう。しかし、そのうち本番ビルドのためだけに使うようになるでしょう。

#### 用法

```
OPTION 1: 

// グローバル環境にインストール
npm install webpack --g

// ターミナル上で使用
$ webpack //<--Generates bundle using webpack.config.js

OPTION 2 :

// ローカル環境にインストールして、package.jsonに追記。
npm install webpack --save

// package.jsonのscriptsに追記。
“scripts”: {
 “build”: “webpack --config webpack.config.prod.js -p”,
 ...
 }

// 以下のように起動。
"npm run build"

```

### Webpack-dev-server（開発ビルド向き）

webpack-dev-serverはポート__8080__番を使うExpressのNode.jsサーバです。このサーバは内部的にWebpackを実行します。webpack-dev-serverを用いる利点は、できることの幅が広がります点です。例：__”ライブリロード”__, __”Hot Module Replacement”__（HMR）

#### 用法：

```
OPTION 1:
// グローバル環境にインストール
npm install webpack-dev-server --save

// ターミナル上で使用
$ webpack-dev-server --inline --hot

OPTION 2:

// package.jsonのscriptsに追記。
“scripts”: {
 “start”: “webpack-dev-server --inline --hot”,
 ...
 }

// 起動。 
$ npm start

ブラウザで以下を開く:
http://localhost:8080
```

### Webpack vs webpack-dev-serverオプション

"inline"や"hot"のようないくつかのオプションはwebpack-dev-server専用のオプションであることに注意しましょう。一方、"hide-modules"のようなオプションはCLI専用です。

### webpack-dev-server CLI オプション vs 設定ファイルオプション

特筆すべきことは、webpack-dev-serverへのオプションの渡し方には以下の２通りがあるということです。

1. webpack.config.jsの"devServer"オブジェクトを通じて。
2. CLIのオプションとして。

```
// CLI経由
webpack-dev-server --hot --inline

// webpack.config.js経由
devServer: {
 inline: true,
 hot:true
}
```

> 私は、webpack.config.js経由だと時々うまくいかない事に気づきました。なので、package.jsonの中でCLIのオプションとして渡すようにしています。

```
//package.json
{
scripts: 
   {“start”: “webpack-dev-server --hot --inline”}
}
```

> 注：hot: trueと-hotの両方を渡さないようにしてください。


### "hot" vs "inline" webpack-dev-serverオプション

"inline"オプションは、"ライブリロード"をページ全体に適用します。"hot"オプションは、"Hot Module Reloading"を可能にします。その結果、変更のあったコンポーネントのみをリロードします(ページ全体ではなく)。両方のオプションを渡した場合には、ソースコードに変更があったときにwebpack-dev-serverがまずHMRを試みます。それがうまくいかない場合に、ページ全体をリロードします。

```
// ソースコードに変更があったとき、以下の３つの例はすべてあたらしくバンドルファイルを生成します。ただし…

// 1. ブラウザをリロードしません。
$ webpack-dev-server

// 2. ページ全体をリロードします。
$ webpack-dev-server --inline

//3. モジュールだけをリロードします。ただし、失敗時にはページ全体をリロードします。
$ webpack-dev-server  --inline --hot
```

## 3. "entry" ― 文字列 vs 配列 vs オブジェクト

__Entry__は起点となるモジュールをWebpackに教えます。Entryには、文字列か配列かオブジェクトを指定できます。これはちょっとわかりづらく思えるかもれませんが、それぞれ目的が異なるのです。

もし、単一のエントリーポイントだけならば、どんなデータ型でも指定可能で、生成結果は同じです。

![webpack2.png](https://qiita-image-store.s3.amazonaws.com/0/77614/3dcde86f-e9bc-a3e2-e562-32e69786908c.png)

### entry ― 配列

しかし、__相互に依存していない__複数ファイルを指定したいときは配列が使えます。

例：HTML内に"googleAnalytics.js"を読み込ませたいとします。このJSファイルをbundle.jsの最後部に追加するよう指定する場合、以下のとおりです。

![webpack3.png](https://qiita-image-store.s3.amazonaws.com/0/77614/f21df3dd-7312-8bbf-90de-33b5de4e2b8e.png)

### entry ― オブジェクト

さて、ようやくSPAではなく__本当の__大規模アプリケーションの話をしましょう。複数のビューを持ち、複数のHTMLファイルを持つと想定します。（例：index.html, profile.html）オブジェクトを使うことで、複数のバンドルファイルをいっぺんに生成するようにWebpackに指定できます。

以下の設定ファイルは２つのJSファイルを生成します。indexEntry.jsとprofileEntry.jsの２つで、それぞれindex.htmlとprofile.html内で使用できます。

![webpack4.png](https://qiita-image-store.s3.amazonaws.com/0/77614/c69b5b4f-4de7-cbff-7cb3-4fa8a067929d.png)

#### 用法：

```
// profile.html
<script src=”dist/profileEntry.js”></script>

// index.html
<script src=”dist/indexEntry.js”></script>
```

注：ファイル名は"entry"オブジェクトのキー名に由来します。

### entry ― 組み合わせ

また、entryオブジェクト内で配列を使うこともできます。例えば、以下の設定ファイルは３つのファイルを生成します。vendor.jsとindex.jsとprifile.jsの３つです。そのうちのvendor.jsは３つのベンダファイルを含みます。

![webpack9.png](https://qiita-image-store.s3.amazonaws.com/0/77614/fde69aeb-77fc-5c82-f366-34d23b27f4aa.png)


## 4. output ― "path" vs "publicPath"

__output__は生成したファイルをどこに格納するかをWebpackに伝えます。outputは"path"と"publicPath"の２つのプロパティを持ちます。ややこしいですね。

"path"は単にWebpackに生成したファイルの格納場所を使えます。一方で"publicPath"はWebpackのプラグインが利用するもので、本番ビルド時にCSSやHTMLファイル内のURLを更新します。

![webpack5.png](https://qiita-image-store.s3.amazonaws.com/0/77614/30b55e6f-58fe-8c4d-e23e-aaa17e1a3580.png)

たとえば、CSSファイル内で'./test.png'というurlを書いたとしましょう。これはローカルホストでは読み込みに成功するかもしれません。しかし、本番環境においては'test.png'は実際にはCDN上にあるかもしれません。つまり本番環境でつかうCDNへと、URLを手動で更新する必要があるのです。

その代わり、Webpackの__publicPath__を使うことができます。その際、publicPathを認識することのできるプラグインも使いましょう。これらは本番ビルド時に、URLを自動で更新します。

![webpack6.png](https://qiita-image-store.s3.amazonaws.com/0/77614/259bbdfe-586f-d5db-ea3e-c7254af1f9f5.png)


```
// 開発環境: サーバも画像もローカルホストにあります。
.image { 
  background-image: url(‘./test.png’);
 }

// 本番環境: サーバはHerokuにあり、画像はCDNにあるとします。
.image { 
  background-image: url(‘https://someCDN/test.png’);
}
```

## 5. ローダーとローダーチェーン

ローダーとは、色々な種類のファイルの'load'や'import'を手助けしてくれる、追加のnodeモジュールです。ロードの結果、ブラウザが読めるJSやスタイルシートのようなフォーマットになります。一部のローダーを使えば、そのようなファイルをJS内に取り込む事ができます。その際、"require"を使うこともできますし、ES6の"import"を使うこともできます。

例：ES6で書かれたJSをブラウザが読めるES5に変換するために、__babel-loader__を使うことができます。

```
module: {
 loaders: [{
  test: /\.js$/, ←マッチする場合のみロードを適用。
  exclude: /node_modules/, ←node_modulesディレクトリをロード対象から除外。
  loader: ‘babel’ ← babelを使うことを明示。 (‘babel-loader’の略記)
 }]
```

### ローダーチェーン

複数のローダーを数珠つなぎにして、おなじ形式のファイルに適用することもできます。数珠つなぎは__"!"で区切られ、右から左へ__作用します。

例えば、"myCssFile.css"というCSSファイルがあるとしましょう。このファイルの中身を、__\<style>CSSの中身\</style>__という形でHTMLの中に含めたい。そんなときcss-loaderとstyle-loaderの２つのローダーを使えば実現できます。

```
module: {
 loaders: [{
  test: /\.css$/,
  loader: ‘style!css’ <--(style-loader!css-loaderの略記)
 }]
```

これがどのように作用するかは以下のとおりです。

![webpack7.png](https://qiita-image-store.s3.amazonaws.com/0/77614/7058f857-7f28-4cdb-ec4d-21c3d89142a8.png)


1. Webpackはモジュール内のCSSファイルの依存性を調査します。つまり、JSファイル内に"require(myCssFile.css)"があるかどうかチェックするのです。もし依存性を発見した場合、Webpackはそのファイルに__まずcss-loaderを__宛てがいます。
2. __css-loader__は全てのCSSとそのCSSが持つ依存性をJSONにロードします。（CSSの依存性はたとえば @import otherCSSのようなもの）JSONはstyle-loaderに渡されます。
3. __style-loader__はJSONファイルを受け取って、__\<style>CSSの中身\</style>__のようなstyleタグに追記します。そして、index.htmlファイル内にそのタグを挿入します。

## 6. ローダー自身も設定可能
ローダー自身も、パラメータによって違う挙動をするように設定可能です。

以下の例では、url-loaderに対して、1024バイト以下の画像のURLのみを使うするように指定しています。これは以下の２通りの方法で"limit"というパラメータを指定することで実現できます。

![webpack8.png](https://qiita-image-store.s3.amazonaws.com/0/77614/8d493f2e-bc3e-f92c-9cf1-aa0065a428a9.png)

## 7. .babelrcファイル

ES6をどのようにES5に変換するかを知るために、babel-loaderは"presets"を用います。また、ReactJSXをJSにパースする方法も指定できます。これらは"query"というパラメータを通じて、設定可能です。

```
module: {
  loaders: [
    {
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel',
      query: {
        presets: ['react', 'es2015']
      }
    }
  ]
}
```

しかし、多くのプロジェクトにおいては、babelの設定は肥大化しがちです。そのため、__.babelrc__と呼ばれるbabel-loaderの設定ファイルに記述し分けておくことも可能です。babel-loaderは自動的に.babelrcをロードしてくれます。

以下がよく目にする例です。

```
//webpack.config.js 
module: {
  loaders: [
    {
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel'
    }
  ]
}

//.bablerc
{
 “presets”: [“react”, “es2015”]
}
```

## 8. プラグイン

バンドル生成時に作用する追加のnodeモジュールがプラグインです。

例えば、__[UglifyJsPlugin](https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin)__はbundle.jsを取得して、ファイルサイズ削減のために圧縮を行います。

__[extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin)__も似たようなもので、内部的にはcss-loaderとstyle-loaderを用いています。このプラグインは全てのCSSを一箇所に集めて、最終的にはstyles.cssというファイルに抜き取り、index.htmlにstyle.cssへのリンクを追記します。

```
// webpack.config.js
// 全ての.cssファイルを取得して、内容を結合して、単一のstyles.cssに抜き出す。
var ETP = require("extract-text-webpack-plugin");

module: {
 loaders: [
  {test: /\.css$/, loader:ETP.extract("style-loader","css-loader") }
  ]
},
plugins: [
    new ExtractTextPlugin("styles.css") // styles.cssに抜き出す。
  ]
}
```

注：HTMLのスタイル属性として、インラインでCSSを付与したいならば、[extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin)なしでも可能です。ローダーを以下のように指定すればいいのです。

```
module: {
 loaders: [{
  test: /\.css$/,
  loader: ‘style!css’ <--(style-loader!css-loaderの略記)
 }]
```

## 9. ローダー vs プラグイン

お気づきかもしれませんが、__ローダーは個別のファイル単位に作用します。__あるいは、バンドルの生成__前__に作用します。

一方で、__プラグインはバンドルファイルに作用し、バンドル生成過程の最終段階で働きます。__そして、いくつかの[commonsChunksPlugins](https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin)のようなプラグインは作用範囲が広く、どのようにバンドルが生成されるかを規定します。

## 10. ファイルの拡張子を解決する

多くのWebpackの設定ファイルはresolve extensionsプロパティを持っており、以下の例のように__空文字__が含まれています。空文字は、拡張子なしのimportをサポートします。たとえば__require("./myJSFile")や、import myJSFile from './myJSFile'__のような拡張子なしの記述です。

```
{
 resolve: {
   extensions: [‘’, ‘.js’, ‘.jsx’]
 }
}
```

## 筆者の他のポスト（original）

### Webpack

1. _[Webpack — The Confusing Parts](https://medium.com/@rajaraodv/webpack-the-confusing-parts-58712f8fcad9#.lx82mu7eb)_


### React and Redux

1. _[Step by Step Guide To Building React Redux Apps](https://medium.com/@rajaraodv/step-by-step-guide-to-building-react-redux-apps-using-mocks-48ca0f47f9a#.zgg0rbnfw)_
2. _[A Guide For Building A React Redux CRUD App (3-page app)](https://medium.com/@rajaraodv/a-guide-for-building-a-react-redux-crud-app-7fe0b8943d0f#.bde1g0x22)_
3. _[Using Middlewares In React Redux Apps](https://medium.com/@rajaraodv/using-middlewares-in-react-redux-apps-f7c9652610c6#.yoz0rundz)_
4. _[Adding A Robust Form Validation To React Redux Apps](https://medium.com/@rajaraodv/adding-a-robust-form-validation-to-react-redux-apps-616ca240c124#.q847xarw7)_
5. _[Securing React Redux Apps With JWT Tokens](https://medium.com/@rajaraodv/securing-react-redux-apps-with-jwt-tokens-fcfe81356ea0#.pa3ld1ixh)_
6. _[Handling Transactional Emails In React Redux Apps](https://medium.com/@rajaraodv/handling-transactional-emails-in-react-redux-apps-8b1134748f76#.xsog42fj2)_
7. _[The Anatomy Of A React Redux App](https://medium.com/@rajaraodv/the-anatomy-of-a-react-redux-app-759282368c5a#.g5yw8l4o9)_

### Salesforce

1. _[Developing React Redux Apps In Salesforce’s Visualforce
](https://medium.com/@rajaraodv/developing-react-redux-apps-in-salesforce-s-visualforce-3ad7be560d1c#.7rhlw6dv6)_