Bienvenido a esta guía de introducción a Turbolinks, una librería Javascript desarrollada por Basecamp para interceptar enlaces en nuestro HTML y, en lugar de cargar la página como se haría normalmente, realizar una petición AJAX para pedir el contenido y posteriormente mostrarlo reemplazando a la vista actual.
En esta guía aprenderemos el funcionamiento de Turbolinks, su integración con Rails y cómo debemos plantear nuestras aplicaciones para que la integración sea perfecta.
Turbolinks intercepta todos los clicks en enlaces de tipo <a href> que apunten al mismo dominio. Cuando un usuario hace click en alguno de esos enlaces:
- Impide que el navegador ejecute la acción por defecto al hacer click (cargar esa página).
- Modifica la URL visible usando el History API.
- Pide la nueva página usando XMLHttpRequest (AJAX).
- Renderiza el nuevo HTML reemplazando el contenido del
bodyy mezclando el delheaderde la respuesta.
Es importante tener en cuenta que los objetos Javascript window y document y el elemento HTML <html> permanecen entre los renderizados realizados, por lo que tendremos que adoptar ciertas medidas con el código Javascript que veremos más adelante.
Es muy habitual que en nuestra aplicación añadamos lógica para ejecutar código Javascript ante los eventos de window.onload o DOMContentLoaded. Tenemos que tener en cuenta que usando Turbolinks esos eventos sólo se lanzarán la primera vez que accedamos a una web, ya que las siguientes veces la página no se cargará al hacerse en segundo plano mediante peticiones AJAX.
En ese sentido, Turbolinks proporciona el evento turbolinks:load que se ejecuta tanto en la primera vez que se carga nuestra aplicación web como cada vez que seguimos un enlace usando la librería y que podemos usar para añadir nuestra lógica Javascript:
document.addEventListener("turbolinks:load", function() {
// ...
})Siempre que sea posible evita hacer uso del evento turbolinks:load para escuchar otros eventos en los elementos HTML, en su lugar usa la Delegación de Eventos para escuchar una sóla vez los eventos en window o document y aplicar la lógica necesaria si realmente la acción se ha producido en un elemento de nuestro interés.
Por ejemplo, mediante este código podemos añadir un listener a un evento click que será ejecutado si el elemento pulsado o alguno de sus ancestros tiene una propiedad HTML data-replace-target.
export default function delegate(element, eventType, selector, handler) {
element.addEventListener(eventType, (...args) => {
const dataTarget = args[0].target.closest(selector);
if (dataTarget) {
handler.call(this, dataTarget, ...args.slice(1));
}
});
}Ejemplo de uso del código anterior:
import delegate from './delegate';
delegate(document, '[data-replace-target]', 'click', (target, evt) => {});Si queremos desactivar la funcionalidad en algunos enlaces concretos, debemos marcarlos con el atributo data-turbolinks="false"
<a href="/" data-turbolinks="false">Disabled</a>
<div data-turbolinks="false">
<a href="/">Disabled</a>
</div>Podemos indicarle a Turbolinks que esté pendiente de los assets que tenemos definidos en nuestro head, de forma que si tras recibir una página detecta que uno de los assets ha cambiado de URL, en lugar de aplicar esos cambios realice una recarga completa de la página para iniciar de nuevo nuestra aplicación con los nuevos assets (habitualmente código javascript nuevo) y tener así siempre los últimos cambios disponibles.
Podemos indicarle que debe estar pendiente de los cambios en un asset usando el atributo HTML data-turbolinks-track="reload":
<head>
...
<link rel="stylesheet" href="/application-258e88d.css" data-turbolinks-track="reload">
<script src="/application-cbd3cd4.js" data-turbolinks-track="reload"></script>
</head>La instalación de Turbolinks la haremos de la forma habitual al estar publicado como paquete en npmjs.com:
yarn add turbolinksPosteriormente en nuestro archivo app/javascripts/packs/application.js lo cargamos e inicializamos.
Ejemplo usando una sintaxis de ES6:
import Turbolinks from 'turbolinks';
Turbolinks.start();Ejemplo usando la sintaxis de CommonJS:
require('turbolinks').start();Con estos sencillos pasos ya quedaría nuestra aplicación preparada para usar Turbolinks.