Before starting

  • Quick introduction
  • Not a silver bullet
  • We are just at the beginning

Why?

  • More interactive applications
  • More data to load
  • Reduce the overall complexity

Back in my days...

Rails UJS & Server-generated JavaScript Responses

            
              def create
                @user = User.new(params[:user])

                respond_to do |format|
                  if @user.save
                    format.html { ... }
                    format.js
                  else
                    format.html { ... }
                    format.js
                  end
                end
              end
            
          
            
              // app/views/users/create.js.erb

              const users = document.querySelector("#users");
              users.insertAdjacentHTML("beforeend", "<%= j render(@user) %>");
            
          

Rails UJS & SJR

            
              
    <%= render @users %>
<%= form_with model: @user do |form| %> <%= form.label :name %>
<%= form.text_field :name %> <%= form.submit %> <% end %>

Rails UJS & SJR

It was awesome but...

Rails UJS & SJR

  • Hard to maintain in complex UIs
  • Hard to scale in big teams
  • Configuration over convention
  • Lots of stuff to write manually

Here come the big guys

Front-end Frameworks & SPAs

  • Render happens in the browser
  • Fetch data in JSON via AJAX
            
              $ rails new my-awesome-project --api
            
          

How does it work?

How does it work?

Front-end Frameworks & SPAs

Front-end Frameworks & SPAs

Front-end Frameworks & SPAs

Front-end Frameworks & SPAs

  • Business Logic Duplication
  • Overall performance issues
  • Complex toolchain
  • API and data interchanges
  • Organizational challenges
  • Tons of JS

Front-end Frameworks & SPAs

To prevent full page reload?

  • Maybe you just need Turbolinks with Rails UJS
  • Or just some React or Vue sprinkles
  • You are not Facebook

Here comes Hotwire

Basic concept

Rails partials

            
              <%# app/views/todos/index.html.erb %>

              

Todos

<%= render "search_form" %> <%= render @todos %>
            
              <%# app/views/todos/_todo.html.erb %>

              

<%= todo.description %>

Basic concept

Turbo Frames

Turbo Frames

            
              <%# app/views/todos/show.html.erb %>

              

My awesome todo

<%= @todo.name %>

<%= @todo.description %>

<%= link_to 'Edit this todo', edit_todo_path(@todo) %>
            
              <%# app/views/todos/edit.html.erb %>

              

Editing message

<%# form_with ... %>

Turbo Frames

  • Update just what you need
  • No JavaScript required
  • Basically instant
  • Everything stay on the server side
  • Plug'n'play

What if you need to update multiple frames at once

Or update frames from HTTP responses?

Turbo Stream

            
              def create
                user = User.create!(params[:user])

                respond_to do |format|
                  format.turbo_stream do
                    render turbo_stream: turbo_stream.append(:users, partial: "users/user",
                      locals: { user: user })
                  end

                  format.html { redirect_to users_url }
                end
              end
            
          

Turbo Stream

            
              format.turbo_stream do
                render turbo_stream: [
                  turbo_stream.append(...),
                  turbo_stream.replace(...)
                ]
              end
            
          

Turbo Stream

Turbo Stream

            
              <%# app/views/todos/show.html.erb %>

              <%= turbo_stream_from @todo %>

              

<%= @todo.name %>

Turbo Stream

            
              class Todo < ApplicationRecord
                # broadcasts
                after_create_commit -> { broadcast_append_to self }
                after_destroy_commit -> { broadcast_remove_to self }
                after_update_commit -> { broadcast_replace_to self }
              end
            
          

Demo

You now ๐Ÿ‘‡

Limitations and Drawbacks

  • Poor documentation at the moment
  • Works only perfectly with Stimulus
  • Hard with complex partials
  • Scaling WS could be difficult

When to use it?

Conclusion

  • First-in-Class alternative to SPA
  • Back-end independent
  • Rails way
  • Majestic Monolith
  • Progressively Enhance is possible
  • SEO Friendly

me

@guillaumebriday

Thanks ! ๐Ÿ™