前回の記事では、モダンなフロントエンド開発環境をつくる手順として、フロント側の設定について書きました。 今回はサーバ側の設定についてまとめます。

やること

サーバ側の設定としては、次の設定を行ないます。

  1. マニフェスト(JSON形式)を解析して変数に格納する
  2. ヘルパでファイルのURLを取得するメソッドを定義する
  3. ファイルをheadタグから参照する

また、付録として次の設定についても書いています。

  • デプロイ時にwebpackでビルドする
  • コマンド1つでサーバ起動&ビルド監視を行なう

手順

1. マニフェストを読む

本番環境では、キャッシュ対策としてファイルにハッシュ値をつけています。 Sprocketsを使っていれば勝手にやってくれますが、webpackの場合自分で設定しなければなりません。

webpack-manifest-pluginを使えば、本番環境向けのビルド時に各ファイルとそのハッシュ値つきのファイル名をJSONオブジェクトとして出力してくれます。

これをアプリケーションサーバ起動時に読み、ヘルパに渡します。

app/config/initializers/assets.rb:

if Rails.env.production?
  manifest_path = Rails.root.join('public', 'assets', 'webpack.manifest.json')

  if File.exists?(manifest_path)
    Rails.application.config.assets.webpack_manifest = JSON.parse(File.read(manifest_path))
  end
end

2. ヘルパにメソッドを定義する

本番環境でのアセットへのパスは、ファイル名にハッシュ値を含めないといけません。 1で読んだマニフェストを元に、ハッシュ値つきのURLを返すメソッドをヘルパに定義します。

開発環境では、webpack-dev-serverに向けています。

app/helpers/application_helper.rb:

module ApplicationHelper
  def webpack_asset_path(path)
    if Rails.env.development?
      return "http://localhost:8080/assets/#{path}"
    end

    manifest = Rails.application.config.assets.webpack_manifest

    if manifest && manifest[path].present?
      path = manifest[path]
    end

    "#{compute_asset_host}/assets/#{path}"
  end
end

3. ビューから参照する

あとは、headタグ内で次のように参照すれば、開発環境ではwebpack-dev-server、本番環境ではハッシュ値つきのファイルのURLを参照します。

<%= stylesheet_link_tag webpack_asset_path('application.css') %>
<%= javascript_include_tag webpack_asset_path('application.js') %>

付録

デプロイ時にビルドする

Capistranoなどでデプロイする際、Unicornなどのアプリケーションサーバをリロードする前に、アセットをビルド→マニフェストの配備を行なう必要があります。

まずは次のようにビルド関連のスクリプトを登録します。

{
  "scripts": {
    "webpack:clearn": "rimraf public/assets",
    "webpack:build": "NODE_ENV=production $(npm bin)/webpack -p",
    "build": "npm run webpack:clean && npm run webpack:build"
  }
}

rimrafはNode.jsでrm -rfを実行するためのパッケージです。 必要に応じてインストールしておきます。

上記のbuildをデプロイ時に実行します。 capistrano-npmを導入している場合、npm:installタスクが挿入されるので、そこにフックをかければよいです。

namespace :deploy do
  namespace :assets do
    task :build do
      execute "cd #{release_path} && npm run build"
    end
  end
end

after 'npm:install', 'deploy:assets:build'

これで、アセットがビルドされてpublic/assetsに配備されるとともに、ハッシュ値つきのファイル名が記載されたマニフェストファイルが生成されます。

Foremanでプロセスを起動する

Foremanは、複数のプロセスを管理するGemです。 今回のケースでは、Railsとwebpack-dev-serverの起動&終了を一手に担ってくれます。

まず、webpack-dev-server用のスクリプトを登録します。

package.json:

{
  "scripts": {
    "webpack:watch": "webpack-dev-server"
  }
}

あとは、次のようなProcfileを用意すれば、foreman startで2つのプロセスを起動することができます。

Procfile:

rails: bundle exec rails server
webpack: npm run webpack:watch

参考記事

おわりに

前回の記事とあわせて、モダンなフロントエンド開発環境が構築できました。 webpackは一度覚えておくととても便利なので、参考になればと思います。