Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。画像はすべて元記事からの引用です。
原文の目次は省略しました。原文の乱れは訳文で修正してあります。

Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)

👋皆さんこんにちは。本記事では私がRubyやRuby on Railsを学んだ一環として、ドキュメントに書かれていないことを全部盛りしました。RubyやRailsのエコシステムは初めてなので、皆さまからのフィードバックを心よりお待ちしております。お気づきの点がありましたら元記事にコメントをどうぞ。

Ruby on Railsのためのチュートリアルの大半はAPIの利用方法にフォーカスしていますが、これは理にかなっています(例: Rails をはじめよう - Rails ガイド)。

しかしrails new blogしてコントローラを編集し、git push herokuを何度かやってみるまではいいとして、そこから先はどうすればいいのでしょうか?私はその先に進みたかったので、以下についてのベストプラクティスが欲しかったのです。

  • 開発用セットアップ
  • RubyやRuby on Railsのコードエディタの設定
  • アセットの設定やオートリロード(Webpacker)
  • 再現可能なビルド、安全な環境
  • もう少し学べる書籍をいくつか

自分はこれらの点について相当じたばたしました。というのもオンライン上での議論がほとんど見当たらないからです。つまりこれらの点については「実際に体当たりで使って学ぶのが普通」ということです。

私はRailsアプリケーションを学んでデプロイするときに、自分がハマった小さなワナや、上述の課題をすべて解決するために追加しなければならなかったコード片を、以下のようにすべてREADMEファイルに盛り込むところから始めました。

ある時点からこのリストはどんどん膨れ上がってきたので、次にRailsアプリケーションを始めなければならなくなったときに「自分が使える資料にいつでも手が届く」状態にすべく書き直す必要を感じました。

このメモ書きを公開することで私の知見を共有し、(願わくば)皆さまのお役に立てられればと思います。

エディタとVS Codeのセットアップ

私はJavaScript開発者だったので、それもあってVisual Studio Codeを使っています。JetBrainsの「Ruby 2019 State of the developer ecosystem」↓を見ると、RubyMineのようにもっとよさげなエディタがあるようですね。お使いの方はご感想を私の記事のコメントまでお知らせください。

エディタの設定

シンプルな割には忘れがちですが、VS CodeはEditorConfigをサポートしています。プロジェクトのルートディレクトリに.editorconfigファイルを作成しておけば、VS Codeを使っているどのユーザーでもインデント設定や改行コードをマスター設定にできます(訳注: VS Codeの場合はEditorConfig拡張のインストールが必要です)。

最小限の.editorconfigファイルを作成します。

# editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

これでプロジェクトの他のコントリビューターもEditorConfigを使えるようになります。

VS Codeの拡張

VS CodeでのRailsやRubyを気持ちよく編集するために、以下の拡張を使っています。

これらの拡張を楽にインストールできるよう以下のフォルダとファイルを作成します。これでRailsプロジェクトのメンバー全員に拡張がおすすめされ、インストールをいちいち依頼しなくてもよくなります。

  • .vscode/extensions.json:
{
  "recommendations": [
    "rebornix.Ruby",
    "kaiwood.endwise",
    "vortizhe.simple-ruby-erb",
    "bung87.rails",
    "ninoseki.vscode-gem-lens"
  ]
}

これで、プロジェクトをVS Codeで開けばこれらのチーム用拡張をインストールするようヒントが表示されます。

VS Codeの設定

さらに、RubyやRailsプロジェクトの開発効率を最大限に高めるため、以下のプロジェクト設定を使っています。

  • .vscode/settings.json
{
  "ruby.useLanguageServer": true,
  "ruby.useBundler": true,
  "ruby.intellisense": "rubyLocate",
  "ruby.format": "rufo",
  "files.associations": {
    "*.html.erb": "html"
  },
  "[html]": {
    "editor.defaultFormatter": "vscode.html-language-features"
  },
  "editor.formatOnSave": true
}

これで、.rbファイルや.erb.htmlをエディタで保存するとRubyやRailsのコードが自動的にフォーマットされるようになります。

