web 2.0

Seebz.net

Minifiez vos feuilles de styles et vos fichiers javascript

On en parle de plus en plus, Google commence à prendre en compte le temps de chargement des pages dans son algorithme de positionnement.
Une façon simple d'accélérer le temps de chargement est de regrouper et compresser les fichiers externes, diminuant le nombre de requêtes HTTP et le poids de ces fichiers.

Ce tutoriel a pour objectif de vous expliquer comment mettre en place un tel système.

Introduction

Supposons que votre layout contienne les lignes suivantes :

<html>
<head>
	<title>Monsite.com</title>
	<link rel="stylesheet" type="text/css" href="/styles/common.css" /> 
	<link rel="stylesheet" type="text/css" href="/styles/site.css" /> 
	<link rel="stylesheet" type="text/css" href="/styles/divers.css" /> 
	<link rel="stylesheet" type="text/css" href="/styles/print.css" media="print" /> 
	<script type="text/javascript" src="/js/mootools-core.js"></script> 
	<script type="text/javascript" src="/js/mootools-more.js"></script> 
	<script type="text/javascript" src="/js/application.js"></script> 
</head>
<body>

Ceci pourrait se représenter par l'arborescence suivante :

Nous remarquons que ces quelques lignes feront appel à 7 fichiers externes, fichiers qui ne sont pas forcément compressés. Je propose donc de regrouper les fichiers qui peuvent l'être et y supprimer les caractères inutiles (espaces, sauts de ligne et commentaires).

De cette manière, nous n'appellerons plus que 3 fichiers que je nommerais minify.all.css, minify.print.css et minify.js (dans notre exemple, nous avons besoin de 2 feuilles de styles).

Modification du layout/template

Notre code précédent deviendrai le suivant :
<html>
<head>
	<title>Monsite.com</title>
	<link rel="stylesheet" type="text/css" href="/styles/minify.all.css" /> 
	<link rel="stylesheet" type="text/css" href="/styles/minify.print.css" media="print" /> 
	<script type="text/javascript" src="/js/minify.js"></script> 
</head>
<body>

Bien entendu, cela ne suffira pas, les fichiers "minify" n'ayant pas étés générés.
Pour se faire, nous allons utiliseront des scripts PHP qui généreront les autres fichiers s'ils n'existent pas, nous les appellerons minify.css.php et minify.js.php.

Le fichier minify.css.php

Nous placerons ce fichier dans le dossier styles, nous verrons par après comment l'appeler ;)

<?php

// Paramètres
if(isset($_GET['media']) && $_GET['media']=='print') {
	$sources = array('print.css');
	$dest = 'minify.print.css';
} else {
	$sources = array(
		'common.css',
		'site.css',
		'divers.css'
	);
	$dest = 'minify.all.css';
}


// Traitement
error_reporting(0);

$out[] = sprintf('/* Generated on %s at %s */', date('Y-m-d'), date('H:i'));
foreach($sources as $source)
{
	$out[] = '';
	$out[] = sprintf('/* %s */', $source);
	$out[] = minify_css(file_get_contents($source));
}
$out = implode("\n", $out);

// Affichage
header('Content-Type: text/css');
echo $out;

// Enregistrement
file_put_contents($dest, $out);


/*
 * La fonction minify_css()
 *
 * placez ici la dernière version que vous trouverez à l'adresse :
 * http://code.seebz.net/p/minify-css/
 */

Le fichier minify.js.php

Ce fichier, à placer dans le dossier js, est assez semblable au précédant.

<?php

// Paramètres
$sources = array(
	'mootools-core.js',
	'mootools-more.js',
	'application.js'
);
$dest = 'minify.js';



// Traitement
error_reporting(0);

$out[] = sprintf('/* Generated on %s at %s */', date('Y-m-d'), date('H:i'));
foreach($sources as $source)
{
	$out[] = '';
	$out[] = sprintf('/* %s */', $source);
	$out[] = minify_js(file_get_contents($source));
}
$out = implode("\n", $out);

// Affichage
header('Content-Type: application/javascript');
echo $out;

// Enregistrement
file_put_contents($dest, $out);


/*
 * La fonction minify_js()
 *
 * placez ici la dernière version que vous trouverez à l'adresse :
 * http://code.seebz.net/p/minify-js/
 */

