はじめに
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によるアセットパイプラインについては以下の記事を参照してください。
- 同一ファイル形式の分散を避けるという意味。例えば、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の使い方を覚えていただければと思います。