Guia Hotwire: Turbo Drive

Eduardo Yutaka Nakanishi
5 min readFeb 6, 2024

--

Esse é o primeiro capítulo de uma série de artigos que irei escrever com o objetivo de desmistificar o uso do Hotwire principalmente em conjunto com o Ruby on Rails

Se você tentou aprender Hotwire (Turbo Drive, Turbo Frames, Turbo Streams, Stimulus) pelo https://hotwire.dev mas achou a documentação um pouco incompleta e confusa — you are not alone!

O conteúdo que estou escrevendo tem o objetivo de facilitar essa curva inicial de aprendizado do Hotwire e é o fruto de várias visitas à documentação, videos, artigos, experimentos e uso em produção dessa abordagem de desenvolvimento que virou tendência no mundo Rails

O que é o Turbo Drive?

Para começarmos a entender a família turbo, podemos observar esse gráfico apresentado no Opening Keynote do Rails World 2023

Nesse gráfico, o Turbo Drive é representado pelo “Full <body> replacement” (conseguiu achar ali na imagem?). A ideia principal é, como apontado pela documentação, fazer a “navegação dentro de um processo persistente” (WTF?)

Mas o que isso significa??

Quando clicamos em um link <a href="https://medium.com>Medium</a> o nosso navegador inicia uma requisição HTTP GET no URL passado dentro do href e realiza um “full-page reload”

Isso significa que a response dessa request HTTP será um bloco<html> inteiro, incluindo o <head> que contém assets como CSS e JavaScript. Logo, os assets terão que ser baixados novamente pelo navegador e você passa por uma experiência de “recarregar” a página, onde geralmente aparece uma barrinha de carregamento no navegador

Os SPA (Single Page Applications) têm uma proposta de navegação diferente, na qual a página não é inteiramente substituída e em vez disso a navegação parece mais fluida e instantânea. Eles conseguem fazer isso porque as interações de navegação são feitas inteiramente no Client-Side por meio do JavaScript, ou seja, quando um link é clicado, o JavaScript substitui o DOM da sua página por outra sem fazer uma requisição HTTP

Um dos principais objetivos do Turbo Drive então é tentar proporcionar essa mesma experiência de navegação dos SPA mas de maneira mais simples, sem o uso de um Router customizado como é feito em algumas bibliotecas React

Como o Turbo Drive faz isso?

O Turbo Drive obtém esse efeito de navegação fluida dos SPA de uma maneira parecida aos frameworks JavaScript

Basicamente, o Turbo Drive é um pequeno arquivo JavaScript que adicionamos no nosso projeto (ele já vem pronto, não precisamos escrever o JavaScript!) e o código dele amplifica as capacidades dos nossos links HTML

O código do Turbo Drive intercepta todos os clicks em anchor tags (<a> tag) e em vez de fazer o “full-page reload”, ele realiza uma request AJAX, pega o resultado apenas do <body> e realiza o “full-body replacement” mencionado no gráfico introdutório

Em outras palavras, em vez de realizar o fluxo normal de um link do HTML, ele faz a requisição no JavaScript (tipo um fetch API, axios) e substitui apenas o <body> do DOM

Assim, os assets do <head> são preservados, não necessitando fazer o download uma segunda vez (pois geralmente os assets são os mesmos) obtendo ganho de performance e a experiência de navegação dos SPAs com a vantagem de que você não precisa fazer nada demais além de adicionar o Turbo Drive na aplicação, ou seja, você não escreve nada em JavaScript, não precisa mudar seu HTML nem seu Ruby, apenas obtém os benefícios!

Mas e se eu precisar recarregar os assets nessa nova página?

O comportamento padrão do Turbo Drive é fazer apenas um full-body replacement em vez de um full-page replacement, mantendo os assets intactos (que geralmente são definidos nos layouts do Rails)

No entanto, podemos customizar esse comportamento com data attributes específicos do Turbo Drive

Aquele JS do Turbo Drive que você adiciona permite que seu HTML possa ter novos atributos que são utilizados no Turbo Drive, como por exemplo o “turbo-visit-control”

