Rails5でのWebpackerによるBootstrapの利用

はじめに

Rails6からWebpackerが標準で入っているようですが、ここではRails5での導入を試みてみます。

今までは、JQueryやBootstrapを導入するには、それぞれのGemをインストールする必要があり、SprocketsというGemによって複数のアセットファイル(JS、CSSや画像)をコンパイル(結合や圧縮)を行うアセットパイプラインという仕組みを実装していました。

今後は、GemではなくyarnにてJSやCSSのパッケージを管理し、Webpackというアセットファイルを1のJSファイルにまとめて管理するモジュールバンドラをWebpackerというGemで利用するのが主流のようです。

Webpackerは、rails new コマンド実行の際に、次のオプションをつけることで導入できます。

--webpack --skip-coffee --skip-turbolinks --skip-sprockets

要は、Gemfileにwebpackerを登録し、sprocketsなんかのGemの記述を削除するだけです。
また、予めシステムにyarnとnode.jsをインストールしておく必要があります。

yarnでbootstrapを入れる

その際に、jquery、 popper.js も依存ライブラリなので入れます。
その前に、現在の package.json の内容を確認しておきます。

package.json

{
  "name": "sample_app",
  "private": true,
  "dependencies": {
    "@rails/webpacker": "5.2.1"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.11.0"
  }
}

yarnにてセットアップします。

$ bin/yarn add bootstrap jquery popper.js @popperjs/core

※Docker環境で動いている場合は、コンテナ内で実行します。
追記(2021/05/17): セットアップすべきライブラリとして「@popperjs/code」を追記しました。

Rails-ujsの導入

以前jquery-ujsと呼ばれていたもので、今はrails-ujsに代わっています。

RailsのRESTfulの一部(DELETE、UPDATE)での動作をHTTPのPOSTリクエストで実現するために、JavaScriptを使用しているため、このrails-ujsは必要不可欠です。

Rails 5.1 よりRails本体に取り込まれているので gem install は不要になりましたが、Webpackerを使用する場合は導入されません。
また、JavaScriptのエントリポイントから明示的に import する必要があります。
ということで、これも yarn でインストールします。

$ bin/yarn add rails-ujs

package.json の中身を確認します。

package.json

{
  "name": "sample_app",
  "private": true,
  "dependencies": {
    "@rails/webpacker": "5.2.1",
    "bootstrap": "^4.5.2",
    "jquery": "^3.5.1",
    "popper.js": "^1.16.1",
    "rails-ujs": "^5.2.4-4"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.11.0"
  }
}

Webpackerのでディレクトリ構成

従来の「app/assets/javascripts」は残ったままになっています。
アセットパイプラインを利用する場合は、こちら配下にJSやCSSを入れて、Sprocketsによってビルドされることになります。

Webpackerの場合は、「app/javascript」に置くことになります。GitHubのWebpackerのREADME.mdによると、次のような配置を想定しているようです。

app/javascript:
  ├── packs:
  │   # only webpack entry files here
  │   └── application.js
  │   └── application.css
  ├── src:
  │   └── my_component.js
  ├── stylesheets:
  │   └── my_styles.css
  └── images:
      └── logo.svg

(参考)
webpacker/README.md at master · rails/webpacker
 https://github.com/rails/webpacker/blob/master/README.md

app/javascript」配下に、コンパイル前のJSやCSSを置くことになりますが、特にディレクトリ構成等は決まりはないようです。そして、「public/packs」にコンパイル後のファイルが入るようです。

今回は「app/javascripts」ディレクトリの下に、「stylesheets」ディレクトリを作成し、その中に、「application.scss」を作成します。また、画像ファイルを入れるためのディレクトリ「images」も作成して用意します。

$ mkdir app/javascript/stylesheets
$ mkdir app/javascript/images
$ touch app/javascript/stylesheets/application.scss

ディレクトリツリー構成は次の通りです。

$ tree app/javascript/
app/javascript/
├── images
├── packs
│   └── application.js
└── stylesheets
    └── application.scss

application.scssを編集します。

app/javascript/stylesheets/application.scss

@import "~bootstrap/scss/bootstrap";

bootstrapをGemで入れた場合は、「@import "bootstrap"」で良いのですが、yarnで追加したCSSを指定する場合は、チルダ「~」を使用することで、node_modulesまでのパスを解決してくれます。

"~bootstrap/scss/bootstrap"
→ "node_modules/bootstrap/scss/bootstrap.scss"

jQueryとBootstapのJSを使えるようにする

次に、エントリポイントであるapplication.jsを編集します。

