webpackでcssとimageをバンドルする


`webpack`は`Javascript`と`css`や`image`を一緒にまとめることができるのが、GruntやGulpといった他のタスクランナーのように設定が煩雑にならない強み、と公式サイトで見た。
実際、それがどれほど便利なのかを試してみた。
以下は、`es6+babel+webpack`の環境を想定しています。

## cssのバンドル
 `css-loader`をインストール。Scssを使いたいので`sass-loader`もインストールします。

```bash:loaderのインストール
$ npm install --save-dev css-loader sass-loader
```

`webpack.config.js`を編集します。

```js:webpack.config.js
// es5
'use strict';

var webpack = require('webpack');
var path = require('path');

var env = process.env.NODE_ENV;
var config = {
  module: {
    loaders: [
      {
        test: /\.js$/,
        loaders: ['babel-loader?presets[]=react&presets[]=es2015&cacheDirectory'],
        exclude: /node_modules/
      },
      {
        // 今回はScssを使うので.scssとしています。
        // cssを直接使う場合は.cssとして、loadersからsassを除きます。
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass']
      },
    ]
  },
  entry: {
    'index': 'index.js',
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
  ],
  resolve: {
    extensions: ['', '.json', '.js', '.jsx'],
    modulesDirectories: ['node_modules', __dirname]
  }
};

module.exports = config;
```

`resolve`の`extensions`で`.scss`を指定した場合は、`import './test'`のように拡張子を除いて`import`できます。
`import`の拡張子なしはJavascriptファイルのみがいいような気もする。

そしてscssファイルを作成します。

```scss:style.scss
.main-container {
  width: auto;
  height: auto;
}

#box {
  border: solid 5px;
  width: 300px;
  height: 300px;
  margin: auto;
}
```

Directory構造はこのようになりました。

```bash:directory構造
$ tree
.
├── index.html
├── index.js
├── style.scss
└── webpack.config.js
```

他のファイルはこのような感じです。

```js:index.js
import './style.scss'
```

```html:index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Load CSS Example</title>
  <script src="dist/index.js"></script>
</head>

<body>
  <div class="main-container">
    <div id="box"></div>
  </div>
</body>

</html>
```

## imageのバンドル
`file-loader`と`url-loader`をインストールします。

```bash:loaderのインストール
$ npm install --save-dev file-loader url-loader
```

上の`webpack.config.js`に追記します。

```js:webpack.config.js
// es5
...,
var config = {
  module: {
    loaders: [
      {
        test: /\.js$/,
        loaders: ['babel-loader?presets[]=react&presets[]=es2015&cacheDirectory'],
        exclude: /node_modules/
      },
      {
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass']
      },
      {
        // 追記
        test: /\.(jpg|png)$/,
        loaders: 'url-loader'
      },
    ]
  },
  ...,
}

module.exports = config;
```

Directory構造はこのようにしました。

```bash:directory構造
$ tree
.
├── image.jpg
├── image.png
├── index.html
├── index.js
├── style.scss
└── webpack.config.js
```

`index.js`に追記します。

```js:index.js
import './style.scss'
import jpg from './image.jpg' // base64データがビルドされるのでそれをimportする
import png from './image.png' // base64データがビルドされるのでそれをimportする

let imgJpg = document.createElement('img')
imgJpg.src = jpg
document.getElementById('box').appendChild(imgJpg)

let imgPng = document.createElement('img')
imgPng.src = png
document.getElementById('box').appendChild(imgPng)
```

DOMを扱うので、`index.html`の`script`タグを移動します。

```html:index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Load CSS Example</title>
</head>

<body>
  <div class="main-container">
    <div id="box"></div>
  </div>
</body>
<script src="dist/index.js"></script>
</html>
```

## 余談：imageをファイル名でリンクする場合
* 元のPATHを書けば良いだけだとは思うが、一応出来るので試す。
* 出力先は`output`で指定したPATH

`webpack.config.js`で`url-loader`の代わりに`file-loader`を使用します。
名前を指定しないとmd5Hashでファイル名が出力されるので注意。

```js:webpack.config.js
// es5
...,
var config = {
  module: {
    loaders: [
    
      {
        // loaderを変更。名前をファイル名のままで維持する
        test: /\.(jpg|png)$/,
        loaders: 'file-loader?name=[name].[ext]'
      },
    ]
  },
  ...,
}

module.exports = config;
```

imageは使いどころが難しいですが、動的に使用する場合は便利な時があるかもしれませんね。