本ガイドではWebpackerのインストール方法と、Railsアプリケーションのクライアント側で用いるJavaScriptやCSSなどのアセットをWebpackerで利用する方法について解説します。ただしWebpackerの開発は終了した点にご注意ください(訳注: 移行方法は末尾の参考資料をご参照ください)。
このガイドの内容:
Webpackerは、汎用的なwebpackビルドシステムのRailsラッパーであり、標準的なwebpackの設定と合理的なデフォルト設定を提供します。
webpackなどのフロントエンドビルドシステムの目的は、開発者にとって使いやすい方法でフロントエンドのコードを書き、そのコードをブラウザで利用しやすい方法でパッケージ化することです。webpackは「JavaScript」「CSS」「画像やフォント」といった静的アセットを管理できます。webpackを使うと、「JavaScriptコードの記述」「アプリケーション内の他のコードの参照」「コードの変換(トランスパイル)や結合」をダウンロードしやすいpackにまとめられます。
詳しくはwebpackのドキュメントを参照してください。
RailsにはSprocketsも同梱されています。SprocketsもWebpackerと同様のアセットパッケージングツールで、Webpackerと機能が重複しています。どちらのツールも、JavaScriptをブラウザに適したファイルにコンパイルすることでproduction環境でのminifyやフィンガープリント追加を行えます。development環境では、SprocketsもWebpackerもファイルをインクリメンタルに変更できます。
SprocketsはRailsで使われる前提で設計されているため、統合方法はWebpackerよりもシンプルで、Ruby gemを用いてSprocketsにコードを追加できます。webpackは、より新しいJavaScriptツールやnpmパッケージとの統合に優れており、より多くのものを統合できます。新しいRailsアプリは「JavaScriptはwebpackで管理する」「CSSはSprocketsで管理する」設定になっていますが、webpackでCSSを管理することもできます。
新しいプロジェクトで「npmパッケージを使いたい場合」「最新のJavaScript機能やツールにアクセスしたい場合」は、Sprocketsではなくwebpackerを選択すべきでしょう。「移行にコストがかかるレガシーアプリケーション」「gemで統合したい場合」「パッケージ化するコードの量が非常に少ない場合」は、WebpackerではなくSprocketsを選ぶべきでしょう。
Sprocketsに慣れ親しんでいる方は、以下の表を参考に両者の対応関係を理解するとよいでしょう。なお、ツールごとに構造が微妙に異なっているため、必ずしも概念が直接対応しているとは限らない点にご注意ください。
| タスク | Sprockets | Webpacker |
|---|---|---|
| JavaScriptをアタッチする | javascript_include_tag |
javascript_pack_tag |
| CSSをアタッチする | stylesheet_link_tag |
stylesheet_pack_tag |
| 画像にリンクする | image_url |
image_pack_tag |
| アセットにリンクする | asset_url |
asset_pack_tag |
| スクリプトをrequireする | //= require |
importまたはrequire
|
Webpackerを使うには、Yarnパッケージマネージャー(1.x以上)とNode.js(10.13.0以上)のインストールが必要です。
WebpackerはnpmとYarnに依存しています。npm(Node Package Manager)レジストリは、Node.jsとブラウザランタイムの両方で、主にオープンソースのJavaScriptプロジェクトの公開やダウンロードに用いられるリポジトリです。npmの位置づけは、Rubyのgemを扱うrubygems.orgに似ています。Yarnコマンドラインユーティリティは、RubyのBundlerと位置づけが似ています。BundlerがRubyの依存関係のインストールや管理を行うのと同様に、YarnはJavaScriptの依存関係をインストールおよび管理できます。
新規プロジェクトにWebpackerを含めるには、rails newコマンドに--webpackを追加します。
既存のプロジェクトにWebpackerを追加するには、プロジェクトのGemfileにwebpacker gemを追加してbundle installを実行し、続いてbin/rails webpacker:installを実行します。
| ファイルとフォルダ | 場所 | 説明 |
|---|---|---|
| JavaScriptフォルダ | app/javascript |
フロントエンド向けJavaScriptソースコードの置き場所 |
| Webpacker設定ファイル | config/webpacker.yml |
Webpacker gemを設定する |
| Babel設定ファイル | babel.config.js |
Babel(JavaScriptコンパイラ)の設定 |
| PostCSS設定ファイル | postcss.config.js |
PostCSS(CSSポストプロセッサ)の設定 |
| Browserlistファイル | .browserslistrc |
Browserlist(対象ブラウザを管理する)設定 |
また、インストールコマンドはyarnパッケージマネージャを呼び出してpackage.jsonというファイルを作成し、基本的なパッケージセットのリストをこのファイルに含めます。これらの依存関係はYarnでインストールされます。
Webpackerをインストールすると、app/javascript/packsディレクトリ以下のJavaScriptファイルがコンパイルされて独自のpackファイルにまとめられます。
たとえば、app/javascript/packs/application.jsというファイルが存在すると、Webpackerはapplicationという名前のpackを作成します。このpackは、<%= javascript_pack_tag "application" %>というERBコードが使われているRailsアプリケーションで追加されます。これによって、development環境ではapplication.jsが変更されるたびに再コンパイルされ、ページを読み込むとコンパイル後のpackが使われます。実際のpackディレクトリに置かれるのは、主に他のファイルを読み込むマニフェストファイルですが、任意のJavaScriptコードも置けます。
RailsのデフォルトJavaScriptパッケージがプロジェクトに含まれていれば、Webpackerで作成されたデフォルトのpackはそのデフォルトJavaScriptパッケージにリンクします。
import Rails from "@rails/ujs" import Turbolinks from "turbolinks" import * as ActiveStorage from "@rails/activestorage" import "channels" Rails.start() Turbolinks.start() ActiveStorage.start()
これらのパッケージをRailsアプリケーションで使うには、これらのパッケージをrequireするパックをインクルードする必要があります。
app/javascript/packsディレクトリにはwebpackのエントリーファイルだけを置き、それ以外のものを置かないことが重要です。webpackはエントリーポイントごとに個別の依存関係グラフを作成するので、packを多数作成するとコンパイルのオーバーヘッドが大きくなります(アセットのその他のソースコードはこのディレクトリの外に置くべきです: Webpacker自身はソースコードの構造に制約をかけませんが、適切なソースコード構造を提案することもありません)。以下はソースコード構造の例です。
app/javascript:
├── packs:
│ # ここにはwebpackエントリーファイルだけを置くこと
│ └── application.js
│ └── application.css
└── src:
│ └── my_component.js
└── stylesheets:
│ └── my_styles.css
└── images:
└── logo.svg
通常、packファイル自体はimportやrequireで必要なファイルを読み込むマニフェストですが、いくつかの初期化を行うこともあります。
これらのディレクトリを変更したい場合は、config/webpacker.ymlファイルのsource_path(デフォルトはapp/javascriptディレクトリ)とsource_entry_path(デフォルトはpacksディレクトリ)も変更してください。
JavaScriptソースファイル内のimportステートメントは、インポートするファイルの位置を「相対的に」解決します。つまり、import Bar from "./foo"と書くと、現在いるディレクトリにあるfoo.jsファイルを探索しますが、import Bar from "../src/foo"と書くとsrcという名前の親ディレクトリにあるファイルを探索します。
Webpackerでは、PostCSSプロセッサを用いてCSSやSCSSのサポートを即座に利用できます。
CSSコードをpackにインクルードするには、まずCSSファイルをトップレベルのpackファイルにインクルードします(JavaScriptファイルをインクルードするときと同じ要領です)。つまり、CSSのトップレベルマニフェストがapp/javascript/styles/styles.scssにある場合は、import styles/stylesでインポートします。これにより、webpackがCSSファイルをダウンロードに含められるようになります。実際にWebページで読み込むには、ビューのコードに<%= stylesheet_pack_tag "application" %>を追加します。
CSSフレームワークを用いる場合は、フレームワークをyarnでnpmモジュールとして読み込むインストール手順(yarn add <フレームワーク名>が典型)に従えば、Webpackerにフレームワークを追加できます。たいていのフレームワークには、CSSやSCSSファイルにインポートする手順があるはずです。
Webpackerのデフォルト設定では、画像やフォントなどの静的アセットもすぐに使えるようになっています。この設定には画像ファイルやフォントファイルのフォーマットに対応する拡張子が多数含まれており、webpackはそれらの拡張子も生成されたmanifest.jsonファイルに追加します。
webpackのおかげで、以下のコード例のように静的アセットをJavaScriptファイル内で直接インポートできます。インポートされた値は、そのアセットへのURLを表します。
import myImageUrl from '../images/my-image.jpg' // ... let myImage = new Image(); myImage.src = myImageUrl; myImage.alt = "I'm a Webpacker-bundled image"; document.body.appendChild(myImage);
Webpackerの静的アセットをRailsのビューで参照する必要がある場合は、WebpackerにバンドルされるJavaScriptファイルで明示的にrequireする必要があります。Sprocketsとは異なり、Webpackerはデフォルトでは静的アセットをインポートしない点にご注意ください。デフォルトのapp/javascript/packs/application.jsファイルには、指定のディレクトリからファイルをインポートするテンプレートがコメントの形で用意されているので、静的ファイルを置きたいディレクトリごとにコメント解除して利用できます。ディレクトリはapp/javascriptを起点とする相対パスです。テンプレートではimagesというディレクトリ名になっていますが、app/javascriptの中であれば任意のディレクトリ名に変更できます。
const images = require.context("../images", true)
const imagePath = name => images(name, true)
静的アセットは、public/packs/mediaディレクトリ以下に出力されます。たとえば、app/javascript/images/my-image.jpgにある画像をインポートすると、public/packs/media/images/my-image-abcd1234.jpgに出力されます。この画像のimageタグをRailsのビューでレンダリングするには、image_pack_tag 'media/images/my-image.jpgを使います。
Webpackerで静的アセットを扱う場合のAction Viewヘルパーについては、以下の表でアセットパイプラインのヘルパーとの対応を確認できます。
| ActionViewヘルパー | Webpackerヘルパー |
|---|---|
favicon_link_tag |
favicon_pack_tag |
image_tag |
image_pack_tag |
asset_pack_pathというジェネリックなヘルパーも利用できます。このヘルパーにローカルファイルのパスを渡すと、Railsのビューで使えるWebpackerパスを返します。
また、app/javascriptのCSSファイルから直接ファイルを参照して画像にアクセスすることもできます。
バージョン5の時点のWebpackerは「Railsエンジン対応」ではありません。つまりWebpackerは、Railsエンジンで利用できるSprocketsと機能的な互換性がありません。
Railsエンジンgemの作者がWebpackerの利用をサポートする場合は、フロントエンドアセットをgem本体に追加してnpmパッケージとして配布し、ホストアプリケーションとの統合方法を説明する指示書(またはインストーラ)を提供することが推奨されます。Alchemy CMSは、このアプローチの良い例です。
Webpackerは、webpack-dev-serverでのHMR(Hot Module Replacement)をすぐ利用できるようになっており、webpacker.ymlファイルでdev_server/hmrオプションを設定することで切り替えられます。
詳しくはwebpackのDevServerドキュメントを参照してください。
ReactでHMRをサポートするには、react-hot-loaderの追加が必要です。詳しくはReact Hot LoaderのGetting Startedガイドを参照してください。
webpack-dev-serverを実行していない場合は、HMRを必ず無効にしてください。そうしないと、CSSで"not found error"エラーが発生します。
Webpackerにはデフォルトでdevelopment、test、productionの3つの環境があります。webpacker.ymlファイルに環境設定を追加することで、環境ごとに異なるデフォルトを設定できます。また、Webpackerは環境設定を追加するためにconfig/webpack/<environment>.jsファイルを読み込みます。
Webpackerには、development環境で実行する./bin/webpackと./bin/webpack-dev-serverという2つのbinstubファイルが同梱されます。これらのbinstubファイルは、標準の実行ファイルであるwebpack.jsとwebpack-dev-server.jsの薄いラッパーになっており、環境に応じて適切な設定ファイルや環境変数が読み込まれるようになっています。
development環境のWebpackerは、デフォルトでRailsページが読み込まれると必要に応じて自動的にコンパイルを行います。つまり別のプロセスの実行は不要であり、コンパイルエラーは標準のRailsログに出力されます。これを変更するには、config/webpacker.ymlファイルをcompile: falseに変更します。bin/webpackを実行すると、packを強制的にコンパイルします。
コードのライブリロード機能を使いたい場合や、JavaScriptコードが多くてオンデマンドのコンパイルが遅くなる場合は、./bin/webpack-dev-serverまたはruby ./bin/webpack-dev-serverを実行する必要があります。webpack-dev-serverのプロセスは、app/javascript/packs/*.jsファイルの変更を監視して変更時に自動的に再コンパイルし、ブラウザを再読み込みします。
Windowsユーザーは、これらのコマンドをbundle exec rails serverとは別のターミナルで実行する必要があります。
このdevelopmentサーバーを起動すると、Webpackerが自動的にすべてのwebpackアセットリクエストをこのサーバーにプロキシします。サーバーを停止すると、オンデマンドのコンパイルに戻ります。
Webpackerドキュメントには、webpack-dev-serverを制御する環境変数の情報が記載されています。また、rails/webpackerのwebpack-dev-server利用法ドキュメントにある追加の注意事項も参照してください。
Webpackerはbin/rails assets:precompileのrakeタスクにwebpacker:compileタスクを追加するので、assets:precompileを使う既存のデプロイパイプラインはすべて動作します。webpacker:compileタスクはpackをコンパイルしてpublic/packsに配置します。
Webpackerでメジャーなフレームワークを利用する方法などの高度な話題については、Webpackerドキュメントを参照してください。
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。