Pré-requis
Compilation avec Parcel
Parcel permet comme beaucoup d'autres « bundlers » de compiler des fichiers (tels que CSS, Javascript, etc...) afin d'optimiser le chargement d'un site web. Plus simple d'utilisation que pas mal de ses concurrents, il est aussi moins configurable car très automatisé dans son fonctionnement de base. Mais sous cette apparence de simplicité se cache un outil puissant que l'on peut modeler suivant nos besoins.
Prenons l'exemple d'un site simple avec la structure suivante :
index.html :
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS « inline » avec Parcel</title>
<link rel="stylesheet" href="./scss/index.scss">
</head>
<body>
<header>
<a href="#accueil">Accueil</a>
<a href="#articles">Articles</a>
</header>
<main>
<h1>Bienvenue !</h1>
<h2>CSS « inline » avec Parcel</h2>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Accusamus rem, cupiditate dolore cumque placeat beatae officia porro explicabo. Fugiat qui nisi perferendis ducimus facere quas eaque, voluptatum suscipit quam quibusdam!</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Accusamus rem, cupiditate dolore cumque placeat beatae officia porro explicabo. Fugiat qui nisi perferendis ducimus facere quas eaque, voluptatum suscipit quam quibusdam!</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Accusamus rem, cupiditate dolore cumque placeat beatae officia porro explicabo. Fugiat qui nisi perferendis ducimus facere quas eaque, voluptatum suscipit quam quibusdam!</p>
</main>
<footer class="bg-light">
<a href="#social">Réseaux sociaux</a>
<a href="#blog">Blog</a>
</footer>
</body>
</html>
index.scss :
scssa {
color: #fff !important;
text-decoration: none;
background-color: transparent;
}
header {
background: #00485e;
padding: 0.5rem 1rem;
font-size: 1.5rem;
display: flex;
a {
margin-right: 2rem;
}
}
main {
font-size: 2rem;
padding: 1rem;
min-height: 150vh;
}
h1,h2 {
font-weight: 500;
line-height: 1.2;
margin-top: 0;
}
h1 {
font-size: 3rem;
margin-bottom: 1em;
}
h2 {
font-size: 3rem;
margin-bottom: 1em;
}
p {
margin-top: 0;
margin-bottom: 3em;
}
footer {
padding: 0.5rem 1rem;
display: flex;
a {
color: #000 !important;
margin-right: 2rem;
}
}
@import "~bootstrap/scss/bootstrap";
package.json :
json{
[...]
"devDependencies": {
"replace": "^1.2.0"
},
"dependencies": {
"bootstrap": "^4.5.0"
}
}
Installation de Parcel :
Tout d'abord il est nécessaire d'installer le paquet Parcel pour pouvoir l'utiliser.
bashnpm install parcel-bundler -g
Lancement d'une compilation Parcel avec serveur de développement :
Pour nous aider à développer notre site, Parcel nous propose de lancer un serveur rechargeant automatiquement notre page en cas de modifications apportées à notre code :
bashparcel ./public/index.html
Notre site est maintenant accessible à l'adresse : http://localhost:1234
Audit
Lors de l'audit du site (réalisé avec Lighthouse dans les DevTools de Chrome) on peut s'apercevoir que le fichier CSS (dont le nom a changé car il a été compilé par Parcel) est une ressource bloquant le rendu de la page :
Extraction du CSS avec Parcel
L'important est maintenant d'identifier le code CSS critique. Dans notre cas c'est assez simple, car seuls les éléments header
et main
(ainsi que les éléments les composant) sont au dessus de la ligne de flottaison. Nous allons donc extraire le CSS correspondant dans un nouveau fichier.
critique.scss :
scssa {
color: #fff !important;
text-decoration: none;
background-color: transparent;
}
header {
background: #00485e;
padding: 0.5rem 1rem;
font-size: 1.5rem;
display: flex;
a {
margin-right: 2rem;
}
}
main {
font-size: 2rem;
padding: 1rem;
min-height: 150vh;
}
h1,h2 {
font-weight: 500;
line-height: 1.2;
margin-top: 0;
}
h1 {
font-size: 3rem;
margin-bottom: 1em;
}
h2 {
font-size: 3rem;
margin-bottom: 1em;
}
p {
margin-top: 0;
margin-bottom: 3em;
}
index.scss :
scssfooter {
padding: 0.5rem 1rem;
display: flex;
a {
color: #000 !important;
margin-right: 2rem;
}
}
@import "~bootstrap/scss/bootstrap";
Puis modifier le fichier index.html :
html<link rel="stylesheet" href="./scss/critique.scss">
<link rel="stylesheet" href="./scss/index.scss">
Audit
Lors d'un nouvel audit voici le résultat :
Les deux fichiers CSS sont maintenant des ressources bloquant le rendu de la page. Pour y remédier il faut passer le code CSS du fichier critique.scss « inline » dans index.html et différer le reste du CSS. Ce qui donne dans index.html :
html<link rel="stylesheet" href="./scss/critique.scss" inline>
<link rel="preload" href="./scss/index.scss" type="text/css" onload="this.rel='stylesheet'" as="style">
Et là vous me direz que le CSS critique n'est pas « inline » et vous aurez raison. Mais comme ce fichier est susceptible d'être modifié, il faut que ce soit Parcel qui s'occupe de placer automatiquement ce code dans index.html.
Pour en savoir plus sur le CSS différé : https://web.dev/defer-non-critical-css/
L'API Parcel à la rescousse
Parcel mets à disposition une API permettant d'écrire des règles de compilation avancées (https://parceljs.org/api.html).
Nous allons créer un nouveau fichier build.js :
javascriptconst Bundler = require('parcel-bundler');
const Path = require('path');
const replace = require('replace');
const fs = require('fs');
const entryFolder = Path.join(__dirname, './public');
const entryFiles = [Path.join(entryFolder, '/index.html')];
const options = {
watch: false
// minify: true,
// sourceMaps: false
};
const inlineLinkRegex = new RegExp(/<link.* href="(.*)".* inline.*>/, 'g');
(async function () {
// Création du bundler
const bundler = new Bundler(entryFiles, options);
// Evénement emit par Parcel lorsque le build est terminé
await bundler.on('buildEnd', () => {
// Pour chaque fichier d'entrée, on va chercher si du CSS doit être placé inline
entryFiles.forEach((file, index) => {
// Fichier de sortie correspondant
const outFile = Path.join(bundler.options.outDir, file.replace(entryFolder, ''));
// Contenu du fichier de sortie
const fileContent = String(fs.readFileSync(outFile));
// On cherche les balises link contenant l'attribut inline
const matches = fileContent.matchAll(inlineLinkRegex);
for (const match of matches) {
// Contient la balise link complète
const fullMatch = match[0];
// Contient l'attribut href de la balise link
const groupMatch = match[1];
// Chemin du fichier CSS compilé (dans le dossier de sortie)
const cssFilePath = Path.join(bundler.options.outDir, groupMatch);
// Contenu du fichier CSS correspondant à la balise link
const cssContent = fs.readFileSync(cssFilePath);
// On remplace la balise link par le contenu du fichier CSS correspondant
replace({
regex: fullMatch,
replacement: "<style>" + cssContent + "</style>",
paths: [outFile],
recursive: false,
silent: true,
});
// Suppression du fichier CSS compilé devenu inutile
fs.unlinkSync(cssFilePath);
}
});
});
// On lance le build pour compiler sans serveur de dev
const bundle = await bundler.bundle();
// On lance le build avec un serveur de dev
// Attention, le code de remplacement ne fonctionnera pas lors de la modification de vos fichiers
// const bundle = await bundler.serve();
})();
Il est maintenant possible de lancer une compilation :
bashnode build.js
Une fois la compilation terminée, dans le dossier de sortie (/dist par défaut) le fichier index.html contient le CSS correspondant au fichier critique.css.
Attention, ce script n'a pas vocation à être utilisé en développement mais uniquement pour des compilations uniques (pour de la production par exemple).
Résultats
Lançons un dernier audit avec nos modifications :
Conclusion
Grâce à Parcel, nous avons vu qu'il est simple de mettre en place des actions pour optimiser les performances d'un site web. Sa légèreté et sa simplicité permettent de l'adapter au plus prêt d'un besoin spécifique en un temps relativement court.
Il est important de réaliser des Audits de performances lors du développement d'un site web, car en plus du ressenti utilisateur et de l'image que cela renvoi, elles ont un impact important en terme de référencement sur les moteurs de recherche.