Railsのフロントエンドのノウハウ#2: JavaScript編(翻訳)

概要

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

記事を2本に分割しました。日本語タイトルは内容に即したものにしています。

Railsのフロントエンドのノウハウ#2: JavaScript編(翻訳)

RailsにおけるJavaScriptについての洞察

Rails開発者の多くは、JavaScriptがうまく動作しない場合の振る舞いについてなかなか把握できないことがあります。しかもRailsの場合、JavaScriptのいくつかの振る舞いについても特定の方法で変更されます。

TurbolinksやSpringを嫌う人が多いという話を聞いたことがあるかと思います。私はたまたまどちらの技術も好きですが、これらの動作を理解しておかないと、百戦錬磨のJavaScript開発者ですら頭を抱えるような事態になるかもしれません。

これら2つのライブラリについて簡単にご説明いたします。

Turbolinksは、ページの読み込みを高速化したり、フォームや一部のCRUD操作で使えるUJS機能を素早く読み込めるようにしたりします。Turbolinksを導入するとJavaScriptの「page ready hook」が変更されます。このフックは"turbolinks:load"を行うのに使われます。Turbolinksを使っていると、標準のJavaScript「page ready hook」でいくつかの問題が生じます。

Springはアプリのコードを対象とするプリローダであり、Rubyコードとフロントエンドのアセットの両方について読み込んだものを自身のプロセスにキャッシュし、次回のリクエストで使えるようにします。JavaScriptのエラーハンドリングについての知識がないと、解決に多大な日数を要するバグを追いかけるはめになるかもしれません。Springは、最初のページ読み込みから最初に操作を行った「後で」これらを機能させるためです。したがって、サイトが読み込まれるときに一部が動かないことがあっても、リンクをクリックすると動き出します。

Springの役割を詳しく調べる前に、JavaScriptがひどいコードをどのように扱うかを最初に見てみることにしましょう。

Javascriptが何らかのひどいコードに遭遇したり、評価すべきでないものを評価したりすると、JavaScriptは現在の作業を停止して、何か問題が生じていることをブラウザのコンソールに出力します。すなわち、アプリにJavaScriptの何か新しいライブラリを導入し、そこにひどいコードがあると、それ以降のコードはライブラリであろうと自分のコードであろうと動かなくなります。これはJavaScriptの通常の振る舞いであり、ひどいコードを実行する時点でコードの事項を停止するためのものです。

しかしSpringを追加した場合、アセットがキャッシュに(Turbolinksもろとも)読み込まれてひどいJavaScriptコードが評価された後、SpringはJavaScriptコードをの実行を回避しません。つまり最初のページを読み込むと、SpringやTurbolinksがアセットやライブラリをキャッシュしてより高速読み込みに備えるのです。

最初のリンクを操作してたどるまではまったく問題ないように見えることがあります。というのも、SpringはひどいJavaScriptコードの後でよいJavaScriptコードを生成するためです。最初のページ読み込みでJavaScriptの機能が不要であれば、何か問題が起きているかどうかをコンソールで確認しない限り、何も問題が起きていないように見えます。そして(productionで)コードを公開すると、「ローカルではちゃんと動く」にもかかわらず、サイトの一部がまったく突然にダウンして期待どおりに動かなくなります。

この手の「ローカルと同じ結果をproduction環境で得られない」問題のせいで、多くの人が髪の毛をかきむしりまくっています。

ここでJavaScript開発者にひとつ耳寄りな小技をご紹介します。アプリに新しいライブラリなり新しいJavaScriptコードなりを追加する場合は、常にその末尾にconsole.log("Seems okay ¯\_(ツ)_/¯");を追加しておくというものです。こうしておけばブラウザコンソールでコードがちゃんと動いていることを確認できるようになります。コンソールログにこれが出力されていれば、自分のJavaScriptコードが読み込み中に「ひどいコード」として評価されていないことがわかります。

私はBootstrap 4ライブラリをいろんなバージョンで試しましたが、その中に「ひどい」と評価されるJavaScriptコードも含まれていたことがありました。しかも私はそれを、アプリで必要とされる他のJavaScriptライブラリより前に配置していたのです。おかげで最初のページ読み込みでJavaScript関連のコードが軒並み動かず、ページをリフレッシュしたり何らかのリンク操作を行ったりした後でどうやら動くという事態になりました。私がBootstrap 4ライブラリをTurbolinksより前に置いていたために、コードの振る舞いがそのようになってしまったのです。Springがあっても最初のページ読み込みで問題なく動くように、CoffeeScriptでささやかなハックを仕込みました。

if !Turbolinks?
  location.reload

Turbolinks.dispatch("turbolinks:load")

これはローカル環境では問題なく動作したのですが、productionでは動きませんでした。Rails開発者は、"turbolinks:load"トリガがWebサイトの最初のページ読み込みで当初呼び出されないという問題をちょくちょく踏んでいます。

Turbolinks.dispatch("turbolinks:load")は、JavaScriptのその部分のコードが評価された後できるだけ早い段階でこのWebフックを即座にトリガするための方法です。これは、最初のページ読み込みの時点でJavaScriptやCoffeeScriptのスクリプトをトリガしたい方にとって役に立ちます。

ページ読み込み時にCoffeeScriptをトリガする場合、ちょっと一手間かける必要があります。というのも、CoffeeScriptコードはすべて1つの関数内にラップされていて、スコープが保護されているためです。Turbolinks.dispatch("turoblinks:load")メソッドを使うことで、このあたりのややこしさが少しマシになります。

Springを使っている場合に有用なハックはif !Turbolinks?; location.reloadしかありません。これが必要になるのは、JavaScriptの何らかの「ひどいコード」が評価されるdevelopment環境でJavaScriptコードを読み込む場合だけです。これを使うのではなく、先ほどのconsole.logテクニックを用いてJavaScriptコードの実行に成功したかどうかを確認しましょう。その後で、「ひどいコード」として評価される状況を改善しましょう。

最後に

Capybaraは、フロントエンドのエクスペリエンス全体のテストをシンプルに書ける素晴らしいライブラリです。RailsはCapybaraテストの大半を代わりに生成してくれるので、それを読んで学べば同じようなテストを今後も書き続けられます。面倒な設定はRailsが肩代わりしてくれるので、フロントエンドのテストを始めるのがとても簡単になります。

Rails 5のもうひとつうれしい点は、システムテストで例外が発生すると、ブラウザウィンドウの内容のスクリーンショットをtmp/screenshots/に自動保存してくれるようになったことです。画面とスクリーンショットを比較してテストの問題を特定しやすくなりました。

Railsのライブラリと併用した場合のJavaScriptの振る舞いを理解しておけば、地雷を避けてデバッグ時間を大幅に節約できるようになります。JavaScriptの振る舞いを正しく理解すれば、これまでうんざりさせられていた強力なツールたちをさらに使いこなせるようになります。TurbolinksSpringは、効用をと利用法を理解しておけば素晴らしいツールになるのです。

おかげで近頃はRails開発者でよかったと思えます。フロントエンドテストで大いに楽しみましょう!

Twitter: x“Rails Frontend Testing with JavaScript Insights” via @6ftdan

ツイートより

関連記事

Rails 5.1以降のシステムテストをRSpecで実行する(翻訳)

Rails 5: WebSocketのマルチセッションをMiniTestとシステムテストでテストする(翻訳)

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

この記事の著者

hachi8833

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

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