Опубликован: 16.02.2009 | Уровень: специалист | Доступ: платный
Лекция 2:

Уменьшение размера

Проблемы для Safari

В ходе реализации данного решения возникла маленькая, но досадная неприятность. Safari не умеет правильно обрабатывать файлы с расширением .gz: для этого браузера стили и скрипты не могут иметь такого расширения. Как же нам быть? Выход достаточно простой и очевидный.

Нам нужно именовать все архивы стандартным образом, но при этом иметь неархивированную версию для обратной совместимости (например, с дополнительным суффиксом nogzip ). Поэтому для подготовки файлов нам будут нужны две команды ( jquery здесь используется только в качестве примера):

cp $src/jquery.js $dst/jquery.nogzip.js
gzip $dst/jquery.nogzip.js -9 –n -c > $dst/jquery.js

где $srcдиректория, в которой хранятся исходные файлы, а $dst — финальная директория для публикации. Сначала мы копируем файл в финальное место дислокации, а потом его архивируем под "правильным" именем.

Конфигурируем Apache

Тесты под Konqueror показали, что этот браузер не понимает архивированных файлов (CSS и JavaScript), поэтому чтобы уберечь десятую долю процента посетителей от сердечного приступа (когда они увидят сайт без соответствующих стилей), стоит добавить его в этот набор правил. Аналогично и "старым" браузерам (которые явно указывают, что не понимают архивов) отдается неархивированное содержание.

<IfModule mod_rewrite.c>
	RewriteEngine On
#перенаправляем Konqueror и "старые браузеры"
	RewriteCond %{http:Accept-encoding} !gzip [OR]
	RewriteCond %{http_USER_AGENT} Konqueror
	RewriteRule ^(.*)\.(css|js)$ $1.nogzip.$2 [QSA,L]
</IfModule>

Вся вышеуказанная конструкция "обернута" условием наличия на сервере подключенного mod_rewrite. Если он отсутствует, то это сразу станет видно на заявленных браузерах (перестанут отображаться стили и отрабатывать скрипты). Иначе Apache просто не сможет запуститься, т. к. RewriteEngine не будет объявлен.Дополнительно к заявленной логике необходимо выставить ряд заголовков для отдаваемых файлов. В частности, Vary и Cache-control касаются локальных проксирующих серверов, которые не должны кэшировать эти файлы, а пропускать их дальше к пользователю, не обрезая при этом заголовок User-Agent (иначе наш сервер никак не узнает, можно ли отдавать архивированную копию файла или нет).

<IfModule mod_headers.c>
	Header append Vary User-Agent
#выставляем для всех css/js-файлов Content-Encoding
 <FilesMatch .*\.(js|css)$>
	Header set Content-Encoding: gzip
	Header set Cache-control: private
 </FilesMatch>
#сбрасываем Content-Encoding в том случае, если отдаем не архив
 <FilesMatch .*\.nogzip\.(js|css)$>
	Header unset Content-Encoding
 </FilesMatch>
</IfModule>

В итоге для всех файлов, которые мы отдаем как архивы, дополнительно объявляется Content-Encoding, а для их неархивированных копий этот заголовок сбрасывается. Чем и достигается полная работоспособность данного решения.

Маленькие "но"

Единственное неудобство, которое может возникнуть: нужно иметь в разработке нормальные версии, а при публикации всех изменений — их архивировать и переименовывать. При промышленном подходе к разработке все эти действия автоматизируются, а при кустарном — трудозатраты не так существенны по сравнению с увеличением скорости загрузки сайта (если, конечно, не собирать проект прямо на боевом сайте, без конца архивируя один и тот же файл).

Итак, финальный алгоритм действий (при наличии на сервере mod_headers ; иначе лучше воспользоваться конфигурацией, приведенной в восьмой главе) должен быть следующим:

  1. Добавляем описанные выше инструкции (оба блока) в конфигурационный файл Apache или . htaccess.
  2. Пакуем файлы (с помощью 7-zip или gzip ) и кладем на место обычных (расширение у файлов должно остаться прежним, .css или .js ). Например, если у нас есть файл anyname.css, то после упаковки получается файл anyname.css.gz ; переименовываем его обратно в anyname.css и заливаем на сервер. Для gzip все немного проще:
    gzip -c -9 -n anyname.css > anyname.css.gz
    mv anyname.css anyname.nogzip.css
    mv anyname.css.gz anyname.css
  3. Рядом с сжатыми файлами кладутся файлы с расширением nogzip.css или nogzip.js, которые содержат неархивированные копии. Например, после заливки сжатого файла anyname.css нужно создать на сервере еще один файл anyname.nogzip.css, который является копией несжатого файла. Для gzip это копирование уже производится чуть выше второй строкой в листинге.

Два слова о nginx

