Увеличиваем скорость загрузки web страниц

Владимир | | htaccess, JavaScript, PHP, Web разработка.

Недавно я наткнулся на одну очень интересную тему для WordPressWP-Coda. Выглядит просто шикарно! Но дело не в этом.

Эта тема использует довольно много эффектов, реализованных с помощью JavaScript.

Мне стало интересно, во сколько эта красота обходится посетителям, и оказалось, что не так уж и дорого. Всего один js-файл размером 45кБ.

Дело в том, что автор упаковал семь исходных файлов в один и после этого сжал его упаковщиком вроде Packer JavaScript en PHP.

Но первый же эксперимент показал, что это не предел. Если упаковать этот файл в gzip архив, то его размер уменьшается до 21кБ. А большинство современных браузеров прекрасно работают с такими архивами.

При этом нет необходимости что-либо переделывать в самой теме.

Достаточно создать архив и положить его в одну папку с исходным файлом.

После этого в файл .htaccess добавляем правила:

<IfModule mod_rewrite.c>
	RewriteEngine On
	AddEncoding gzip .gz
	RewriteCond %{HTTP:Accept-encoding} gzip
	RewriteCond %{HTTP_USER_AGENT} !Safari
	RewriteCond %{REQUEST_FILENAME}.gz -f
	RewriteRule ^(.*)$ $1.gz [QSA,L]
</IfModule>

Работают эти правила так.
1) включаем RewriteEngine;
2) указываем, что файлы с расширением .gz имеют MIME тип gzip;
3) начинаем проверки:
3.1) если браузер принимает gzip;
3.2) если это не Safari (у него вроде есть проблемы с gzip);
3.3) если существует файл с таким же именем, как и у запрошенного, но с расширением .gz;
4) если все проверки прошли успешно, то добавляем к имени файла расширение .gz и отправляем этот файл браузеру.

Таким образом, если браузер не работает с gzip, то он получит исходный файл, если поддерживает – получит архив.

Посетитель разницы не заметит. Разве что немного увеличится время загрузки страницы.

В качестве примера, взгляните на скриншоты Firebug, сделанные для блога с темой WP-Coda.

Исходный вариант:

uncompressed javascript

После сжатия и установки правил в .htaccess:

compressed javascript

Кстати, заметьте, имя файла в обоих случаях одно и тоже. Изменяется только его размер. Т.е. браузер в обоих случаях считает, что получил файл, указанный в теге script (global.js), а сервер отправляет в первом случае global.js, а во втором — global.js.gz.

На мой взгляд, такой подход имеет только один недостаток. Во время разработки очень не удобно работать с одним большим js файлом, тем более сжатым 😉

Вручную упаковывать файлы тоже не интересно, поэтому нужно автоматизировать процесс.

Для этих целей я написал небольшой php скрипт.

//подключаем библиотеки
require_once 'libs/jsmin-1.1.1.php';

/**
 * Путь к папке со скриптами (отностильно этого скрипта)
 */
define('JS_DIR', "test_site/js/");

/**
 * Имя упакованного файла (будет размещен в папке со скриптами)
 */
define('JS_OUTPUT_FILE', 'global.js');

//определяем папку в которой находится скрипт
$scriptDir = substr($_SERVER['SCRIPT_FILENAME'], 0, strrpos($_SERVER['SCRIPT_FILENAME'], '/') + 1);

$resStr = "";

//открываем папку и получаем список файлов с расширением "js"
if ($dh = opendir($scriptDir.JS_DIR)) {
    while (false !== ($file = readdir($dh))) { 
        if ((substr($file, strrpos($file, '.') + 1) == "js") &&
        		($file != JS_OUTPUT_FILE)) {
        	$resStr .= "/*---------".$file."---------*/\n";
        	//сжимаем текущий файл
        	$resStr .= JSMin::minify(file_get_contents($scriptDir.JS_DIR.$file))."\n\n";
       	}
    }
    closedir($dh);
    //сохраняем сжатые данные в файл
    if ($fh = fopen($scriptDir.JS_DIR.JS_OUTPUT_FILE, 'w')) {
    	fwrite($fh, $resStr);
    	fclose($fh);
    }
    else {
    	echo "Ошибка: не могу открыть файл для записи: ".$scriptDir.JS_DIR.JS_OUTPUT_FILE;
    }
    
    echo "Скрипты упакованы файл: ".JS_DIR.JS_OUTPUT_FILE."<br />";

    //архивируем данные (используем самую высокую степень сжатия)
    $gzData = gzencode($resStr, 9);
    //создаем архив
    if ($fzip = fopen($scriptDir.JS_DIR.JS_OUTPUT_FILE.".gz", 'wb')) {
    	fwrite($fzip, $gzData);
    	fclose($fzip);
    }
    else {
    	echo "Ошибка: не могу открыть файл для записи: ".$scriptDir.JS_DIR.JS_OUTPUT_FILE.".gz";
    }
    
    echo "Создан архив: ".JS_DIR.JS_OUTPUT_FILE.".gz";
}
else {
	echo "Ошибка: не могу открыть папку со скриптами";
}

Принцип работы следующий. Вы указываете папку с js файлами (JS_DIR) и имя файла в который будут упакованы все скрипты (JS_OUTPUT_FILE).

Скрипт читает содержимое всех файлов с расширением js из папки и сжимает его.

Примечание. Для сжатия используется PHP версия библиотеки JSMin. Она просто удаляет пробелы и комментарии из исходных файлов.

После этого сжатые скрипты записываются в файл, указанный в JS_OUTPUT_FILE. Именно этот файл нужно подключать к вашим страницам.

Следующим этапом php скрипт создает архив (с помощью функции gzencode), который получает имя JS_OUTPUT_FILE.gz.

Для тестирования я взял библиотеку jQuery и написал js-файл с небольшой функцией, которая создавала пару эффектов.

Т.е. в исходном варианте было 2 файла:
jquery-1.2.3.js – 96кБ
script.js – 1кБ

Сжатый вариант:
global.js – 53,1кБ

Архивный вариант:
global.js.gz – 16кБ

Как видите, разница довольно ощутимая.

Если есть желание поэкспериментировать, качайте архив с скриптом и библиотекой JSMin.

До встречи!