<head>
...
<meta name="turbo-visit-control" content="reload">
</head>

Ao adicionar uma <meta> tag com o atributo name="turbo-visit-control” e content="reload" a uma página, essa página em específico fará um full-page reload, “desfazendo” o efeito do turbo de fazer apenas o full-body reload

É um recurso que podemos utilizar para quando precisamos recarregar a página pois temos algum script JavaScript que precisa executada toda vez que a página é acessada (o que o Turbo não faz). Podemos dizer que você estará fazendo literalmente um hard reset na página e tudo será carregado do início

O que mais o Turbo Drive faz?

O ponto principal do Turbo Drive é otimizar a navegação sem recarregar os assets e fazendo a experiência ser mais fluida, mas ele tem algumas funcionalidades extra também que eu vou citar aqui:

Poder navegar com outro método além de GET

Vejamos o exemplo de link abaixo:

<a href="/users/1" turbo-data-method="delete">Deletar Usuário</a>

Esse link fará uma requisição HTTP DELETE no URL /users/1 e seguirá o fluxo normal do Rails, indo provavelmente para a controller/action “users#destroy”. O que acontece depois depende de como o destroy foi programado na controller

O famoso “turbo-data-confirm”

Bibliotecas como o devise utilizam o atributo “turbo-data-confirm” — que é um daqueles atributos extras que o Turbo adiciona ao nosso HTML — para mostrar um alerta de confirmação para o usuário que deve ser aceitado para concluir a ação

Desativando o Turbo

Podemos usar um data attribute do Turbo para desativar o full-body reload e usar o full-page reload

<a href="users/1" data-turbo="false">Usuário 1</a>

Esse atributo pode ser usado em forms e outro elementos HTML também, de modo que todos os elementos filhos terão o Turbo Drive desabilitado. Para reabilitar, podemos adicionar data-turbo=”true”

Turbo Drive no Ruby on Rails

Nas views ERB do Ruby on Rails, costumamos usar view helpers para definir as nossas tags HTML. Aqui abaixo estão alguns exemplos de tags do Rails e seus equivalentes em HTML puro:

# Usando view helpers
<%= link_to user_path(@user), "Delete User", data: { turbo_confirm: "Are you sure?" } %>

# Usando HTML puro
<a href="/users/1" data-turbo-confirm="Are you sure?">
Delete User
</a>

A sintaxe dos data attributes nos view helpers é de passar o data como sendo uma Hash que contém chaves/valores com os nomes dos atributos do turbo

Outro exemplo pra você pegar a manha:

# Usando view helpers
<%= form_for @user, data: { turbo_method: :update } do |form| %>
<%= form.label :name %>
<%= form.text_field :name %>
<% end %>

# Usando HTML puro
<form action="/user/1" data-turbo-method="update">
<label>Name</label>
<input type="text" />
</form>

Em suma, é importante nos acostumarmos com a sintaxe tanto do HTML puro como dos view helpers pois isso é algo que ajuda muito na hora de ler e entender o que o código está fazendo, principalmente de gemas ou terceiros

Conclusão

O Turbo Drive adiciona ao Ruby on Rails (e outros frameworks) melhorias de performance real (evitar full-page reloads desnecessários) e aparente (navegação mais fluida para o usuário) por meio de um pequeno código JavaScript adicionado no projeto

Além disso, ele estende as capacidades do HTML adicionando data attributes que permitem modificar o comportamento padrão de tags HTML (como o método HTTP que os links e forms utilizam, o turbo confirm, etc.)

Para o desenvolvedor, pouca coisa precisa ser mudada, ainda estamos desenvolvendo aplicações Ruby on Rails como sempre estivemos acostumados, mas com várias melhorias e usufruindo de tendências do ecossistema de desenvolvimento

  1. Guia Hotwire: Turbo Drive
  2. Guia Hotwire: Turbo Frames (em breve)
  3. Guia Hotwire: Turbo Streams (em breve)
  4. Guia Hotwire: Stimulus Controller (em breve)

--

--