Rails
bootstrap
font-awesome
webpack

Rails 5.1を使うならSprocketsは捨ててwebpackを使おう


やりたいこと


  • es6を使う。coffee scriptとはサヨナラ〜

  • bootstrapを使う。

  • bootstrap datetimepickerを使う。(追記)

  • font-awesomeを使う。

  • webpackでjs、css(scss、sass)ファイルを管理する。

bootstrapはjqueryに依存しているので、jqueryも設置します。

jqueryに依存してないbootstrap.nativeもあるが、既存の資産でjqueryを使うところが多いので、しばらくはjqueryとes6を共存した方がいいと思いました。

作業者がjqueryには慣れているが、es6には慣れてないことも1つの理由です。


bootstrap datetimepicker(追記:2017年12月20日)

bootstrap datetimepickerを使う場合は、Eonasdanのbootstrap datetimepickerではなくこれをforkしてbootstrap4用に直したbootstrap4-datetimepickerを使います。

% yarn add bootstrap4-datetimepicker

そして、application.jsやapplication.cssに追加します。


app/javascript/packs/application.js

... snip ...

import 'bootstrap/dist/js/bootstrap'
import 'moment/moment'
import 'bootstrap4-datetimepicker/src/js/bootstrap-datetimepicker'
import 'moment/locale/ja'

Eonasdanのbootstrap datetimepickerはbootstrap3に合わせたものでbootstrap4で使うとカレンダーは表示されませんでした。時間設定の部分は表示されます。

moment/locale/jaはカレンダーを日本語化してくれるものです。


app/javascript/stylesheets/application.css

... snip ...

@import '~bootstrap4-datetimepicker/build/css/bootstrap-datetimepicker';

jsとcssを読み込む経路が異なります。気をつけてください。


rails-ujs(追記:2017年12月20日)

link_toでmethod: :deleteが効かない場合があります。

ruby on rails 5.0まではjqueryに依存していてこれはjquery-ujsで処理してくれるものでしたが、5.1以降ではもうjqueryに依存していないので、純粋なjavascriptで書いたrails-ujsを使います。

% yarn add rails-ujs

application.jsにも追加します。


app/javascript/packs/application.js

... snip ...

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


プロジェクトの生成

% rails new sample -B -C -S -T --skip-coffee --skip-turbolinks --webpack -d mysql

オプションの説明はrailsだけを叩くと表示されるので、簡単に説明します。

-Bはプロジェクト生成と共にbundle installすることをスキップします。

-CはAction Cableをスキップします。

-SはSprocketsをスキップします。

-Tはminitestをスキップします。私はRSpecの方なので、スキップしますが、minitestが良いならスルーしてください。

--skip-coffeeはcoffee scriptをスキップします。es6を使います。

--skip-turbolinksはturbolinksをスキップします。最初から使ったことないです。

--webpackはSprocketsの代わりにwebpackを使います。

-d mysqlはデータベースとしてmysql(mariadb)を使います。


ライブラリの設置


Gemfile

group :development do

... snip ...
gem 'pry-rails'
gem 'annotation'
gem 'foreman'
end

pry-railsとannotationはあった方がいいですね。

webpackを使う場合、railsのアプリケーションサーバーだけではなくwebpack-dev-serverなども起動しなければなりません。

開発環境でそれぞれ起動することは面倒なので、一緒に起動するためにforemanを使います。個人的には5年ぶりに使いますが、まだ残されていました。

この以外にも開発に役に立つgemはもっとありますが、この記事では「やりたいこと」に集中したいと思うので、この位で始めます。

% cd sample

% bundle install --path vendor/bundle

私はrbenvとrbenv-gemsetを使っていますが、開発環境ではvendor/bundleにgemを設置しています。

多数のrailsバージョンやgemを設置することが多く、一種の習慣みたいになりました。

vimとctagsでomni補完機能を使っていてGemfile.tagsのファイルサイズを最小化するためです。

プロジェクトごとに使っているgemが異なるので、管理的な面でもこうした方がいいです。

vendor/bundleは容量が大きくなりやすいので、バージョン管理の対象外にしましょう。

次はwebpackerを設置します。webpackerはwebpackをrailsで利用するために作られました。

これからjsライブラリの管理にはwebpackを使います。

% rails webpacker:install

npmの代わりにyarnを利用してbootstrapとfont-awesome、bootstrapの依存パッケージであるjqueryとtether、popper.jsなどを設置します。

bootstrapの場合、バージョンを明示しないとbetaバージョンが設置されますが、色々と異なる部分がありましてややこしくなるので、alphaバージョンの最新バージョンを設置します。

% yarn add bootstrap@4.0.0-alpha.6 font-awesome jquery tether popper.js


設定

Sprocketsを使う場合はAsset pipelineを使う時と同じ手順なので、assetsの配下でjsやcssを管理しますが、webpackの場合はjavascriptの配下で管理することになります。

app