A ce stade, nous devrions avoir cette arborescence :

Maintenant, il ne nous reste plus qu'à faire une règle du style « si le fichier "minify.js" n'existe pas, on charge le fichier "minify.js.php" ». (Même chose pour les feuilles de styles)

Le .htaccess

# Désactivation de l'option MultiViews (à décommenter si nécessaire)
#Options -MultiViews

# Minify
RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/minify\.js$ 			$1/minify.js.php [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/minify\.css$			$1/minify.css.php [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/minify\.all\.css$		$1/minify.css.php?media=all [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/minify\.print\.css$	$1/minify.css.php?media=print [L]

# Cache (30 jours)
<FilesMatch "minify(\..+)?\.(css|js)$">
Header set Cache-Control "max-age=2592000, public"
</FilesMatch>

De cette façon, les fichiers seront générés lors du premier appel et seront mis en cache pendant 1 mois dans le navigateur, économisant encore quelques requêtes HTTP inutiles.

J'espère que cet article vous a plu et vous sera utile :D

Partager : Share
 

7 Réponses à “Minifiez vos feuilles de styles et vos fichiers javascript”

  1. Extra ce tutorial. D'autant plus que diminuer le nombre de requêtes HTTP et le poids des fichiers est très à la mode en ce moment.
    Je garde ce tuto sous la main, il me sera utile. :)

  2. Le problème du expire sans versioning c'est que si tu as un bug js ou que tu changes de CSS tes visiteurs l'auront pendant un mois en cache.

    Pour en savoir plus sur le versioning : http://dev.petitchevalroux.net/astuces-divers/faire-versioning-fichier-statique-astuces.198.html

    Sinon très bonne idée ton test if not file exist. J'ai souvent vu des personnes taper direct sur le php pensant "optimiser" grâce à la minification... Ça m'a toujours fait doucement rigoler...

  3. @petitchevalroux : pour le problème du "versionning", j'ai tendance à ajouter un paramètre à l'url (par exemple v) que j'incrémente lors d'une modification de façon à forcer le rechargement de ces fichiers.
    Tu peux d'ailleurs le remarquer dans la source de mon blog ;)

    Par exemple :

    <script type="text/javascript" src="script.js?v=1"></script> 
    


    edit: après lecture de ton article, je me rend compte qu'on est d'accord sur le principe :)

  4. En effet !

    En espérant que les gens lisent les comm's ;)

  5. Hmmmm.... On peut faire bcp mieux :
    Une vraie compression (Dean Edwards et Gzip)
    Ajouter l'expire
    Créer un répertoire dédié à la compression (pour éviter de tout mélanger)
    Analyser les modifs faites au fichier JS source et générer seulement si modifié
    Fusionner les fichiers...

    Bref, le code proposé manque cruellement d'ingéniosité.

  6. @Elo si tu aurai lu l'article, tu aurai remarqué que le script PHP n'est exécuté que si le fichier `minify` n'existe pas, autrement dit une seule fois... et que les fichiers sources étaient fusionnés.

    Pour la gestion des headers (Etag, Modified-Since, ...) et de la compression gzip, on laisse ça à la charge du serveur web. Bien entendu, il faut bien le paramétrer.
    Personnellement j'ai désactivé les headers `Etag` et `Last-Modified` pour ces fichiers (de façon a éviter des requêtes qui auront pour réponse 304) et ajouté un Expire de 1 mois... sans oublier Deflate bien entendu ;)

    Pour le reste, libre au gens d'organiser leurs dossiers comme ils l'entendent, de même pour les scripts `minify`.


    Il n'y a pas UNE bonne solution, il y en a plusieurs avec leurs avantages et inconvénients. Ce n'est pas parce que les gens n'utilisent pas TA solution que ça ne vaut rien.

  7. Merci pour ce code, je l'ai testé hier soir, j'ai encore quelques modifications à apporter mais globalement ça tourne bien.
    Je me permettrais de rajouter que pour compresser les fichier il y a le YUI Compressor (écrit en java) qui permet l'obfuscation des scripts JS et styles CSS. Je l'utilise pour mes scripts et c'est vraiment pas mal :).

    Cdlt ^^

Poster un commentaire

Remonter