自作のRails製Webサービスの短歌投稿サイトUtakataにJSフレームワークを入れたいと思って、当初はVue.jsを検討していたけれど、SPA的なものをやろうとすると既存コードを全面的に書き換えねばならず*1、限られたプライベートの時間で行う趣味の開発で対応するには無理があるのではという感触があった。
困って会社のエンジニアに相談したところ、Railsの生みの親のDHHがCTOを務めるBasecampが開発したというStimulusを紹介してくれた。これを試してみたら予想以上に簡単に既存のRailsアプリに取り込めたので、導入方法と簡単な使用例を書いてみたい。
既存のRailsアプリにStimulusを導入する
yarnのインストール
https://yarnpkg.com/lang/ja/docs/install/#mac-stable
上掲URLを参考にして、webpacker で使用する yarn(JavaScriptのパッケージマネジャー)をインストールする。
私のMacの環境では、Homebrewでインストールし、
$ brew install yarn
.bash_profile
にパスを通した。
export PATH="$PATH:/opt/yarn-[version]/bin"
webpackerのインストール
gem 'webpacker'
をGemfile
に記述し、
$ bundle install
し、gemがインストールされたら、
$ rails webpacker:install
を実行する。
Stimulusの導入
$ rails webpacker:install:stimulus
を実行する。
app/javascript/packs/application.js:
そうすると、上掲のようなファイルが自動で作成されるので、<%= javascript_pack_tag 'application' %>
をapp/views/layouts/application.html.erb
のheadタグ内に追加する。
これでもう開発の準備が整った。環境構築に手間取らずにすぐに開発に取り組めるのは本当にありがたい。
簡単な使用例 ―フォームの入力内容をリアルタイムに別の領域に表示する―
短歌投稿サイトUtakataには、投稿画面でフォームの入力内容を縦書きプレビューする機能がjQueryで実装されていたけれど、それをStimulusで書き換えてみた。説明のため実際のコードを一部簡略化して紹介したい。
app/views/posts/new.html.erb:
app/javascript/controllers/post_controllers.js:
たったこれだけで、フォームの入力内容をリアルタイムに表示する機能ができた。
data-controller
:controller名を指定するdata-target
:操作したい要素を指名する(controller.target
の形式)data-action
:イベントと起動するメソッド名を指定する(event->contoroller#method
の形式)
この3つを指定するだけで基本的な操作はサクサク書けそうだ。
参考情報その1 ―jQueryで書いた場合―
app/views/posts/new.html.erb:
正直これだけなら大差ないけれど、より複雑な処理を追加した場合に可読性やメンテナンス性、書きやすさ等に差がついて来ると思われる。
参考情報その2 -Herokuにデプロイする-
デプロイする前に下記のコマンドを実行する必要がある。
$ heroku buildpacks:clear $ heroku buildpacks:set heroku/nodejs $ heroku buildpacks:add heroku/ruby
Stimulusのメリットまとめ
- 簡単に導入できて簡単に使える
- turbolinksに対応していてRailsとの相性がバッチリ
- 本格的なSPA設計の手間を省きつつSPAライクなWebサービスを手軽に開発できる
- (特にStimulusの機能という訳ではないが)ES2015(ES6)以降のJavaScriptで書ける
参考記事
https://stimulusjs.org/reference/controllers
公式リファレンス。他のメジャーなJSフレームワークのリファレンスと比べると極めて簡素な章立てで、短時間で全容を把握することができる。
Vue.jsの導入記事だけれど、共通点が多くて参考になった。
↓その他、Stimulusについての興味深い情報が紹介されている記事。
*1:2018/11/19追記:このVue.jsの理解は怪しいという指摘をブコメでいただいた。 http://b.hatena.ne.jp/entry/374217143/comment/Chinosoko
*2:2018/11/23追記