Ruby on Rails + webpack-dev-server で Development.

Ruby on Rails + webpack-dev-server で Development.

Rails で JavaScript が必要なプライベートプロジェクトでは、ながらく Npm + Watchify + Gulp + Rails を手動起動などしながらすすめていましたが、最近、意を決して Yarn + Webpack + Rails に変更しました。そこで、Rails と JavaScript の接合点も Railsway にのった設定に変えようと思いました。(今までは public/css を直接参照していた)

ざっと検索したところ、webpack-dev-server 経由で JavaScript を参照する場合、あらたな helper を用意する方式しか見つけられなかったので、assets の path を変更する方式をメモります。

概要

webpack-dev-server を port 5001 で起動し、Rails の assets 用のタグがそれを参照するようにします。

Rails configuration

#config/environments/development.rb

Rails.application.configure do
  # snip
  config.action_controller.asset_host = 'http://localhost:5001'
end

Webpack configuration

Files place

JavaScript ファイルとして app1.js, app2.js, app3.js が書きだされる想定です。

- app # 他 Rails のディレクトリ
- public
- lib
  - sass
    - common.sass
  - src
    - app1
      - index.js
    - app2
      - index.js
    - app3
      - index.js
  - package.json

package.json

style-loader を噛ませるととても遅いので、sass は node-sass ダイレクトで書きだします。書きだし先のディレクトリを参照できるように、webpack-dev-server を --content-base でルートを public に合わせておきます。

  "scripts": {
    "watch": "webpack-dev-server --progress --colors --config ./webpack/dev.config.js --port 5001 --content-base ../public",
    "watch-sass": "node-sass --watch ./sass/common.sass ../public/stylesheets/common.css"
  },

webpack.config.js

publicPath を javascripts という、Rails ネーミングに合わせておきます。

sass も webpack-dev-server を通す場合、こちらにも publicPath が必要ですが、こちらは ExtractTextPlugin 側に設定しなければならない点に注意します。

const entryPoints =  require('glob').sync('./src/*/index.js').reduce((a, v)=> {
  a[v.split('/')[2]] = v
  return a
}, {})

const jsConfiguration = {
  entry: entryPoints,
  output: {
    publicPath: 'javascripts',
    filename: "[name].js"
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  }
}

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const cssConfiguration = {
  entry: './sass/common.sass',
  output: {
    publicPath: 'stylesheets',
    filename: "common.css"
  },
  module: {
    loaders: [
      {
        test: /\.sass|\.scss/,
        loader: ExtractTextPlugin.extract({
          fallbackLoader: "style-loader",
          loader: "css-loader?minimize!sass-loader",
          publicPath: 'stylesheets',
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin("common.css")
  ]
}

module.exports = [
  jsConfiguration,
  // cssConfiguration
]

できあがり

これで以下のようにコンパイルされ、webpack-dev-server は狙ったファイルを返すようになりました。

= javascript_include_tag('app1.js')
<script src="http://localhost:5001/javascripts/app1.js"></script>

なお Rails 起動時には webpack-dev-server も同時に起動することになりますが、Procfile.dev を用意して foreman で起動すると手間がかからなくて良いようです。

web: bundle exec rails server -p 5000
compile: cd lib/es && yarn run watch
compile: cd lib/es && yarn run watch-sass
foreman start -f Procfile.dev