Webpack2+sassでbundle.cssを出力する＆sassで画像ファイルを扱う

# はじめに

`sass-loader` を使っているものの `entry` や `output` にjsが指定されている記事があったり、
loaderの指定方法が変わっていたりして、よくわからなかったので理解のため自分の記事を書きます。

また、SCSSで `background-image` を扱おうとした際に、
webpackのビルドで扱けてしまったので、その解決策も書く。

# Webpack2でsassをビルドする

参考にしたページ: http://qiita.com/nicchi__1985/items/e30e73de6d8443909537

## SCSSをWebpackでビルドするのに必要なパッケージたち

```json:package.json
{
  ～略～
  "devDependencies": {
    "css-loader": "^0.26.1",
    "extract-text-webpack-plugin": "2.0.0-rc.3",
    "node-sass": "^4.5.0",
    "sass-loader": "^5.0.1",
    "style-loader": "^0.13.1",
    "webpack": "^2.2.1"
  },
  ～略～
}
```

`extract-text-webpack-plugin` は、jsではなくcssとして出力するプラグインという認識。
Webpack2でビルドしてエラーが出た際に、調べていたらRC版を使えばいいよというIssueを見つけたので使用しています。

## Webpack1 と Webpack2 の記述で混乱したところ

- `module.loaders.loader` ではなく `module.rules.use` を使う
- `loader: 'style!css!sass'` や `loader: 'style-loader!css-loader!sass-loader'`ではなく `use: ['sass-loader', 'css-loader', 'sass-loader']` を使う

参考にしたページ(公式): https://webpack.js.org/guides/migrating/

## ファイル構成

```
$ tree
.
├── index.html
├── package.json
├── scss
│   ├── app.scss
│   └── _body.scss
└── webpack.config.js
```

### scss/app.scss

```scss:app.scss
@import '_body';
```

### scss/_body.scss

```scss:_body.scss
body {
  color: #ffffff;
  background-color: #000000;
}
```

### webpack.config.js

```js:webpack.config.js
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: './scss/app.scss',
  output: {
    filename: 'bundle.css'
  },
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: "style-loader",
            use: ["css-loader", "sass-loader?outputStyle=expanded"]
          }
        )
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('bundle.css')
  ]
};
```

エントリポイント: `scss/app.scss` を指定
アウトプットに: `bundle.css` を指定

## ビルド

```
$ webpack
```

これで `bundle.css` が出力されます。
`index.html` で `bundle.css` を読み込めばバンドルされたCSSがそのまま使えます。

# Webpack2 + sass で画像ファイルを扱う

```
background-image: url(../res/background.png);
```

を指定したかったのだが、
Webpackがエラーになってしまって上手くいかなかったときに調べたこと

## 必要なパッケージ

```diff:package.json
 {
   ～略～
   "devDependencies": {
     "css-loader": "^0.26.1",
     "extract-text-webpack-plugin": "2.0.0-rc.3",
+    "file-loader": "^0.10.0",
     "node-sass": "^4.5.0",
     "sass-loader": "^5.0.1",
     "style-loader": "^0.13.1",
     "webpack": "^2.2.1"
   },
   ～略～
 }
```

`url-loader` または `file-loder` が必要と書かれているページがありました。
参考にしたページ: http://a0sy.hatenablog.jp/entry/2015/08/03/204933

`url-loader` を使用すると BASE64エンコード されてしまうという記述があったので、
`file-loader` を使って試してみることにしました。

## ファイル構成

```diff
 $ tree
 .
 ├── index.html
 ├── package.json
+├── res
+│   └── background.png
 ├── scss
 │   ├── app.scss
 │   └── _body.scss
 └── webpack.config.js
```

### scss/_body.scss

```diff:_body.scss
 body {
-  color: #ffffff;
-  background-color: #000000;
+  color: #000000;
+  background-image: url(../res/background.png);
 }
```

ここで指定するパスは、
`webpack.config.js` のエントリポイントになっているファイルからのパスのようです。

### webpack.config.js

```diff:webpack.config.js
 var ExtractTextPlugin = require('extract-text-webpack-plugin');

 module.exports = {
   entry: './scss/app.scss',
   output: {
     filename: 'bundle.css'
   },
   module: {
     rules: [
       {
         test: /\.scss$/,
         use: ExtractTextPlugin.extract(
           {
             fallback: "style-loader",
             use: ["css-loader", "sass-loader?outputStyle=expanded"]
           }
         )
-      }
+      }, {
+        test: /\.(jpg|png)$/,
+        use: 'file-loader?name=assets/[name].[ext]'
+      }
     ]
   },
   plugins: [
     new ExtractTextPlugin('bundle.css')
   ]
 };
```

SCSS内で指定されたパス `../res/background.png` が `assets/[name].[ext]` として出力されます。
※res内のファイルを直接参照するのではなく `bundle.js` や `bundle.css` のように、別のファイルとして出力されるようです。

つまり今回のケースでは `assets/` も `.gitignore` に追加しておく必要がある。