Rails5.1でCSSをwebpack-dev-serverによってHMR(ライブリロード)させる

Rails5.1から導入されたwebpackerにより、容易にモダンなフロントエンド開発環境を構築することが可能になりました。

中でも、webpack-dev-serverに寄って提供されているHMR(Hot Module Replacement)はフロントエンド開発の効率を大幅に向上させてくれるため、非常に重宝します。

Rails5.1では、このwebpack-dev-serverに関する設定もデフォルトで行われており、大変助かるのですが、デフォルトの設定ではJavaScriptしかサポートしてくれていません。

JSのフレームワークなど使っていれば、JS内でCSSを書くことも可能ですが、JSのフレームワークなんて知らねーよ！とか、ちょっとしたアプリ作るのにわざわざフレームワークなんて使わねーよ！とか、でもCSSもHMRしたい！ということはあると思います。（自分はありました。）

なので、自分と同じようなめんどくさがりな方々に向けて、Rails5.1でCSSをwebpack-dev-server管理化に置くために行なった設定を書いておきたいと思います。
(間違ってる。もっといい方法がある。そもそもデフォルトの機能で出来ますよ？等々あれば教えてください！)

では早速

# なにはともあれ、まずはrails new

webpackerを使用する場合、`rails new アプリ名 --webpack`といったように、普段のコマンドに`--webpack`オプションを加えます。

既に作成済みのアプリケーションに適用する場合は

```bash
# Gemfileに追記
gem 'webpacker'

bundle install
rails webpacker
```

です。

# webpackのエントリポイントを変更する

デフォルトのエントリポイントは`app/javascripts/packs`になっています。
CSSもwebpackの管理下に置きたいので`javascripts`はやめたいです。
そのためには以下の二つの手順が必要です。

* フォルダ名を変更する
* config/webpack/paths.ymlを変更する

## フォルダ名を変更する

`app/javascripts/packs`を`app/frontend/packs`に変更しましょう。

frontendのところはなんでもいいですが、わかりやすくfrontendとしておきます。

JSファイルとCSSは分けたいので、Railsよろしく、その中に`javascripts`フォルダと`stylesheets`フォルダを作成し、`application.js`と`application.scss`を作成しましょう。

## paths.ymlを変更する

paths.ymlはwebpack用のdatabase.ymlのようなものです。
エントリポイントなどを管理しています。

デフォルトでは以下のようになっていますが

```yaml
default: &default
  config: config/webpack
  entry: packs
  output: public
  manifest: manifest.json
  node_modules: node_modules
  source: app/javascripts
```

ファイル名の変更に伴い、以下のように変更します。

```yaml
default: &default
  config: config/webpack
  entry: packs
  output: public
  manifest: manifest.json
  node_modules: node_modules
  source: app/frontend
```

# manifest.jsonを変更する

manifest.jsonは、コンパイルしたファイルを配信するパスとprefix（であってるのか？）を管理するファイルです。
prefixは後で使います。

manifest.jsonを以下のように編集してください。

```public/packs/manifest.json
{
  "javascripts/application.js": "http://localhost:8080/packs/javascripts/application.js",
  "javascripts/application.js.map": "http://localhost:8080/packs/javascripts/application.js.map",
  "stylesheets/application.css": "http://localhost:8080/packs/stylesheets/application.css",
  "stylesheets/application.css.map": "http://localhost:8080/packs/stylesheets/application.css.map"
}
```

このmanifest.jsonですが、本来webpackerによって動的に生成されるものなんですが、今回はこれで固定したいので、設定を変更します。

config/webpack/shared.jsの40行目をいじります。

```config/webpack/shared.js
new ManifestPlugin({ fileName: paths.manifest, publicPath, writeToFileEmit: true })
// を
new ManifestPlugin({ fileName: paths.manifest, publicPath, writeToFileEmit: false })
// こう
```

これで固定できました。(絶対にもっといい方法ある。)

# JSとCSSの読み込み先を変更

デフォルトだと、今まで通りAssets Pipelineようのヘルパーが定義されているので、変更します。

```application.html.erb
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
を
<%= stylesheet_pack_tag 'stylesheets/application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'javascripts/application', 'data-turbolinks-track': 'reload' %>
こう
```

ここで、manifest.jsonで定義したprefixを使用しています。

ここまでの作業が完了したら

```bash
rails s
bin/webpack-dev-server
```

をそれぞれ別タブで走らせて、ブラウザを開いた状態でpacks下のapplication.jsとapplication.scssを変更すると、リアルタイムで変更が反映されているのがわかります。

※ Railsの初期ページ(Yay! You’re on Rails!のページ)だと読み込まれないので、気をつけてください。

公式のドキュメントをあんまり読んでいないので、ツッコミどころあるかと思いますが、ぜひツッコんでください。
`stylesheet_pack_tag`なんてのがあるくらいなので、もっとデフォルトの機能で出来そうな気がするのですが、知ってる方がいたら教えてほしいです。