├── assets
│   ├── config
│   │   └── manifest.js
│   ├── images
│   ├── javascripts
│   │   └── application.js
│   └── stylesheets
│   └── application.css
├── javascript
│   ├── packs
│   │   └── application.js
│   └── stylesheets
│   └── application.scss

「app/javascript/stylesheets」は私が改めて追加したことなので、好みのディレクトリ名で作って使ってください。


app/javascript/stylesheets/application.scss

@import '~bootstrap/dist/css/bootstrap';

$fa-font-path: "~font-awesome/fonts";
@import '~font-awesome/scss/font-awesome';

「$fa-font-path: "~font-awesome/fonts";」がない場合、fontを見つかりませんというエラーが表示されます。

githubのwebpackerのissuesで見つけました。

https://github.com/rails/webpacker/issues/619

次はapplication.jsです。


app/javascript/packs/application.js

/* eslint no-console:0 */

// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb

console.log('Hello World from Webpacker')
import 'stylesheets/application'
import 'bootstrap/dist/js/bootstrap'


webpackの場合は「webpack.config.js」設定ファイルを使っていますが、webpackerでは「config/webpack/environment.js」になります。

環境ごとにdevelopment.js、test.js、production.jsファイルが用意されていますが、これらのファイルはenvironment.jsファイルを読み込みます。


config/webpack/environment.js

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

const webpack = require('webpack')

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

module.exports = environment


$やjQueryなどよく使われるaliasを全部指定する必要があります。

Tetherの場合も同様です。

webpackの処理によるoutputはapplication.jsとapplication.cssです。

これらのoutputでレイアウトファイルを修正しましょう。


app/views/layouts/application.html.erb

<!DOCTYPE html>

<html>
<head>
<title>Sample</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<%= csrf_meta_tags %>

<%= stylesheet_pack_tag 'application', media: 'all' %>
<%= javascript_pack_tag 'application' %>
</head>

<body>
<%= yield %>
</body>
</html>


stylesheet_link_tagとjavascript_include_tagの代わりにstylesheet_pack_tagとjavascript_pack_tagを使っていることに注目してください。


起動

railsのアプリケーションサーバーとwebpack-dev-serverをまとめて起動するためにforemanを利用します。

foremanを利用するためには設定ファイルが必要で、デフォルトの設定ファイルの名前がProcfileです。

他の名前にする場合は、オプションで指定する必要があります。


Procfile

rails: rails s -p 3000

webpack: bin/webpack-dev-server

次のコマンドで実行すると、puma(railsのアプリケーションサーバー)とwebpack-dev-serverが一緒に起動されます。

% bundle exec foreman start

因みに、以下のようにする場合は起動できませんでした。

% bundle binstubs foreman

% bin/foreman start


確認

bootstrapがちゃんと表示されるのか確認してみましょう。

まず適当なcontrollerとviewファイルを作ります。

% rails g controller hello world

generatorで生成したworld.html.erbを開いて、下記のように入力してください。


app/views/hello/world.html.erb

<div class='container-fluid'>

<div class='row'>
<i class="fa fa-exclamation-triangle fa-3x"></i>
</div>
<div class="alert alert-success" role="alert">
<strong>Well done!</strong> You successfully read this important alert message.
</div>
<div class="alert alert-info" role="alert">
<strong>Heads up!</strong> This alert needs your attention, but it's not super important.
</div>
<div class="alert alert-warning" role="alert">
<strong>Warning!</strong> Better check yourself, you're not looking too good.
</div>
<div class="alert alert-danger" role="alert">
<strong>Oh snap!</strong> Change a few things up and try submitting again.
</div>

<div class='row'>
<i class="fa fa-list fa-3x"></i>
</div>
<!-- Provides extra visual weight and identifies the primary action in a set of buttons -->
<button type="button" class="btn btn-primary">Primary</button>

<!-- Secondary, outline button -->
<button type="button" class="btn btn-secondary">Secondary</button>

<!-- Indicates a successful or positive action -->
<button type="button" class="btn btn-success">Success</button>

<!-- Contextual button for informational alert messages -->
<button type="button" class="btn btn-info">Info</button>

<!-- Indicates caution should be taken with this action -->
<button type="button" class="btn btn-warning">Warning</button>

<!-- Indicates a dangerous or potentially negative action -->
<button type="button" class="btn btn-danger">Danger</button>

<!-- Deemphasize a button by making it look like a link while maintaining button behavior -->
<button type="button" class="btn btn-link">Link</button>
</div>


タイピングする必要はありません。

bootstrapのサイトでexampleが用意されているので、コピペしてください。

スクリーンショット 2017-12-14 15.56.30.png

font-awesomeのサイトにもexampleが用意されているので、ご参照ください。

http://fontawesome.io/icons/

綺麗に表示されました。

スクリーンショット 2017-12-14 16.41.23.png

画面サイズを変更して見ましょう。

スクリーンショット 2017-12-14 16.41.55.png

Developer Toolsのconsoleにてエラーがないことも確認してください。

スクリーンショット 2017-12-14 15.57.37.png