Subito Labs

Booster Eleventy avec Turbolinks

Pour donner l'illusion d'un routeur côté client et donc améliorer encore les performances d'Eleventy, nous pouvons utiliser la librairie Turbo.

Turbo

Qu'est-ce que Turbo ?

Anciennement appelée "Turbolinks", cette librairie Javascript a été créée par l'équipe de Basecamp. Elle fait partie d'un écosystème comprenant plusieurs projets complémentaires qui ont pour but de "simplifier" la création d'applications modernes en réduisant la dépendance à Javascript. Pour en savoir plus je vous conseille de faire un tour sur la page de cet écosystème.

Comment ça marche ?

On charge simplement la librairie dans notre balise <head> :

<script type="module" src="https://cdn.skypack.dev/@hotwired/turbo"></script>

La librairie va automatiquement s'occuper d'intercepter tous les clicks sur des liens, les fetcher et remplacer le body de notre page par celui de la page cible. Ce faisant, on évite de refaire toutes les requêtes comme le CSS etc...

Sorcellerie me direz-vous ! Et vous aurez raison, car comme tout ce qui est trop beau pour être vrai, il y a certaines choses à adapter à Turbo...

Mes scripts ne fonctionnent plus !

Il est important de comprendre que tout le body est remplacé, si vous chargez des scripts ailleurs que dans le <head>, ils disparaîtront au premier lien cliqué. J'ai remarqué aussi qu'il faut inclure ses scripts dans le <head> avant d'inclure Turbo.

Mes event listener ne sont plus déclenchés !

C'est normal, admettons que vous ayez un fichier app.js contenant le code suivant :

const menu = document.querySelector(".primaryNav");

menu.addEventListener("click", (e) => {
menu.classList.toggle("is-active");
});

Au premier chargement de la page, cela fonctionne, mais dès la première navigation, le DOM est entièrement effacé et remplacé, ce qui veut dire que votre const menu ne pointe plus sur rien. L'event-listener qui y est attaché ne sera pas non plus déclenché.

La solution, l'event delegation

Le DOM est remplacé, mais le document reste le même, il va donc falloir lui déléguer les event-listeners comme ceci :

document.addEventListener("click", (e) => {
let menu = document.querySelector(".primaryNav");

menu.classList.toggle("is-active");
});

Mon formulaire 11ty ne redirige plus vers le message de confirmation

Turbo reçoit le mauvais code HTTP après une soumission réussie d'un formulaire, et ne détecte pas d'évènement de navigation. La solution est de désactiver Turbo sur le formulaire avec data-turbo="false":

<form name="contact" method="POST" action="/success" data-turbo="false" netlify>
<!-- mes champs -->
</form>

Problèmes avec le dev server d'Eleventy

Vous remarquerez aussi que les liens sont cassés lors du développement avec le serveur de dev d'Eleventy. Pour résoudre ce problème il faut charger Turbo seulement en production...

Créer un fichier dotenv

Il faut d'abord installer le paquet npm dotenv :

npm install -D dotenv

Ensuite, on peut créer un fichier .env à la racine de notre projet - il ne doit pas être versionné - et on y écrit cette ligne :

ELEVENTY_ENV="development"

En production, on aura évidemment un fichier .env où la variable ELEVENTY_ENV sera "production".

Créer une variable d'environnement Eleventy

Eleventy permet de déclarer des variables d'environnement, pour cela, créez un dossier _data à la racine de votre projet et ajoutez y un fichier siteData.js contenant :

module.exports = {
environment: process.env.ELEVENTY_ENV
}

Conditionner le chargment de Turbo

Maintenant, dans notre fichier layout, on va pouvoir ne charger Turbo que si on est production :

{% if siteData.environment == "production" %}
<script type="module" src="https://cdn.skypack.dev/@hotwired/turbo"></script>
{% endif %}

Et le tour est joué !

Conclusion

Turbo a provoqué beaucoup de discussions et propose un nouveau paradigme de développement web.

Seul le temps nous dira si cette philosophie aura du succès, mais sur un projet simple où on a besoin de très peu de Javascript, l'accélération que la librairie propose est très intéressante.

Un projet à nous proposer ?

Contactez nous !