Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HotwireからDHHが考えるこれからのRailsとJSの付き合い方を知る

 HotwireからDHHが考えるこれからのRailsとJSの付き合い方を知る

「iCARE Dev Meetup #18」で発表した資料です

https://icare.connpass.com/event/201662/

Shinichi Maeshima

February 17, 2021
Tweet

More Decks by Shinichi Maeshima

Other Decks in Technology

Transcript

  1. Hotwire とは? Basecamp 社製js フレームワーク Rails の作者であるDHH がCTO をしている会社 hey.com(Basecamp

    社製メールアプリケーション) を作るのに使われ ている 複数のフレームワークで構成されている 5
  2. Hotwire とは? ( 意訳) モダンなweb アプリケーションを、JSON とたくさんの JavaScript を使うことなしに、HTML を送ることで実現するアプロー

    チ Hotwire is an alternative approach to building modern web applications without using much JavaScript by sending HTML instead of JSON over the wire. “ “ 6
  3. とはいえ vue やreact と⽐べて細かいことはできない native アプリケーションも基本webview になるぞ hey.com (Basecamp 社製のメールサービス)

    くらいのものであれば Hotwire で実現できるので、そのレベルで問題ないサービスならOK 「そのレベルで問題ないサービス」は結構な割合でありそう 10
  4. Hotwire のアーキテクチャ Turbo Turbo Drive Turbo Frames Turbo Streams Turbo

    Native Stimulus Strada( 現時点で未発表なので今回は話しません) iOS やAndroid のネイティブで必要な機能(ex: カメラ) とHTML と をつなげるためのライブラリらしい 11
  5. 注意点 IE などの古いブラウザで動かすのは⼤変そう fetch API custom elements Intersection Observer API

    など、モダンブラウザでしか動かないAPI を利⽤している polyfill を使えば動きそうだけど⼤変そう IOS も12 以上( 近いうちに13 以上) が必要 13
  6. 不遇の Turbolinks リリース当時( 約7 年前) はjQuery およびjQuery プラグイン全盛 Turbolinks はjQuery

    プラグインと相性が悪いことがあった Turbolinks を使うためには⾊々わかっている必要があった 通常のページロードは最初の⼀回のみであること E2E テストで、次ページに遷移したかをちゃんと待つ必要がある form に関しては完全に対応していないこと ハマるひとが多く、デメリットが⼤きいと判断→ 基本消されるライ ブラリに 17
  7. ( 余談 ) いま Turbolinks を使っているひと はどうやって Turbo に移⾏したらいいの エイヤで頑張ると移⾏できます

    詳細はブログに書いたのでこちらを⾒てください Turbolinks からTurbo への移⾏ - おもしろweb サービス開発⽇記 19
  8. Turbo Drive による改善 form に関してもデフォルトでturbo 仕様になった form_with ヘルパメソッドはこれまでTurbolinks を意識し、デフォ ルトで

    data-remote="true" 属性がついていた Turbolinks を使っていない⼈からしたら混乱の元 Turbo がリリースされたことにより、Rails6.1 から data-remote="true" はデフォルトオフになった 20
  9. Turbo Drive の form 送信時の挙動 form 送信時は302 などのレスポンスが返るとリダイレクト、4xx や 5xx

    系が返るとレスポンスボディを差し替えて履歴はそのまま、と なった Turbolinks 時にここをちゃんとやろうとすると⼿動でSJR(Server generated javascript response) して対応する必要があった 21
  10. SJR ってなに 例えばPost のcreate アクションでバリデーションエラーが起きたら、 次のようなposts/create.js.erb をレンダリングします。 (shared/_error.html.erb にエラーメッセージ⽤の部分テンプレートが ⼊っている想定)

    document.querySelector('#error').innerHTML = "<%= j(render("shared/error", model: @post)) %>"; するとrails-ujs が↑ の内容をeval してくれるので <div id="error"></div> にエラーメッセージが表⽰されます。 22
  11. Turbo Streams Turbo のレスポンスとして、↓ のようなHTML ⽚を Content- Type=text/vnd.turbo-stream.html で返すとTurbo がいい感じに処理し

    てくれる。 <turbo-stream action="append" target="messages"> <template> <div id="message_1"> id がmessages なDOM の内部に挿⼊(append) される </div> </template> </turbo-stream> 24
  12. Turbo Streams で部分テンプレート活⽤ turbo-rails を使っていると次のように書ける turbo-stream タグやtemplate タグを⾃動で付与してレスポンスを返 す これで既存の部分テンプレートを活⽤できる!!

    def create message = Message.create!(params.require(:message).permit(:content)) render turbo_stream: turbo_stream.append(:messages, # ここがturbo-rails 提供部分 partial: "messages/message", locals: { message: message }) end end 25
  13. Turbo Streams で使える action action として使えるのは次の5 種類のみ append prepend replace

    update remove レールを敷くことで判断を楽にできるのと、SJR でセキュリティに⽳ を開けるのを防ぐことができるのがメリット 27
  14. Turbo Streams と websocket websocket(Action Cable) でも使える turbo-rails にはAction Cable

    ⽤のヘルパメソッドがあり、subscribe やbroadcast が簡単にできるようになっている 例えば新着メールが来たタイミングで⾃動的にメールが追加され る、というのが簡単にできる 詳細はturbo-rails ソースコードをみてください( 現時点でドキュメ ントにはほぼ記載がない) 28
  15. Turbo Frames turbo-frame タグ中に書かれた要素はframe として区切られる frame 内のリンクはTurbo Frames ⽤のリンクとなる( 詳しくは次⾴)

    <!-- messages/index.html.erb --> <body> <div id="navigation"> メッセージ⼀覧</div> <turbo-frame id="message_1"> <h1>Hotwire</h1> <p> いいですね</p> // ↓ をクリックすると… ? <a href="/messages/1/edit"> メッセージを編集する</a> </turbo-frame> </body> 31
  16. Turbo Frames <!-- /messages/1/edit --> <body> <h1> メッセージの編集</h1> <!-- リンク元が

    <turbo-frame id="message_1"> に含まれていれば ↓ の中⾝だけが差し替わる! それ以外のリンク元であれば ↑ のh1 タグ含めてbody 全体が差し替わる --> <turbo-frame id="message_1"> <form action="/messages/1"> <input name="message[name]" type="text" value=" メッセージタイトル"> <textarea name="message[name]"> メッセージの内容</textarea> <input type="submit"> </form> </turbo-frame> </body> 32
  17. turbo-frame タグの中だけど普通のリン クにしたいときもありますよね <!-- messages/index.html.erb --> <body> <div id="navigation"> メッセージ⼀覧</div>

    <!-- target="_top" とすると普通のTurbo のリンクとなる(body が全部書き換わる) --> <turbo-frame id="message_1" target="_top"> <h1>Hotwire</h1> <p> いいですね</p> <a href="/messages/1/edit"> メッセージを編集する</a> </turbo-frame> </body> 34
  18. Turbo Frames のもう⼀つの活⽤⽅法 src 属性をつけると、値となるURL を⾮同期でfetch する ファーストビューの時間を短縮できる Turbo Frames

    ⽅式でレスポンスを差し替える <body> <h1> ともだち⼀覧</h1> <div id="friends"> ... </div> <h2> ともだちかも?</h2> <turbo-frame id="maybe_friends" src="/maybe_friends"> </turbo-frame> </body> 36
  19. Turbo Frames でさらに遅延表⽰ loading="lazy" をつけると、その要素が画⾯に表⽰されるまでロー ドを遅延する <body> <h1> ともだち⼀覧</h1> <div

    id="friends"> ... </div> <h2> ともだちかも?</h2> <turbo-frame id="maybe_friends" src="/maybe_friends" loading="lazy"> </turbo-frame> </body> 37
  20. 42

  21. 特定のページだけで発⽕させたい js が 書きやすい // hello_controler.js import { Controller }

    from "stimulus" export default class extends Controller { connect() { // ここにdata-controller="hello" が // 表⽰されたときに実⾏したい処理を書く } } 43
  22. まとめ 未公開のStrada を除き⼀通りHotwire について説明した Hotwire は、" 最⼩限の労⼒でユーザが求めているサービスを提供す ること" に特化しているライブラリ つまりそれはRails

    と同じ⽅針をフロントエンドにも持ち込んだ、 と⾔える 少⼈数で開発するスタートアップ〜中規模なサービスに特に向い ているはず 便利なので使ってみてください! 45