C'est quoi "Early Hints" ?
Early Hints est une fonctionnalité du protocole HTTP/2 qui permet au serveur d'envoyer une réponse HTTP 103 (Early Hints) pour transmettre des en-têtes HTTP avant même que la réponse complète de la page soit renvoyée. Documentation Mozilla
Early Hints est pris en charge par tous les navigateurs modernes (Chrome 103, Firefox 102, Opera 89, Edge 103), sauf Safari.
Dans Firefox, vous devez activer, cette fonctionnalité depuis la page about:config en activant les paramètres network.early-hints.enabled
et network.early-hints.preconnect.enabled
.
Envoyer certains en-têtes en avance est très utile lorsque l'on souhaite donc précharger des ressources comme avec l'en-tête Link
Link </app.css>; rel="preload"; as="style"
.
ATTENTION : le preloading pour des feuilles de style DOIT être défini à style et non stylesheet comme on a l'habitude dans les balises link.
Comment utiliser Early Hints avec Symfony 6.3?
La documentation est assez complète à ce sujet : voir la doc.
On doit appeler la méthode sendEarlyHints
dans notre controller. Cette méthode, disponible depuis Symfony 6.3, va nous permettre
d'activer le mécanisme derrière la fonctionnalité d'Early Hints. On verra après comment est-ce que cela fonctionne en interne.
#[Route("/", name: "homepage")] public function index(): Response { $response = $this->sendEarlyHints([ (new Link(rel: 'preload', href: '/app.css'))->withAttribute('as', 'style'), (new Link(rel: 'preload', href: '/app.js'))->withAttribute('as', 'script'), ]); // chargement du contenu pour le chargement de la page : appels BDD, ... return $this->render('homepage/index.html.twig', response: $response); }
sendEarlyHints
nécessite d'ajouter le paquet symfony/web-link
à nos dépendances pour pouvoir manipuler l'objet Link
.
Mieux comprendre l'implémentation Symfony du Early Hints : les composants HttpFoundation & WebLink.
sendEarlyHints
va construire un objet Symfony\Component\HttpFoundation\Response
avec les en-têtes Link avant d'appeler la méthode sendHeaders
sur ce même objet.
$response->headers->set('Link', $this->container->get('web_link.http_header_serializer')->serialize($populatedLinks), false); $response->sendHeaders(103);
_web_link.http_header_serializer_
fait partie du composant WebLink sources et converti l'objet Link
en un en-tête.
Après ça, un appel à la méthode sendHeaders(103)
est fait qui en interne est traité avec la fonction php : headers_send(103)
. Mais en regardant la documentation PHP, headers_send()
n'existe pas, on a seulement la fonction headers_sent()
. Et c'est pour cette raison que
Early Hints nécessite un environnement PHP particulier comme FrankenPHP.
Un serveur PHP moderne : FrankenPHP
En lisant la documentation de FrankenPHP, on peut y lire ceci :
FrankenPHP gives superpowers to your PHP apps thanks to its stunning features: Early Hints, worker mode, real-time capabilities, automatic HTTPS, HTTP/2, and HTTP/3 support... source
Pour en savoir plus sur FrankenPHP et ce qu'il change a l'écosystème actuel des serveurs PHP, voici un talk de Kévin Dunglas (createur de FrankenPHP) sur YouTube.
Utiliser Docker pour lancer un serveur FrankenPHP :
docker run -v $PWD:/app -p 80:80 -p 443:443 dunglas/frankenphp
Benchmarking
Pour tester la fonctionnalité, je simule un chargement de page très long (2 secondes) et un fichier CSS et JS avec un délai de 1 seconde chacun.
On doit donc observer un délai de chargement de la page de 3 secondes environ sans Early Hints et 2 secondes avec.
Sur Firefox, après avoir activé la fonctionnalité, j'observe bien le gain de performance.
Cependant, je perds dans ma console de debug les traces des appels qui sont faits via du preloading donc mon css et js ne s'affiche pas.
Sur Chrome, aucun changement même avec une version récente (118). Je retesterais dans quelques versions voire si j'ai toujours le même résultat ou si j'ai loupé quelque chose.
Un super article est d'ailleurs disponible sur le blog de Chrome : Faster page loads using server think-time with Early Hints
Même si dans cet exemple, les délais ne sont pas forcément représentatifs de la réalité ça permet de bien visualiser le gain de précharger certaines ressources indispensables à l'affichage de notre page.
Conclusion
En conclusion, la fonctionnalité est très intéressante mais semble pour le moment très peu implémenter au sein des navigateurs.
L'utilisation dans un projet Symfony complexe peut aussi s'avérer plus problématique, on ne va pas mettre a jour l'intégralité des controller pour rajouter un appel à la fonction sendEarlyHints
. Il va falloir travailler sur des solutions plus réutilisables et intelligente au-dessus du fonctionnement offert par Symfony.
Il y a aussi un vraiment manque d'intégration dans l'écosystème actuel des serveurs PHP, merci à frankenPHP de venir moderniser tout ça ! :pray: