【Rails】Webpackerの基本情報と実装方法

はじめに

Rails 6からWebpackerが正式採用されました。Rails 5ではオプションで追加することができたWebpackerですが、Rails 6からは普通にアプリを作成するだけでWebpackerがインストールされ、必要な設定もすべて行われるのですぐにWebpackerを使い始められるようになりました。

本記事では、Webpackerの使い方についてまとめています。

Webpackerの基本

Webpackerについて

Webpackerとは、人気のフロントエンドビルドシステムであるWebpackをRails向けにカスタマイズしたものです。Webpackとは、複雑化するJavaScriptライブラリの依存関係を保ったり、ECMAScript 6 (ES6) で記述されたJavaScriptをトランスパイルしたり、複数のファイルを連結/圧縮することでアプリの表示を高速化したりする機能を備えています。

Sprocketsとの違い

Ruby on RailsにはSprocketsによるアセットパイプラインという機能があります。Sprocketsはアセットファイルを連結/圧縮しアプリの高速化を行なったり、SassやCoffeeScriptなどの高級言語をコンパイルする機能を持ちます。

WebpackerとSprocketsはよく似ていますが、WebpackerはJavaScriptライブラリの追加にNPMパッケージを使用します(SprocketsはRubyGems)。NPMパッケージ経由でJavaScriptライブラリを追加できるため、常に最新のJavaScriptライブラリを使用でき、依存関係を気にすることなくインストールできます。

Webpackerのある環境でもSprocketsを使うことができます。CSSや画像は引き続きSprocketsで扱ったり、古いRailsバージョンから使い続けていてWebpackerへの移行が難しい場合はSprocketsを使い続けることもできます。

ただし、ファイルを参照するためのヘルパーメソッドがWebpackerとSprocketsで異なるため、ファイルを分散することは避けたほうがいいでしょう1

Sprocketsによるアセットパイプラインについては以下の記事を参照してください。

  1. 同一ファイル形式の分散を避けるという意味。例えば、JavaScriptをWebpackerとSprocketsの両方に分散することにはあまり意味がない上、煩雑になるので避けるべきです。JavaScriptはWebpacker、CSSと画像はSprocketsで扱うという分け方はOKです。

Webpackerの使用

Webpackerのインストール

Rails 6以降はアプリを作成した時点でWebpackerがインストールされています。古いバージョンのRailsであったり、アプリ作成時にWebpackerのインストールをスキップした場合は、以下の手順でインストールすることができます。

GemfileにWebpackerを追加しbundle installを実行します。

Gemfile

gem 'webpacker'

Webpackerがインストールできたら、以下のインストールコマンドを実行します

$ rails webpacker:install

Webpackerの構成

Webpackerでは、app/javascripts/packs/ディレクトリ配下のJavaScriptファイル(*.js)はすべてエントリーファイルとして扱われます。実際のJavaScriptファイルやCSSファイル、画像ファイルはapp/javascripts/ディレクトリ配下に配置します。

エントリーファイルをpacks/ディレクトリ配下に配置しなければいけないという以外は、Webpackerの構成はこうしなければいけないという決まりはありません。ファイル形式ごとのディレクトリを作ったり、コンポーネントごとのディレクトリを作ったり、自由に構成することができます。

以下は2種類のエントリーファイルを構成した場合の例です。

app/
 |-javascripts/
    |-packs/
    |  |-application.js   # 全ページ共通のエントリーファイル
    |  |-component.js     # コンポーネント固有のエントリーファイル
    |
    |-javascripts/
    |  |-application.js   # 全ページ共通のコード
    |  |-component.js     # コンポーネント固有のコード
    |
    |-stylesheets/
    |  |-application.css  # 全ページ共通のスタイル
    |  |-component.css    # コンポーネント固有のスタイル
    |
    |-images/
       |-cover.png        # 画像ファイル
       |-favicon.ico      # 画像ファイル

後述するコンパイルを実行すると、public/packs/js/ディレクトリ配下に一意なダイジェスト付きでエントリーファイルごとのパックファイルが作成されます。また、public/packs/media/images/ディレクトリ配下に一意なダイジェスト付きで画像ファイルがコピーされます。

