Webpack+Sass+Browser-sync+ES2015で快適なフロントエンド開発を

# 概要
みなさん、Web開発で消耗していないでしょうか？
今回はSassやES2015、browser-syncをwebpackでまとめて管理してWeb開発をスマートにするための方法をまとめてみました。
実際に完成した開発環境は[こちら](https://github.com/takachan-mirai/webpack-sandbox)になります。
使いたいだけの方はクローンして使ってください。
動作の説明はreadme.md書いておく予定ですが、もし記述してなければこの記事を参考にしながら使ってください。

## 動作環境
- macOS Sierra (10.12.4)
- node.js 
- yarn

## ディレクトリ構成
### public
実際に公開されるディレクトリ。
localhost等で確認するときは、ここに入っているindex.htmlが表示されます。
また、srcのデータをまとめたbundle.jsもここに格納されます。
### src
ここに/css/や/js/といったディレクトリを作って作業していきます。



細かい構成はgithubに上がっているとおりなので参考にしてください。

## yarnをセットアップする。
セットアップするディレクトリに入ったら、

```bash:Terminal.app
$ yarn
```

と入力しましょう。
yarn.lockが生成されていればokです。
次からは基本的にこのディレクトリでコマンドを入力します。

## webpack導入とjsのバンドル
```bash:Terminal.app
$ yarn add webpack extglob --dev
```
package.jsonが生成され、devDependencesにwebpackの項目が追加されていれば大丈夫です。

次にsrc/js/entry.jsを作成しましょう。

```js:entry.js
document.write('hello, webpack.');
```
これで(とりあえず)javascriptの記述は終わりです。
yarn.lockのディレクトリに戻ってpackage.jsonを開き、下の記述にしましょう。

```json:package.json
{
  "devDependencies": {
    //省略
  },
  "scripts": {
    "build": "webpack"
  }
```
globalインストールしていないモジュールは本来、node_modulesからしか呼び出せませんが、scriptsに記述することで素早くに実行できるようになります。

```bash:Terminal.app
$ yarn webpack ./src/js/entry.js ./public/bundle.js
```
上記のコマンドを実行することで、./public内にbundle.jsが生成されます。

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>test</title>
  </head>
  <body>
    <script type="text/javascript" src="./bundle.js"></script>
    </body>
</html>

```

同じく./publicにindex.htmlを作成しましょう。
ここでbundle.jsを読むことで、先程記述したentry.jsの中身がindex.htmlに出力されます。

一々コマンドを叩くのが面倒なので、webpackのコンフィグを設定しましょう。
yarn.lockのあるディレクトリでwebpack.config.jsを作成し、以下の記述をしてください。

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

保存ができたら、以下のコマンドを実行します。

```bash:Terminal.app
$ yarn webpack
```

これで、先程のコマンドと同じ処理がされます。

### 外部jsの読み込み
次は、entry.jsに外部のjsを読み込みましょう。

```js:entry.js
document.write(require('./content.js'));
```

```js:content.js
module.exports = 'Hello, webpack!!';
```

entry.jsを此のように書き換え、同階層にcontent.jsを配置してください。
これで、entry.jsがcontent.jsをrequireして情報を代入してくれます。

## css,scssを読み込む
cssを読み込むには、別途でnode_modulesが必要なのでインストールします。

```bash:Terminal.app
$ yarn add style-loader css-loader sass-loader node-sass --dev
```
これを使ってcssやscssを読み込みます。
一応、package.jsonに追加されているか確認してくださいね。

```js:webpack.config.js
module.exports = {
  entry: './src/js/entry.js',
  output: {
    path: __dirname + '/public/',
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.css$/,
        loaders:['style-loader', 'css-loader']
      },
      {
        test: /\.scss$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader']
      }
    ]
  }
}
```

webpack.config.jsを上記のように書き換えてください。
moduleという項目を追加して、ローダーを読み込みました。
cssとscssはそれぞれこのローダーを用いてバンドルされます。

なお、webpackの環境ではscssをcssに変換せずに直接バンドルされるため、別にcssの方は定義する必要がありません。
必要ないのであれば適宜消して対応してください。(あっても困ることはない)

次にscssファイルを作りましょう。
./src/css/style.scssを作成します。

```scss:style.scss
body {
  background: #f00;
}
```
そしてこれをentry.jsで呼び出します。

```js:entry.js
require('../css/style.scss');
document.write(require('./content.js'));
```

これでscssをバンドルする準備が整いました。

```bash:Terminal.app
$ yarn webpack
```
バンドルが完了すると、index.htmlにcssが適用されていると思います。

## Browser-syncする。
やることが多いです。

```bash:Terminal.app
$ yarn add browser-sync npm-run-all
```

インストールが終わったら、package.jsonのscriptsに記述を追加します。

```json:package.json
{
  "devDependencies": {
    //省略
  },
  "scripts": {
    //省略
    "server": "browser-sync"
  }
}
```
次に、browser-syncのセットアップをします。

```bash:Terminal.app
$ server init
```
これで、yarn.lcokのディレクトリにbs-config.jsが生成されます。

```js:bs-config.js
module.export = {
  //省略
  "files": "./public",
  //省略
  "server": {
    "baseDir": "./public"
  },
  //省略
}
```
このように、filesとserverを変更します。
filesは、変更を監視するディレクトリ(ブラウザのリロードをするため)、baseDirはlocalhost/に相当するディレクトリです。

一見すると、fileは"./src"が正しいと思われますが、実はこれが落とし穴です。(後ほど解説します)

```bash:Terminal.app
$ yarn server start --config bs-config.js
```

これでlocalhost:3000に./public配下がデプロイされます。

ですが、まだsrc内を変更してもブラウザに反映されません。
fileを"./public"にしているのも要因の一つですが、srcが変更されていても、webpackでバンドルされるbundle.jsが自動で書き換わっていないため、どちらにせよ反映されないのです。(index.htmlで読み出しているデータはbundle.jsのみ)

では、先程インストールしたnpm-run-allを使ってsyncさせましょう。

```json:package.json
{
  "devDependencies": {
    //省略
  },
  "scripts": {
    //省略
    "watch:build": "webpack -w",
    "watch:server": "browser-sync start --config bs-config.js",
    "watch": "npm-run-all -p watch:*",
  }
}
```
package.jsonにこのような追記をしましょう。
そしてwatchを呼び出します。
watch:から始まるscriptsを並列に読み込んでくれます。

```bash:Terminal.app
$ yarn watch
```

ブラウザでlocalhost:3000を開くと、index.htmlが見れるかと思います。
また、scssやjsをいじると、ブラウザがリロードされて常に最新の状態が見れます。

### ES2015をトランスパイルする
最後に、ECMAScript2015(ES2015)の開発環境をセットアップします。

```bash:Terminal.app
$ yarn add bower babel-core babel-loader babel-preset-es2015 --dev
```
これで、パッケージのインストールは完了です。
見ての通りbabelを使ってトランスパイルします。

次に、webpack.config.jsを

```js:webpack.config.js
module.exports = {
  entry: './src/js/entry.js',
  output: {
    path: __dirname + '/public/',
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.css$/,
        loaders:['style-loader', 'css-loader']
      },
      {
        test: /\.scss$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.js?$/,
        exclude: /(node_modules|bower_components)/,
        loader: 'babel-loader'
      }
    ]
  }
}

```
jsのローダーを読み込みます。

これで、先程使用していたentry.jsやcontent.jsがES2015としてbundle.jsにトランスパイルされるようになります。

試しに、content.jsを以下のように書き換えてみましょう。

```javascript:content.js
class HelloWorld {
  get() {
    return "hello, world!";
  }
}
let a = new HelloWorld();

module.exports = a.get();
```
ブラウザに"Hello, world!"と表示されていたら導入成功です。

## 最後に
以上で開発環境のセットアップは終了です。
これを機にみなさんも最高の開発環境でフロントエンド開発を進めてみてください。

(他に話すことがないので)何かあれば連絡お願いします。
プルリク、コメントお待ちしています。