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
    から
    DHH
    が考えるこれからの
    Rails

    JS
    との付き合い⽅を知る
    @willnet
    1

    View full-size slide

  2. いろんな会社で技術顧問をしつつ、空
    いた時間で
    savanna.io
    などを開発して
    います
    2

    View full-size slide

  3. savanna.io

    Hotwire
    を利⽤していま

    3

    View full-size slide

  4. 今⽇は
    Hotwire
    の話をします
    4

    View full-size slide

  5. Hotwire
    とは?
    Basecamp
    社製js
    フレームワーク
    Rails
    の作者であるDHH
    がCTO
    をしている会社
    hey.com(Basecamp
    社製メールアプリケーション)
    を作るのに使われ
    ている
    複数のフレームワークで構成されている
    5

    View full-size slide

  6. 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

    View full-size slide

  7. 今どきの
    js
    フレームワークといえば
    JSON
    を使うのがふつう?
    サーバサイドはJSON
    を返す
    フロントエンドはJSON
    を受け取る
    そこからDOM
    を構築してHTML
    をレンダリングする
    js
    ですべてを制御するのでUI
    を細かく作り込める
    7

    View full-size slide

  8. でもそれって⼤変ではないですか?
    ロジックがサーバサイドとクライアントサイド両⽅に必要になる
    クライアントは複数存在するのでそれぞれで実装を頑張らないと…
    ブラウザ
    iOS
    Android
    それぞれに専任のエンジニアが必要
    8

    View full-size slide

  9. Hotwire
    を使うとどうなるか
    サーバサイドにロジックを寄せることができる
    クライアントサイドのコードは最⼩限に抑えることができる
    それでいて、それなりにSPA
    ができる
    結果として
    ひとつのチームですべてを担当できる(
    かも)
    好きな⾔語を使える
    Hotwire
    はRails
    に限らず使えるようになっている
    ※ブリッジになるようなものは必要(ex: turbo-rails gem)
    9

    View full-size slide

  10. とはいえ
    vue
    やreact
    と⽐べて細かいことはできない
    native
    アプリケーションも基本webview
    になるぞ
    hey.com (Basecamp
    社製のメールサービス)
    くらいのものであれば
    Hotwire
    で実現できるので、そのレベルで問題ないサービスならOK
    「そのレベルで問題ないサービス」は結構な割合でありそう
    10

    View full-size slide

  11. Hotwire
    のアーキテクチャ
    Turbo
    Turbo Drive
    Turbo Frames
    Turbo Streams
    Turbo Native
    Stimulus
    Strada(
    現時点で未発表なので今回は話しません)
    iOS
    やAndroid
    のネイティブで必要な機能(ex:
    カメラ)
    とHTML

    をつなげるためのライブラリらしい
    11

    View full-size slide

  12. 前提
    Hotwire
    はRails
    に限らず使えますが、Rails
    を前提にしたツール
    (turbo-rails)
    があるのでRails
    で使うのが便利です
    今回はturbo-rails
    を利⽤している前提で話します
    12

    View full-size slide

  13. 注意点
    IE
    などの古いブラウザで動かすのは⼤変そう
    fetch API
    custom elements
    Intersection Observer API
    など、モダンブラウザでしか動かないAPI
    を利⽤している
    polyfill
    を使えば動きそうだけど⼤変そう
    IOS
    も12
    以上(
    近いうちに13
    以上)
    が必要
    13

    View full-size slide

  14. Turbo
    から話していきます
    14

    View full-size slide

  15. Turbo Drive
    Turbolinks
    を改善させたもの
    15

    View full-size slide

  16. Turbolinks
    とは
    Rails4.0
    からRails
    標準のライブラリとなっている
    すべてのリンクをajax
    で置き換える
    受け取ったHTML
    のうち、body
    だけを現⾏のものと差し替える
    するとjs
    やcss
    のダウンロード→
    パースをスキップできるぶん⾼速化
    できる
    16

    View full-size slide

  17. 不遇の
    Turbolinks
    リリース当時(
    約7
    年前)
    はjQuery
    およびjQuery
    プラグイン全盛
    Turbolinks
    はjQuery
    プラグインと相性が悪いことがあった
    Turbolinks
    を使うためには⾊々わかっている必要があった
    通常のページロードは最初の⼀回のみであること
    E2E
    テストで、次ページに遷移したかをちゃんと待つ必要がある
    form
    に関しては完全に対応していないこと
    ハマるひとが多く、デメリットが⼤きいと判断→
    基本消されるライ
    ブラリに
    17

    View full-size slide

  18. Turbolinks
    もきちんと理解して使えば
    使いやすい
    いまはSPA
    なアプリケーションも増えたので、フロントエンドの知
    識のある⼈も増えている(
    はず)
    要点さえ押さえれば、少ない労⼒でSPA
    化が可能なメリットは変わ
    っていない
    18

    View full-size slide

  19. (
    余談
    )
    いま
    Turbolinks
    を使っているひと
    はどうやって
    Turbo
    に移⾏したらいいの
    エイヤで頑張ると移⾏できます
    詳細はブログに書いたのでこちらを⾒てください
    Turbolinks
    からTurbo
    への移⾏ -
    おもしろweb
    サービス開発⽇記
    19

    View full-size slide

  20. Turbo Drive
    による改善
    form
    に関してもデフォルトでturbo
    仕様になった
    form_with
    ヘルパメソッドはこれまでTurbolinks
    を意識し、デフォ
    ルトで data-remote="true"
    属性がついていた
    Turbolinks
    を使っていない⼈からしたら混乱の元
    Turbo
    がリリースされたことにより、Rails6.1
    から
    data-remote="true"
    はデフォルトオフになった
    20

    View full-size slide

  21. Turbo Drive

    form
    送信時の挙動
    form
    送信時は302
    などのレスポンスが返るとリダイレクト、4xx

    5xx
    系が返るとレスポンスボディを差し替えて履歴はそのまま、と
    なった
    Turbolinks
    時にここをちゃんとやろうとすると⼿動でSJR(Server
    generated javascript response)
    して対応する必要があった
    21

    View full-size slide

  22. SJR
    ってなに
    例えばPost
    のcreate
    アクションでバリデーションエラーが起きたら、
    次のようなposts/create.js.erb
    をレンダリングします。
    (shared/_error.html.erb
    にエラーメッセージ⽤の部分テンプレートが
    ⼊っている想定)
    document.querySelector('#error').innerHTML =
    "<%= j(render("shared/error", model: @post)) %>";
    するとrails-ujs
    が↑
    の内容をeval
    してくれるので

    にエラーメッセージが表⽰されます。
    22

    View full-size slide

  23. SJR
    、セキュリティどうなんですか
    さっき提⽰したコードのレベルなら⼤丈夫だけど、ユーザが⼊⼒し
    た⽂字列をカジュアルにSJR
    とすると⼤変危険ですね><
    そもそもTurbo(links)
    でなにかするときに頻出する操作は限られて
    いる
    特定のDOM
    にHTML
    を挿⼊する(append, prepend)
    特定のDOM
    を差し替える(replace, update)
    特定のDOM
    を削除する
    これを提供するのがTurbo Streams
    23

    View full-size slide

  24. Turbo Streams
    Turbo
    のレスポンスとして、↓
    のようなHTML
    ⽚を Content-
    Type=text/vnd.turbo-stream.html
    で返すとTurbo
    がいい感じに処理し
    てくれる。



    id
    がmessages
    なDOM
    の内部に挿⼊(append)
    される



    24

    View full-size slide

  25. 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

    View full-size slide

  26. 複数操作をする
    ビュー側で複数のturbo-stream
    タグをレンダリングして複数操作をす
    ることもできる
    <% # app/views/entries/entry.turbo_stream.erb %>
    <%= turbo_stream.remove entry %>
    <%= turbo_stream.append "entries" do %>
    <%= render partial: "entries/entry", locals: { entry: entry } %>
    <% end %>
    26

    View full-size slide

  27. Turbo Streams
    で使える
    action
    action
    として使えるのは次の5
    種類のみ
    append
    prepend
    replace
    update
    remove
    レールを敷くことで判断を楽にできるのと、SJR
    でセキュリティに⽳
    を開けるのを防ぐことができるのがメリット
    27

    View full-size slide

  28. Turbo Streams

    websocket
    websocket(Action Cable)
    でも使える
    turbo-rails
    にはAction Cable
    ⽤のヘルパメソッドがあり、subscribe
    やbroadcast
    が簡単にできるようになっている
    例えば新着メールが来たタイミングで⾃動的にメールが追加され
    る、というのが簡単にできる
    詳細はturbo-rails
    ソースコードをみてください(
    現時点でドキュメ
    ントにはほぼ記載がない)
    28

    View full-size slide

  29. ここまで⾒てわかる
    Turbo
    ができること
    既存のHTML
    をそのまま使いつつユーザ体験を良くする(Turbo
    Drive)
    同じテンプレートをいろんなところで使い回す(Turbo Stream)
    ex:
    ⼀通のメッセージを表す部分テンプレートをTurbo Streams

    も使う
    29

    View full-size slide

  30. もっと使いまわしたい
    いろんな環境で共通のテンプレートが使えるとうれしい
    スマホなどの⼩さい画⾯
    PC
    の⼤きい画⾯
    そこで Turbo Frames
    ですよ
    30

    View full-size slide

  31. Turbo Frames
    turbo-frame
    タグ中に書かれた要素はframe
    として区切られる
    frame
    内のリンクはTurbo Frames
    ⽤のリンクとなる(
    詳しくは次⾴)



    メッセージ⼀覧

    Hotwire

    いいですね
    // ↓
    をクリックすると…


    メッセージを編集する

    31

    View full-size slide

  32. Turbo Frames



    メッセージの編集





    メッセージの内容




    32

    View full-size slide

  33. つまり
    Turbo Frames
    を使うとレスポンスのHTML
    の⼀部を使い、もとの
    HTML
    の⼀部を部分的に差し替えることができる
    33

    View full-size slide

  34. turbo-frame
    タグの中だけど普通のリン
    クにしたいときもありますよね



    メッセージ⼀覧


    Hotwire

    いいですね

    メッセージを編集する


    34

    View full-size slide

  35. Turbo Frames
    のメリット
    target="_top"
    つけはずしすることで、⼀つのテンプレートを使いま
    わしできる
    ⼤きいディスプレイのときはインライン編集
    スマホなどの⼩さいディスプレイでは専⽤のページに遷移させる
    35

    View full-size slide

  36. Turbo Frames
    のもう⼀つの活⽤⽅法
    src
    属性をつけると、値となるURL
    を⾮同期でfetch
    する
    ファーストビューの時間を短縮できる
    Turbo Frames
    ⽅式でレスポンスを差し替える


    ともだち⼀覧

    ...


    ともだちかも?


    36

    View full-size slide

  37. Turbo Frames
    でさらに遅延表⽰
    loading="lazy"
    をつけると、その要素が画⾯に表⽰されるまでロー
    ドを遅延する


    ともだち⼀覧

    ...


    ともだちかも?



    37

    View full-size slide

  38. Turbo Native
    iOS
    やAndroid
    でTurbo
    を使うためのライブラリ
    webview
    でアプリケーションを利⽤する
    主にTurbo Drive
    での遷移による履歴をネイティブで管理するた
    めのもの
    38

    View full-size slide

  39. Turbo
    については⼀通り話した
    39

    View full-size slide

  40. Turbo
    を使うとサーバサイドにロジック
    が集中する
    つまりjs
    の量が減る
    が、ゼロになるわけではない
    Turbo
    を使うと、全ページで使うjs
    をひとまとめにして提供するよ
    うになる
    js
    の整理がたいへん
    「A
    というページでだけ発⽕させたいjs
    」を管理するのがたいへん
    40

    View full-size slide

  41. Stimulus
    HTML
    とjs
    をいい感じに紐付け合い整理するライブラリ
    学習コストが低い
    41

    View full-size slide

  42. 特定のページだけで発⽕させたい
    js

    書きやすい
    // hello_controler.js
    import { Controller } from "stimulus"
    export default class extends Controller {
    connect() {
    //
    ここにdata-controller="hello"

    //
    表⽰されたときに実⾏したい処理を書く
    }
    }
    43

    View full-size slide

  43. Stimulus
    のメリット
    controller
    ごとにファイルが⾃然と分かれて整理される
    HTML
    タグの属性名を⾒るとjs
    のどの部分に紐付いているかすぐわ
    かる
    特定のページだけで発⽕させたいjs
    が書ける
    44

    View full-size slide

  44. まとめ
    未公開のStrada
    を除き⼀通りHotwire
    について説明した
    Hotwire
    は、"
    最⼩限の労⼒でユーザが求めているサービスを提供す
    ること"
    に特化しているライブラリ
    つまりそれはRails
    と同じ⽅針をフロントエンドにも持ち込んだ、
    と⾔える
    少⼈数で開発するスタートアップ〜中規模なサービスに特に向い
    ているはず
    便利なので使ってみてください!
    45

    View full-size slide