Кто работал с этим сервером, наверное, уже подумали: есть же модуль ngx_http_gzip_static_module, который позволяет класть рядом с файлом его сжатую версию с дополнительным расширением . gz и забыть практически обо всех описанных проблемах (этот функционал присутствует и для Apache 1.3). К сожалению, минусом данного решения будет отключение сжатия для всех видов файлов у браузера, который не поддерживает хотя бы один (теряется гибкость настройки).

Однако, на данный момент таких случаев — доли процента, поэтому если у нас проект с низкой или средней посещаемостью, указанный модуль (в совокупности с ngx_http_gzip_module ) позволит преодолеть почти все "подводные камни". Подробная конфигурация для nginx и Apache приведена в восьмой главе.

В третьей главе рассказывается, как данное решение можно расширить для сброса кэша на клиенте. Теперь же перейдем к более подробному рассмотрению методов сжатия CSS- и JavaScript-файлов — ведь это может быть не только архивирование.

Все о сжатии CSS

Проблема уменьшения CSS-файлов в размере действительно актуальна, и хотелось бы иметь результаты исследования конкретно для такой оптимизации. Они, собственно, и приведены ниже.

В Интернете было найдено 5 различных инструментов для минимизации CSS-кода; далее ими обрабатывались несколько примеров, которые затем подвергались еще и архивированию. Результаты представлены в виде графиков.

Инструменты

  • CSSMin (http://code.google.com/p/cssmin/). Библиотека проводит набор простейших замен в CSS-файле (удаляет ненужные символы) и склеивает его в одну строку.
  • Minify (http://code.google.com/p/minify/) . Библиотека, минимизирующая как CSS-, так и JS-файлы. Кроме того, она может склеивать несколько файлов в один, заменять относительные пути к фоновым картинкам на более короткие и самостоятельно отдавать кэширующие заголовки. В общем, намного лучше предыдущей.
  • YUI (http://developer.yahoo.com/yui/compressor/). YUI-compressor (использовалась версия 2.2.5). Фактически, делает то же самое, что две предыдущих библиотеки.
  • CSS Minifier (http://www.artofscaling.com/css-minifier/). Автор разработал собственный алгоритм сжатия (после беглого анализа это оказалась несколько переработанная версия CSS Tidy), который, по его собственному утверждению, "жмет лучше всех". Это мы и проверим чуть дальше.
  • CSS Tidy (http://csstidy.sourceforge.net/). Проект по минимизации CSS-файлов с открытым исходным кодом. Имеет много настроек, перенесен на несколько языков и используется на нескольких ресурсах, которые предлагают инструментарий для минимизации CSS-файлов, например, на http://www.codebeautifier.com Это наиболее широко распространенная версия минимизатора.

В качестве исходных файлов брались таблицы стилей с некоторых достаточно активно посещаемых ресурсов. Каждый из них был подвергнут действию минимизатора (для Minifier дополнительно файл склеивался в одну строку; вероятно, это временный баг текущей версии), затем архивировался. Корректность минимизации не проверялась (с этим в некоторых особо агрессивных случаях могут быть проблемы: CSS Tidy с определенными настройками перегруппировывает селекторы, и часть логики теряется).

Графические результаты

Что изображено на графиках? Выведен выигрыш (в процентах) относительно несжатого файла (по оси ординат отложены проценты). По оси абсцисс отложены номера файлов. Данные упорядочены по общей степени сжатия. Вначале по каждому инструменту — отдельный график: выведены показатели для простой минимизации файлов, а также для минимизации с последующим архивированием. Серая линия на графике показывает степень сжатия (в процентах) файла при помощи простого gzip. Все инструменты приведены на одном графике (без архивирования). Действительно, заметен явный выигрыш для Minifier.

 Эффективность различных инструментов для минимизации CSS-файлов по сравнению с gzip

Рис. 2.7. Эффективность различных инструментов для минимизации CSS-файлов по сравнению с gzip

При архивировании, однако, все минимизаторы ведут себя примерно одинаково.

 Эффективность различных инструментов для минимизации CSS-файлов вместе с дополнительным архивированием по сравнению с gzip

Рис. 2.8. Эффективность различных инструментов для минимизации CSS-файлов вместе с дополнительным архивированием по сравнению с gzip

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

 Эффективность различных инструментов для минимизации CSS-файлов вместе с дополнительным архивированием (увеличенный масштаб)

Рис. 2.9. Эффективность различных инструментов для минимизации CSS-файлов вместе с дополнительным архивированием (увеличенный масштаб)

Тут уже видно отчетливо, что CSS Tidy ведет себя в целом лучше остальных скриптов (хотя, за исключением редких случаев, выигрыш не превосходит 6% относительно обычного архивирования).

Дарья Билялова
Дарья Билялова
Россия
Елена Петрушевская
Елена Петрушевская
Россия, г. Нижневартовск