以下は上記の構成でコンパイルを実行した場合の例です。

public/
 |-packs/
    |-js/
    |  |-application-05f0bb437653af4531cb.js       # 全ページ共通のパックファイル
    |  |-application-05f0bb437653af4531cb.js.map   # パックファイルのマップファイル
    |  |-component-9472f6a9d53bd2eab7ce.js         # コンポーネント固有のパックファイル
    |  |-component-9472f6a9d53bd2eab7ce.js.map     # パックファイルのマップファイル
    |
    |-media/
    |  |-images/
    |     |-cover-1f7ba4ee47972015f711b8d1be006752.png     # 画像ファイル
    |     |-favicon-876ac9c783c040793dc4429b36726157.ico   # 画像ファイル
    |
    |-manifest.json   # マニフェストファイル

設定でデフォルトのパスを変更することができます。config/webpacker.ymlの以下の設定を変更します。設定を変更したらwebpack-dev-serverコマンドを再起動してください。

webpacker.yml

default: &default
  source_path: app/javascripts   # ソースパス
  source_entry_path: packs       # ソースエントリーパス
  public_root_path: public       # 公開パス
  public_output_path: packs      # 公開出力パス

ファイルのインポート

Webpackerの構成が決定したら、エントリーファイルでファイルをインポートします。インポートファイルはエントリーファイルからの相対パスで指定します。以下は「Webpackerの構成」セクションの構成で、全ページ共通のエントリーファイルapplication.jsでファイルをインポートする例です。

application.js

// JavaScript/CSSのインポート
import '../javascripts/application.js'
import '../stylesheets/application.css'

// 画像のインポート(コメントアウトを外す)
const images = require.context('../images', true)
const imagePath = (name) => images(name, true)

Webpackerのコンパイル

Webpackerのコンパイルはファイルを参照するページにアクセスしたときに自動で実行されます。bin/ディレクトリ配下のwebpackコマンドまたはwebpack-dev-serverコマンドを実行すると手動でコンパイルすることができます。

webpackコマンドは一度だけWebpackerのコンパイルを行います。webpack-dev-serverコマンドはエントリーファイル(およびエントリーファイルでインポートされているファイル)を監視し、変更が発生した場合に自動でコンパイルを行います。また、Railsのテストサーバーが起動中で、ファイルを参照するページをブラウザで開いている場合は自動で更新されます。なお、webpackコマンドに--watchオプションをつけるとwebpack-dev-serverと同じ動きになります。

webpack --watchコマンドまたはwebpack-dev-serverコマンドの実行中に追加した新しいエントリーファイルは認識されないので、コマンドを再実行する必要があります。

# 一度だけコンパイル
$ bin/webpack

# ファイルを監視し自動でコンパイル
$ bin/webpack-dev-server

また、もともとSprocketsだけをコンパイルするコマンドだったrails assets:precompileにWebpackerのコンパイルが追加されました。このコマンドを自分で実行することはあまりないと思いますが、このコマンドがあることで従来のデプロイプロセスを変更することなくWebpackerのコンパイルが行えるようになっています。

デプロイツールにCapistranoを使っている場合、以下のように設定されていれば自動でコンパイルが実行されます。

Capfile

require "capistrano/rails/assets"

また、Herokuにデプロイする場合はビルドプロセスの一環でコンパイルも行われるので、こちらも手動で実行する必要はありません。

$ git push heroku master

remote: -----> Preparing app for rails asset pipeline
remote:        Running: rake asset:precompile
...
remote:        Asset precompilation completed (2.76s)

パックファイルの参照

CSS/JavaScriptファイルの参照

CSS/JavaScriptファイルを参照するには以下のように記述します。

application.html.erb

<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

application.html.slim

= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'

Turbolinksについては以下の記事を参照してください。

画像ファイルの参照(ビュー)

画像ファイルを参照するには以下のように記述します。

index.html.erb

<%= image_pack_tag 'cover.png' %>

index.html.slim

= image_pack_tag 'cover.png'

Webpackerのヘルパーメソッドasset_pack_pathを使うこともできます。asset_pack_pathはファイル名の先頭にmedia/images/をつける必要があるので注意してください。ファイル名だけを指定するとWebpacker::Manifest::MissingEntryErrorというエラーになります。

