RailsでSprocketsを使わないでwebpackを使いHMRで開発する

RailsでSprocketsを使わずwebpackを使って開発するために、必要最低限のやることをまとめます。ついでにHMRが出来るようにして開発時の利便性を高めます（必要最低限じゃなかったのか）。

ここから先は順を追って実装すれば環境が整うように書いていきます。

使っている代表的ソフトウェアのバージョン。

| ソフトウェア | バージョン |
|:--:|:--:|
|Rails| 5.1.1 | 
|webpack | 2.6.1 |
|webpack-dev-server | 2.4.5 |

## RailsのプロジェクトをSprocketsなしで作成する

まずは `rails new` を実行します。

```bash
$ rails new app_name --skip-sprockets --skip-javascript
```

`--skip-sprockets` でSprocketsを無くし、 `--skip-javascript` でJavaScriptの読み込みを無くします

## 必要なJavaScriptのパッケージをインストールする

必要なJavaScriptのパッケージをインストールします。

```bash
$ yarn add -D webpack webpack-dev-server webpack-manifest-plugin
```

必要最低限のパッケージをまずはインストールします。

## frontendディレクトリにJSを配置する

ビルド対象のJSを `frontend/src/index.js` のように書きます。

```JavaScript:index.js
alert('hoge')
```

今回はわかりやすく `alert` で `hoge` と出力するだけのコードにしています。

## webpack.configを開発用とproduction用を書く

開発時はHRMを行い、本番ではproduction用の設定でビルドしたいので今回は簡単に分けて書きます。

```JavaScript:webpack.config.dev.js
const webpack = require('webpack')
const path = require('path')
const ManifestPlugin = require('webpack-manifest-plugin')

module.exports = {
  entry: {
    index: path.resolve(__dirname, 'frontend/src/index.js')
  },
  output: {
    path: path.resolve(__dirname, 'public/dist'),
    filename: '[name].js',
    publicPath: 'http://localhost:8080/'
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV),
      },
    }),
  ],
  devServer: {
    headers: { 'Access-Control-Allow-Origin': '*' },
    contentBase: 'public/dist',
  },
}
```

開発用の `webpack.config` です。HMRをするため `output` の `publicPath` に公開されるURLを指定し、 `devServer` の設定を追加しています。

```JavaScript:webpack.config.prod.js
const webpack = require('webpack')
const path = require('path')
const ManifestPlugin = require('webpack-manifest-plugin')

module.exports = {
  entry: {
    index: path.resolve(__dirname, 'frontend/src/index.js')
  },
  output: {
    path: path.resolve(__dirname, 'public/dist'),
    filename: '[name]-[hash].js'
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV),
      },
    }),
    new webpack.optimize.UglifyJsPlugin({
      minimize: true,
      compress: {
        warnings: false,
      },
    }),
    new ManifestPlugin(),
  ],
}
```
Production用のmanifestをはき出すため、 `ManifestPlugin`を追加しています。 `output` の `filename` にハッシュ値付きのJSをはき出すように設定しています。

## package.jsonのscriptsに実行スクリプトを書く

`package.json` にproductionビルド用と開発用のスクリプトを書きます。

```json
"scripts": {
    "build": "NODE_ENV=production webpack --config webpack.config.prod.js --progress --colors",
    "dev": "NODE_ENV=development webpack-dev-server --config webpack.config.dev.js --progress --colors --inline --hot"
}
```

## manifest.jsonの場所をRailsの設定に追加する

production環境ではハッシュ値付きのJSの場所を `manifest.json` から特定する必要があるので、webpackではき出された `manifest.json` を読み込ませるようにinitializerに追加します。

```ruby:manifest.rb
if File.exist?(Rails.root.join('public', 'dist', 'manifest.json'))
  Rails.application.config.assets_manifest = JSON.parse(File.read(Rails.root.join('public', 'dist', 'manifest.json')))
end
```

## JavaScriptのパスを返すヘルパーの作成

productionと開発で読み込ませるJSが違うのでそれを返すヘルパーを追記します。

```ruby:application_helper.rb
module ApplicationHelper
  def assets_path(path)
    return "http://localhost:8080/#{path}" if Rails.env.development?
    manifest = Rails.application.config.assets_manifest
    path = manifest[path] if manifest && manifest[path].present?
    "/dist/#{path}"
  end
end
```

使い方としては以下のように`script`タグの`src`の中で使用します。

```erb
<script type="text/javascript" src="<%= assets_path('index.js') %>"></script>
```

## 実行

`webpack-dev-server` を起動します。

```bash
$ yarn run dev
```

コンパイルされ以下のように結果が得られ、alertの中を書き換えてその書き換えた内容が出ればコンパイルは成功です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11510/9a0a6e68-ef49-c1d7-178f-3aab3a5a2dd0.png)

ふがと書き換える。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11510/784abbd8-2b6b-b9df-e297-cf7ba65b4769.png)

## まとめ

必要最低限ですが、Railsのフロントエンド開発をwebpackで出来るように構築しました。必要最低限しかやっていないのでここから先は割と自由に出来ると思います。

成果物のURLは以下です
https://github.com/nasum/app_name

## 参考URL

[Rails + モダンJS環境(Webpack)で新規アプリ作成 - Qiita](http://qiita.com/UFO/items/3c4e6a323e86c0c64e04)

[webpack-dev-serverの基本的な使い方とポイント - dackdive's blog](http://dackdive.hateblo.jp/entry/2016/05/07/183335)