これは現時点で私が見出したベストのセットアップです。最終的にはPrettierとそれ用のRubyプラグインがベストなオプションになるかと思いますが、記事執筆時点では.erb.htmlのフォーマットがサポートされていません(#371)。

  • フォーマットがよく効くように以下をGemfileに追加しておきます。
group :development do
  # [...]
  gem 'rufo', '~> 0.7.0', require: false
end

これで、.rbファイルや.erb.htmlファイルを保存するたびに自動フォーマットされるようになります。

Webpackerの使い方

このセクションでは[S]CSSについて説明します。この説明はすべてのSCSSファイルとCSSファイルに適用できます。Webpackerは複数のフォーマットをサポートしています(webpacker/css.md at master · rails/webpacker)。

当初、Webpackerについて以下の理由で混乱しました。

Rails 6からRailsアプリケーションにWebpackが同梱されて組み込めるようになりました。これはWebpacker経由で行われます。Webpackerは、事前に設定されたWebpackにビューヘルパーを加えたものを提供することで、生成されたアセット(JavaScriptや[S]CSSファイルなど)を簡単に対応付けられるようにします。

2019年11月の時点では、デフォルトのRailsアプリケーションのerbテンプレートファイルには以下が含まれています。

  • app/views/layout/application.erb.html
  <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %>
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

2行目は、app/javascript/packs/application.jsというエントリポイントから生成されたコンパイル済みJavaScriptファイルパスをWebpackerから取得します。

しかし1行目は、現在のアセットからのファイル生成を片っ端からアセットパイプラインに指示します。

このようにシステムが二重になっていることで混乱しました。何か理由はあるのかもしれませんが、ここではWebpackerのみを用いてアセットを生成するよう修正しましょう。

[S]CSSファイルをWebpackerで扱う

[S]CSSファイルをWebpackerで扱う(Rails 6でBootstrap 4を使うなど)には、CSSをインクルードする行を以下のように変更する必要があります。

  • app/views/layout/application.erb.html
  <%= stylesheet_pack_tag "application", media: "all", "data-turbolinks-track": "reload" %>

これにより、「application」という名前のパックについてWebpackerがスタイルシートアセットの正しいURLを提供するようになります。現在のメインのパックのファイル名をアプリケーションが実際に参照するときの名前はapp/javascript/packs/application.jsです。

stylesheet_link_tagstylesheet_pack_tagに変更されていることにお気づきでしょうか。

次に、メインのSCSSファイルを作成します(実際のファイル名や置き場所は何でも構いません)。

  • app/javascript/src/style.scss
@import "~bootstrap/scss/bootstrap"; // Bootstrapを使う予定なら

次にJavaScriptのimport文を書きます。

  • app/javascript/packs/application.js
// [...]
import "../src/style.scss";

このスタイルシートは、実際にはこのJavaScriptファイルでは読み込まれません。この記述は、単にWebpackにコンパイルを指示して、Railsアプリケーションのテンプレートでrequireのパスを指定できるようにするためのものです。

Rails 6でBootstrap 4を使う

先ほどの最後の部分を@import "~bootstrap/scss/bootstrap";に変えて動かすには、Bootstrapをインストールする必要があります。ただしGemfileに書くのではなく、Yarnを使います。~を付けた~bootstrapという記述は、node_modules/bootstrap/...以下からファイルを探すようWebpackに指示するためのものです。それでは追加しましょう。

  • ターミナルで以下を実行します
yarn add bootstrap

BootstrapのJavaScriptを動かすには、JavaScriptの依存関係もインストールする必要があります。

  • ターミナルで以下を実行します
yarn add jquery popper.js

インストールしたファイルをJavaScriptアプリケーションでrequireします。

  • app/javascript/packs/application.js
require("jquery");
require("bootstrap");

[S]CSSやJavaScriptファイルのオートリロード

私にとってWebpackの強みのひとつといえばオートリロード機能ですが、デフォルトのRails 6では無効になっています。オートリロードでは、developmentモードですべてのページの更新が常に読み込まれます。オートリロードを有効にするにはwebpack-dev-serverを使う必要があります。ありがたいことに、webpack-dev-serverは新しいRails 6アプリケーションには既に同梱されているので、これをRailsサーバーと一緒に起動するだけで使えます。

  • ターミナルで以下を実行します
./bin/webpack-dev-server

私はdevelopment用サーバーでは1つのコマンドで実行できるようにするのが好みです。rails server./bin/webpack-dev-serverをパラレルに起動できれば理想的です。昨今ならProcfile.devhivemindで今風にやると楽にできそうです。

hivemindは基本的にforemanですが、「よくできています」。私はインターネット上のツールを信頼しているのでこれを使っています。必要な作業は以下のとおりです。

  • Procfile.devを作成します
web: rails server
webpacker:  ./bin/webpack-dev-server
  • .envを作成または更新します
HIVEMIND_PROCFILE=Procfile.dev

これで、rails serverrails sをローカルで起動する代わりに、以下のようにhivemindでやれます。

  • ターミナルで以下を実行します
brew install hivemind
hivemind

おめでとう、これでhttp://localhost:5000にアクセスすればWebサーバーが実行されます。組み込みのオートリロードも高速です。


1つ問題があったのは、WebpackerがYarn integrityチェックを頻繁に行うことでdevelopment環境で遅くなる点でした。私のYarn依存関係は最新かつ常に同じに保たれていることを確認してあるので(次の「再現可能な環境」を参照)、Yarn integrityは無効にしました。

Webpackerを使えばいろんなことができるのですが、メインのRailsドキュメントには情報がありません。Webpackerについて学ぶには以下がおすすめです。私はWebpackerについて必要なこと(特にフォルダ構造webpack-dev-server、 CSS)はすべてここで学びました。

訳注: 以下の記事も参考にどうぞ

【保存版】Rails 5 Webpacker公式ドキュメントの歩き方+追加情報

自動テストとデスクトップ通知

私はJavaScript方面から来たので、JestというJavaScript例外テストツールを使っていました。これは今やJavaScriptアプリケーションのテストでは定番です(他のものを使っても別に構いません)が、RubyやRuby on Railsのテストにはさまざまな方法があります。ほとんどの場合自分に必要なのは、テストの自動実行と、テストがパスまたは失敗した場合のデスクトップ通知です。

テストの自動実行ツールは皆さんも既にネットでいろいろ見つけていることでしょう。たとえば「Automating Minitest in Rails 6」はよい出発点です。

でも自分は以下のようなデスクトップ通知がどうしても必要欲しいのです。

これならエディタを切り替えずにテストの状態をチェックできます。

最も簡単に通知を実現する方法はterminal-notifierとterminal-notifier-guardを使うことだとわかってきました。

必要な作業は、Gemfileのdevelopmentグループとtestグループに以下を追加することだけです。

gem 'terminal-notifier', '2.0.0'
gem 'terminal-notifier-guard', '1.7.0'

これでbundleを実行すれば、guardがこれらのgemを自動検出してナイスな通知を表示してくれます。


本記事では当初Growlを推していましたが、理由はterminal-notifierがその時点でうまく動かなかったためでした。しかしコメントで再挑戦を勧められて、今度はうまくいきました。

もちろんGrowlでも問題なくやれますので、既にお使いの方はそのままどうぞ。

再現可能な環境

私はNode.jsやJavaScript方面の出身なので、「再現可能な環境」に必要な正しい習慣を身に付けてきました。

再現可能な環境(reproducible environments)についてご存知ですか?Travis CIで動かそうがHerokuで動かそうが、はたまたMacbookで動かそうが、常に同一の依存関係、プラットフォーム、言語バージョンで実行するべきです。MacbookではYarn 1.9にRuby 2.6にNode.js 12.3.4という依存関係で動かしつつ、HerokuではYarn 1.1にRuby 2.4にNode.js 12.1.0という依存関係で動かしたいことなどありえません。理想は、どのバージョンについてもインストールやメンテナンスやアップグレードを簡単に行えることです。

bundler、Rails、Ruby、Node.js、Yarnもこれに該当します。次のセクションで方法を説明します。

再現可能な環境: Ruby編

  1. rbenvでさまざまなバージョンのRubyを簡単にインストールできるようにする
  2. .ruby-versionファイルでRubyバージョンを全プラットフォームで強制的に設定する
  3. Gemfileを変更して、bundler実行時にRubyのバージョンを強制的に設定する
  4. 依存関係のバージョンを抽出する(いわゆる依存関係のピニング(pinning)

1. rbenvをインストールします

2. .ruby-versionファイルを以下の内容で作成します

2.6.5

3. GemfileのRubyバージョンを、Bundlerで使うRubyバージョンと合わせます

ruby '2.6.5'

4. GemfileのRuby依存関係で正確なバージョンを指定します

gem 'webpacker', '~> 4.0'

具体的には、上を以下のように変更します。

gem 'webpacker', '4.2.0'

ありがたいことにVS Codeにインストールした拡張のおかげで、Ruby依存関係の最新版を簡単に確認できます。Gemfileの該当行にマウスオーバーするだけで以下のように表示されます。

依存関係のピニングはデリケートな問題です。ありがたいことに、Gemfileやbundlerでバージョンを指定するときのさまざまな戦略のメリットやデメリットについてうまくまとめた良記事がありますのでご覧ください。

再現可能な環境: Node.jsとYarn編

RailsがWebpackに依存するようになったことで、Node.jsとYarnにも依存するようになりました。これは驚きですね。つまり、それぞれのバイナリで使うバージョンも正確に指定する必要があります。

以下の要領で進めます。

  1. インストールして使う.Node.jsのバージョンは.nvmrcファイルで指定する。HerokuもTravis CIも、利用するNode.jsのバージョンをこれで推測する。
  2. インストールして使うYarnのバージョンはYarnポリシーで指定する。これはYarn 1.13.0以降であればどこでも使えます。Yarn policyは誕生して1年ですが、安全です。
  3. (Webpacker経由のWebpackなどのように)Node.jsスクリプトを実行するYarnやNode.jsのバージョンは、package.jsonのenginesフィールドで検証される。
  4. 依存関係のバージョンを抽出する

1. nvmをインストールします

続いて以下の内容で.nvmrcファイルを作成します。

12.13.1

本記事をお読みの方は、Node.jsの最新バージョンをNode.jsサイトで確認してお使いください。

2. ターミナルで以下のYarnポリシーを設定します

yarn policies set-version 1.19.1

これでYarn 1.19.1がダウンロードされて.yarnrcファイルが作成され、Yarn 1.19.1を使うようYarnのバイナリに指示されます。いいですね〜❤️。繰り返しますが、本記事をお読みの方は、Yarnの最新バージョンをYarnサイトで確認してお使いください。

最新のLTS版Node.jsも利用できます。

3. package.jsonを以下のように更新します

{
  // [...],
  "engines": {
    "node": "12.13.1",
    "yarn": "1.19.1"
  }
}

4. package.jsonの依存関係をすべて正確なバージョンにピニングします

"@rails/webpacker": "^4.2.0",

具体的には、上のバージョンを以下のように変更します。

"@rails/webpacker": "4.2.0",

次のセクションでは、依存関係を実際にピニングできるツールについて説明します。

これでマスターとなるNode.jsとYarnの環境ができました!

依存関係の自動アップデート

ご覧のように、再現可能な環境づくりの一環として、私はいついかなるときでも依存関係のバージョンはピンポイントで指定しています。なにかのはずみで、環境やプラットフォームの依存関係バージョンがちょっと違ってしまうという事態になって嬉しい人などいません。そんなことになれば時間をドブに捨てるはめになります。

もちろん、Gemfile.lockやyarn.lockのようなロックファイルのおかげで大半の問題は解決できますが、それだけでは不十分です。ロックファイルを使っても失敗する可能性がある(参考)というだけでなく、私はいついかなる場合でも現在の直接的な依存関係も正確に知っておかないと気が済まないのです。今使える機能や今あるバグの両方について知りたいときに、package.jsonやGemfileの”~2.x”みたいなバージョン表記の背後で何が起きているのかを解明するのに謎のコマンドを調べまくるはめになりたくないのです。

しかし、たまには依存関係のアップグレードもやりたいのです。それも一切つらい目に遭わずに。JavaScriptやRubyの依存関係の自動アップデートについては、Renovateを一度チェックしてみることをおすすめします。

Herokuと、Yarnインストールかぶり現象

Herokuにデプロイする場合、Herokuの以下のガイドがよくできているので、これに従いましょう。

私の場合、Herokuにデプロイ中にYarnインストールが複数回トリガされるというおかしな動作に遭遇しました。ひとつはHerokuでpackage.jsonファイルが検出されたとき、もうひとつはWebpackerでアセットをバンドルしているときです。これでは困るので、これらのタスクを以下のように分割したいと思いました。

  1. Yarn依存関係をインストール
  2. Ruby依存関係をインストール
  3. アセットのコンパイル

タスク1.と2.はHerokuで自動検出されますが、自分で順序を指定することもできます。これを行うには、buildpacksとbuildpacksの順序を自分で設定し、最初にNode.jsのを、次にRubyのを使うようにしなければなりません。

  • ターミナルで以下を実行します
heroku buildpacks:clear
heroku buildpacks:add heroku/nodejs
heroku buildpacks:add heroku/ruby

今度はWebpackerによるYarnインストールをすべて無効にしなければなりません。Rakefileに以下を追加します。

Rake::Task['yarn:install'].clear
namespace :yarn do
  desc "Disabling internal yarn install from Rails"
  task :install => [:environment] do
    puts "Disabling internal yarn install from Rails"
  end
end

Rake::Task['webpacker:yarn_install'].clear
namespace :webpacker do
  desc "Disabling internal yarn install from Rails"
  task :yarn_install => [:environment] do
    puts "Disabling internal yarn install from Rails"
  end
end

この問題(#744)を調べてくれたRebecca Lynn Cremonaに感謝いたします。

RubyやRailsを学ぶのに最適なリソース一覧

これについては別記事に切り出しました。

解説は以上です。

Node.jsの経験を元にRails世界に飛び込んでみましたが、全般的に楽しめました。本記事で指摘した問題がいずれ解消しますように。そのときには本記事を更新いたします。本記事で取り上げたトピックについてもっと詳しい方がいらっしゃいましたら、ぜひ元記事にコメントいただくかvincent@codeagain.comまでお知らせください。

本記事がどこかでお役に立ちましたら、他の方にもおすすめください。

お読みいただいた皆さまに感謝いたします。

おたより発掘

関連記事

Rails 6のDocker開発環境構築をEvil Martians流にやってみた

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