index.html.erb

<%= link_to asset_pack_path('media/images/cover.png') do %>
  <%= image_pack_tag 'cover.png' %>
<% end %>

index.html.slim

= link_to asset_pack_path('media/images/cover.png') do
  = image_pack_tag 'cover.png'

画像ファイルの参照(CSS)

CSSで背景画像などを設定したい場合、画像ファイルをCSSファイルからの相対パスで記述します。

background-image: url('../../images/cover.png');

アイコンファイルの参照

アイコンファイルを参照してFaviconを設定したい場合、favicon_pack_tagを使用します。

application.html.erb

<%= favicon_pack_tag 'favicon.ico' %>

application.html.slim

= favicon_pack_tag 'favicon.ico'

まとめ

Webpackはコンパイルが遅かったり設定ファイルが複雑でわかりにくいと言われることもありますが、WebpackをラップしたWebpackerを素直に使う分にはそれほど難しくはありません。Ruby on RailsからSprocketsが完全に削除されることはないと思われますが、Webpackerの使用を推奨されていることは確かなので、使ったことがないという人は一度使ってみることをおすすめします。

本記事を参考にして、Webpackerの使い方を覚えていただければと思います。

関連記事

【Rails】Paranoiaを使用した論理削除(ソフトデリート)
# はじめに Paranoiaは、Railsアプリケーションで論理削除(ソフトデリート)を実現するためのGemです。 論理削除は、データベースのレコードを物理的に削除するのではなく、削除フラグを設定することで「削除済み」とみなす方法です。こ [...]
2024年7月20日 21:33
【Rails】activerecord-multi-tenantを使用したマルチテナントアプリケーションの作成
# はじめに マルチテナントアプリケーションでは、複数の顧客(テナント)が同じアプリケーションを利用するため、データの分離が必要です。 activerecord-multi-tenantは、このようなマルチテナント環境をサポートするための便 [...]
2024年7月18日 16:50
【Rails】RubyとRailsにおけるattr_reader, attr_writer, attr_accessorの概念と使用方法
# はじめに RubyとRailsの開発において、`attr_reader`,`attr_writer`,`attr_accessor`は非常に便利なメソッドです。これらは、クラス内でインスタンス変数に対するゲッターおよびセッターメソッドを簡単に [...]
2024年7月17日 18:11
【Rails】RubyとRailsにおけるyieldの概念と使用方法
# はじめに RubyとRailsにおける`yield`は、メソッドやテンプレートの中で動的にコードブロックを実行する能力を提供し、これによってコードの再利用性と拡張性が大幅に向上します。本記事では、RubyとRailsにおける`yield`の概 [...]
2024年7月17日 13:15
【Rails】AASMを使用してオブジェクトの状態遷移を効率的に管理
# はじめに Railsアプリケーションにおいて、オブジェクトの状態管理は重要な課題の一つです。AASM (Acts As State Machine) gemは、複雑な状態遷移を効率的に管理します。本記事では、AASMの基本的な使い方を解説して [...]
2024年7月16日 18:00
【Rails】RSpec + Swagger + rswagでアプリケーションのAPIをテストおよびドキュメント化する方法
# はじめに Railsアプリケーションの開発において、APIのテストとドキュメント化は重要な要素です。 RSpecはテストフレームワークとして広く利用されており、SwaggerはAPIの設計とドキュメント化を支援します。これらを統合するr [...]
2024年7月16日 14:27
【Rails】mailcatcherを使用して開発環境でメール送信をテストする方法
# はじめに mailcatcherは、開発環境でのメール送信をキャプチャするためのツールです。ローカルで送信されたメールをブラウザ上で簡単に確認できるようにします。mailcatcherをRailsアプリケーションで使用する方法について説明しま [...]
2024年7月15日 16:37
【Rails】impressionistを使用してページビューやクリック数を追跡する方法
# はじめに impressionist Gemを使用してRailsアプリケーションでページビューやクリック数を追跡する方法について説明します。 # 実装方法 ## impressionist Gemのインストール まず、impre [...]
2024年7月15日 14:18