webpack入門 -React,React-Router,Server-Side-Rendering周りで使う-

[以前の記事](http://qiita.com/tanaka0325/items/43d105d7c341b8431983)でも書いたのですが、[webpack](https://webpack.github.io)を使ってみたので簡単に使い方についてメモしておこうと思います。

※あまり詳しく無い人間なので間違っている部分も多分に含まれてる可能性がありますのでご了承ください。

## webpack とは？

[公式](https://webpack.github.io)がしっかりしてるっぽいし、調べれば色々と出てくるので詳しくは書きませんが、ざっくり言うとbrowserifyと同じでライブラリのimport周りをいい感じに解消してくれるやつ。
更にcssとかjsをそれぞれ1ファイルにまとめることができたり、画像の圧縮ができたり、その際にbabelとかでトランスパイル？することができるやつ。
（css,画像周りはまだ試してないのでよくわかってない）

browserifyは単一のjsファイルを単一のjsファイルに吐き出すのが基本(だと思ってるけれど違うかもしれない)なのに対して、webpackの場合は複数ファイルから複数ファイルに吐き出せたりする。

さらにbrowserifyはjsのみが対象だけれど、webpackの場合はcssや画像も対象にしている。
なのでbrowserifyだけの場合そこらへんも考慮し始めると結局gulpとかが必要になってくるのだけれど、webpackの場合それだけで完結できる。

使用するライブラリが減らせるということは、その分学習コストも減るしバグが入り込む余地も減るし、新しいバージョンに対応してないなどの心配事も減るので良いですね。

## 最低限の webpack

まずは webpack を最低限の設定で動かしてみる。

### webpack のインストール

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

### webpack.config.js 作成

webpackは webpack.config.js というファイルにどういうことをしたいのか、を記述していきます。
(作らなくてもコマンド叩くときに指定すればできるけれど、その件については今回は触れない)

```js:webpack.config.js
module.exports = {
  entry: __dirname + '/index.js',
  output: {
    path: __dirname,
    filename: 'bundle.js',
  },
}
```

### webpack コマンドを叩いてコンパイル

最終的には package.json にコマンドを書くけれど一旦は直でコマンドを叩いて確認する。

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

これでエラーが出ずに正常に実行されれば、index.jsと同じディレクトリにbundle.jsが生成されているはず。

### 上記の config の解説

上記の config で出てくる各項目について説明。

#### entry

ビルドする対象となるファイル。
複数指定することも可。[^1]
[^1]: 複数指定する場合の書き方は[こちら](http://dackdive.hateblo.jp/entry/2016/04/13/123000)が詳しい

#### output

ビルド先のファイルの設定。
entry で複数指定した場合複数指定する。

## React, es2015 を babel を使って webpack 経由でコンパイルする

[以前の記事](http://qiita.com/tanaka0325/items/43d105d7c341b8431983)では browserify を使っていたので、こちらを webpack で同じ挙動になるように config を設定してみます。

### webpack.config.js を書き換える

```js:webpack.config.js
module.exports = {
  entry: __dirname + '/index.js',
  output: {
    path: __dirname,
    filename: 'bundle.js',
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query:{
          presets: ['react', 'es2015']
        }
      }
    ]
  }
}
```

### 上記の config の解説

ここらへんからハードルが上がってきましたね。
ただしよく見ると増えてる項目は「resolve」と「module」だけです。（moduleがややこしく見えるけれど）

#### resolve

見た通りビルド対象に含めたいファイルの拡張子を指定します。
React のプロジェクトで jsx がある場合は追加しますが、無ければ無しで大丈夫です。

#### module

module は webpack がビルドするときに特定の処理をしたい場合に指定するところです。
そして「特定の処理」は別のプラグインで loader として公開されているので、やりたいこと毎に loader をインストールしてそれを記述します。

今回の場合は「react, es2015 のコードを babel を使ってコンパイル」したいので、babel-loader をインストールしそれ用の記述をしています。

```bash
$ npm install babel-loader babel-preset-react babel-preset-es2015
# babel-preset-react, babel-preset-es2015 は babel で react, es2015 をコンパイルするときに使用するやつです
```

それぞれの子項目について見ていきます。

##### test

この module を使う対象を指定します。
今回は js ファイル全てに対して。

##### exclude

ビルド対象の中で、除外するファイルを指定します。
/\.js$/ と書いたものの node_modules/ まで含まれると死んじゃうので除いておきます。

##### loader

使用する loader を指定します。
今回は babel なので 'babel-loader'。

##### query

指定した loader に渡すクエリパラメータです。
今回は es2015, react でコンパイルしたいので書いておきます。


これで同じように下記のコマンドを叩けば正常にビルドできると思います。

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

## React, React-Router, Server-Side-Rendering をする場合の設定

今回は下記の様な状況の場合、どのような config を書けばいいのか説明します。

- React を使用
- React-Router を使用して SPA
- Express でサーバを立てて Server-Side-Rendering

今回はあくまで webpack の説明なので、React-Router, Express, Server-Side-Renderingあたりについては書きません。

~~[github](https://github.com/tanaka0325/react-router-for-beginners)にソースを上げてるのそっちをみればだいたいわかると思います。~~

（追記）
個人的にこれよりも良い気がするサンプルができたの修正
リンクは下記になりますー
[tanaka0325/react-skeleton](https://github.com/tanaka0325/react-skeleton)

### ディレクトリ構成

```
package.json
webpack.config.js
  app/
    index.html
    src/
      index.js
      routes.js
      server.js
      components/
    dest/
```

（追記）上が古い方で、下が新しい方
こうなった経緯はまた別記事で・・・

```
package.json
webpack.config.js
webpack.server.config.js
public/
  index.html
src/
  components/
  index.js
  routes.js
  server.js
```

~~app/src内のindex.jsがクライアント側のエントリーポイントのjsで、server.jsがサーバー側のjs。~~
※ディレクトリ構成については絶賛悩み中・・・何がいいのやら

~~これを下記のようにビルドします。~~

- ~~index.js -> app/dest/app.bundle.js~~
- ~~server.js -> app/dest/server.bundle.js~~

### webpack.config.js

```js:webpack.config.js
var commonLoader = [
  {
    test: /\.js$/,
    exclude: /node_modules/,
    loader: 'babel-loader',
    query:{
      presets: ['react', 'es2015']
    }
  },{
    test: /\.json$/,
    loader: 'json-loader',
  }
];

module.exports = [
  {
    name: 'client',
    entry: __dirname + "/app/src/js/index.js",
    output: {
      path: __dirname + '/app/dest/',
      filename: 'app.bundle.js'
    },
    module: {
      loaders: commonLoader
    },
    resolve: {
      extensions: ['', '.js', '.jsx']
    }
  },{
    name: 'server',
    entry: __dirname + "/app/src/js/server.js",
    target: 'node',
    output: {
      path: __dirname + '/app/dest/',
      filename: 'server.bundle.js',
      libraryTarget: 'commonjs2',
    },

    module: {
      loaders: commonLoader
    },
    resolve: {
      extensions: ['', '.js', '.jsx']
    }
  }
];
```

[hmarui66/react-server-rendering-sample](https://github.com/hmarui66/react-server-rendering-sample)
こちらをものすごい参考にさせて頂いてます。

だいたいは今までの説明でわかると思いますので、ポイントのみ説明します。

#### module.exports を複数設定する

今回はクライアント側とサーバー側で設定する項目が異なる部分があるのでそれぞれ別の設定をしています。
module.exportsにリストで複数渡すことで実現できます。

#### target: 'node'

サーバー側に書いてあるやつ。
webpack でビルドする際に環境によってrequireまわりであったり細かい部分の差異があるようでちゃんと指定しないとエラーがでます。

[公式のドキュメントのtargetの項目](https://webpack.github.io/docs/configuration.html#target)に詳しく書いてありますが、デフォルトでは 'web' になっているみたい。
今回サーバー側は node で express を動かしているので 'node' を設定。

#### libraryTarget

サーバー側のoutput の中に書いてあるやつ。
[こちら](http://qiita.com/srd7/items/9b4e76229b22222c36aa)に詳しく解説されていますのでぜひ一読を。

正直個人的にあまり node 周りをほぼ触って来なかったのであまりピンと来ていません。。。
使用しているライブラリとパスがバッティングしないように、したときにどうするのか、的な記述だと思いますが、もっと詳しくなってわかったら追記しますね。

## まとめ

たいへん

## 参考リンク

- [tutorials/getting-started](https://webpack.github.io/docs/tutorials/getting-started/)
- [webpack.config.jsの読み方、書き方](http://dackdive.hateblo.jp/entry/2016/04/13/123000)
- [hmarui66/react-server-rendering-sample](https://github.com/hmarui66/react-server-rendering-sample)
- [webpack で Node サーバー用のコードを bundle する](http://qiita.com/srd7/items/9b4e76229b22222c36aa)