ただし、以下の文をapplication.jsの先頭に入れます。CRSFセキュリティエラーを起こさないようにするためらしい。

import Rails from 'rails-ujs';
Rails.start();

app/javascript/pack/application.js

import 'jquery'
import 'bootstrap'
import '../stylesheets/application'
import Rails from 'rails-ujs';
Rails.start();
const images = require.context('../images', true)

続いて、app/views/layouts/application.html.erbにて、CSSとJSの読み込み先をWebpackにします。

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>SampleApp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

-    <%= stylesheet_link_tag    'application', media: 'all' %>
-    <%= javascript_include_tag 'application' %>
+    <%= javascript_pack_tag 'application' %>
+    <%= stylesheet_pack_tag 'application' %>

  </head>
  <body>
+    <div class="container-fluid">
      <%= yield %>
+    </div>
  </body>
</html>

※8行目と9行目(頭が「-」の行)は削除します。

Bootstrap V4.1は、jqueryとpopper.jsに依存するので、webpackにプラグインとして導入します。

config/webpack/environment.js

const { environment } = require('@rails/webpacker')
const webpack = require('webpack')

environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
  })
)
module.exports = environment

webpackの設定(webpack/environment.js)でProvidePluginを加えると、importやrequireなしで$やBootstrapのJavaScriptが使えるようになるそうです。

(参考)

確認

試しにrails generateコマンドにて、適当なコントローラとビューファイルを作成してみます。その際にSproketsで利用するアセットファイルを作成しないようオプション「--skip-assets」を付けてやります。

$ bundle exec rails g controller StaticPages home help --skip-assets

予め、config/application.rb に次のように設定しておいて、rails g やったときに、余計なassetsを作成しないようにする方法もあります。

config/application.rb

module SampleApp   
  class Application < Rails::Application
    config.load_defaults 5.1
    config.generators do |g|
      g.assets false
    end
end

(参考)
Rails5.1ではAsset Pipeline捨てたほうがいいらしいので捨ててみた – Qiita
 https://qiita.com/ry_2718/items/9b824a3f9ca750ce403e

テストとして、生成されたビュー「app/views/static_pages/help.html.erb」に、次のようにbootstrapのスタイルを記述したタグを書いてみます。

app/views/static_pages/help.html.erb

<h1>Sample App</h1>
<p>This is help page. Help!</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a></p>

JSやCSSをコンパイルするには、次のコマンドを実行します。

$ bin/webpack

もしくは、次のコマンドを一回実行しておけば、JSやCSSのコードの変更を自動検知して再コンパイルしてくれる。

$ bin/webpack-dev-server

「rails s(こちらの例では、pumaを使用)」と「webpack-dev-server」、それぞれのプロセスをまとめて管理できるツールとして foreman があります。
Gemなので、Gemfileに追記し、bundle installします。

Gemfile

group :development do
  # Access an interactive console on exception pages or by  calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application  running in the background. Read more:  https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'foreman'
end
:
$ bundle install

Railsアプリのルートディレクトリに、「Procfile」という名前のファイルを作成します。

Procfile

web: bundle exec puma -C config/puma.rb
webpacker: ./bin/webpack-dev-server

次のコマンドで、すべてのプロセスを一度に起動させることができます。

$ bundle exec foreman start

ブラウザにて次のURLでアクセスしてみます。

http://localhost/static_pages/help

実行結果

上手くいきましたね。

追記(2021/05/17)

yarnコマンドにて必要なライブラリをインストールする際、最初次のように

$ bin/yarn add bootstrap jquery popper.js

とだけ記述していましたが、後日どうように実行したところ、BootstrapがVer.4ではなくVer.5の最新版が入り、Railsを稼働させたところ、CSSが更新されず、ログを確認すると、

:
ERROR in ./node_modules/bootstrap/dist/js/bootstrap.esm.js
Module not found: Error: Can't resolve '@popperjs/core' in '/opt/sample_app/node_modules/bootstrap/dist/js'
:

とエラーが出力されていました。色々確認してみたところ、@popperjs/core もyarnで入れておかなければならなかったようです。最終的に作成された package.json の中身がこちら

{
  "name": "sample_app",
  "private": true,
  "dependencies": {
    "@popperjs/core": "^2.9.2",
    "@rails/webpacker": "5.2.1",
    "bootstrap": "^5.0.0",
    "jquery": "^3.6.0",
    "popper.js": "^1.16.1",
    "rails-ujs": "^5.2.6",
    "yarn": "^1.22.10"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.11.0"
  }
}

参考にさせていただいたサイト

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中