3 августа 2008 в 17:43

Еще немного о сжатии

В этом топике я постараюсь обобщить материал про сжатие данных. Сжиматься будет css, js, html.

Объединение файлов в модули


Первым шагом к сжатию стало объединение css и js файлов в модули. Каждый модуль содержит список css и js файлов, а также модулей, которые необходимых для собственной работы. Эту информацию я решил хранить в конфиге приложения.
<units>
   <Jquery>
      <js>
         <file>cms/js/Jquery/Core.js</file>
         <file>cms/js/Jquery/Extens.js</file>
      </js>
   </Jquery>
   <Jquery.Facebox>
      <depend>
         <unit>Jquery</unit>
      </depend>
      <js>
         <file>cms/js/Jquery/Facebox.js</file>
         <file>cms/js/Jquery/Pngfix.js</file>
      </js>
      <css>
         <file>cms/js/Jquery/Facebox.css</file>
      </css>
   </Jquery.Facebox>
   <Cms.Core>
      <js>
         <file>cms/js/Cms/Core.js</file>
         <file>cms/js/Cms/Class.js</file>
      </js>
   </Cms.Core>
</units>
* This source code was highlighted with Source Code Highlighter.

Теперь подключить необходимые файлы очень просто. Для этого я написал класс, содержащий статический метод loadUnit(). В зависимости от настроек, он может подключать исходные файлы, либо сохранять их содержимое в один монолитный и подключать его.

Сжатие и минимизация


Я выбрал 3 пакера, указанных в приложении. Для сжатия написан класс, который в зависимости от настроек системы сжимает файлы определенным образом. Сжатию также подвергается HTML. Также, если в настройках включено gzip сжатие, файлы сжимаются методом gzencode().

Кэширование


Чтобы лишний раз не сжимать файлы, можно сохранять два варианта, обычный, и сжатый методом gzip. Эти файлы отдаются напрямую web-сервером, минуя PHP. Чтобы определить, поддерживает ли клиентский браузер сжатие, используем mod_rewrite.
RewriteCond %{HTTP:Accept-Encoding} gzip [OR]
RewriteCond %{HTTP:TE} gzip
RewriteCond %{HTTP_USER_AGENT} !Safari
RewriteCond %{HTTP_USER_AGENT} !Konqueror
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule ^pack\/(.*)$ /pack/$1.gz [QSA,L]

Если файла нет, перенаправляем запрос скрипту, который создает его, либо устанавливаем обработчик 404 ошибки.

Еще можно добавить…


Сжатие теряет смысл, если у пользователя стоит Outpost. Он автоматически режет заголовок Accept-Encoding, поэтому мы не можем узнать, можно ли отдавать сжатый файл. Эта опция Outpost выключается в реестре, но просить пользователя это сделать не целесообразно. Если пользователь пользуется оперой, то можно использовать заголовок TE, который аналогичен заголовку Accept-Encoding. Для других браузеров я нашел только одно решение – определять возможность сжатия по версии, но из-за неточности этого метода предпочел его не использовать.

HTML на статических сайтах можно кэшировать так же, как Java Script и CSS, отдавая web-сервером браузеру напряму. При изменении данных сбрасывать кэш. Но далеко не всегда на сайтах используется статический контент. Поэтому, приходится сжимать динамически, что не приемлемо на сайтах с высокой посещаемостью. Если на таких сайтах ведется статистика посещаемости, можно использовать эти данные и в часы с низкой нагрузкой отдавать сжатый HTML.

Если не хочется все самому писать и нет необходимости подгонять сжатие под конкретную систему, можно воспользоваться готовой библиотекой Minify.

Приложение


Функция сжатия html (взята с gadelkareem.com):
function htmlCompress($html)
{
   preg_match_all('!(<(?:code|pre|script).*>[^<]+</(?:code|pre|script)>)!',$html,$pre);
   $html = preg_replace('!<(?:code|pre).*>[^<]+</(?:code|pre)>!', '#pre#', $html);
   $html = preg_replace('#<!–[^\[].+–>#', '', $html);
   $html = preg_replace('/[\r\n\t]+/', ' ', $html);
   $html = preg_replace('/>[\s]+</', '><', $html);
   $html = preg_replace('/[\s]+/', ' ', $html);
   if (!empty($pre[0])) {
      foreach ($pre[0] as $tag) {
         $html = preg_replace('!#pre#!', $tag, $html,1);
      }
   }
   return $html;
}   
* This source code was highlighted with Source Code Highlighter.

Используемые минимизаторы:
Dean Edwards JavaScript's Packer
Скрипт сжатия CSS из библиотеки Minify

Ссылки по теме:
Сжатие css и js без потери производительности сервера
CSS: все о сжатии
Практический CSS/JS: архивируем все!
Алексей @megahertz
карма
26,1
рейтинг 0,0
fullstack
Самое читаемое Разработка

Комментарии (17)

  • +3
    читал уже довольно много о сжатии на хабре, но все равно думаю стоит сказать автору спасибо за статью =)
  • 0
    Очень полезная статья. На крупных сайтах нужно оптимизировать всё ;)
    • 0
      Оптимизировать нужно, но лучше делать правильную подачу информации, чтобы сначала грузилась нужная пользователю часть, а потом навигация, и реклама ну и т.д.
      • 0
        Вопрос может быть не только в удобстве для пользователя, но и в уменьшении исходяшего трафика с точки зрения сервера.
  • 0
    " я решил храню в конфиге"

    очепт
    • 0
      Спасибо
  • 0
    Че-то по ссылкам на минимизаторы 404...
    • 0
      хабраэффект о_О
    • 0
      там реферер видимо проверяется, поставил другую
  • 0
    Возможно, и эта ссылка покажется чуть полезной:
    http://www.ewgenij.net/javascript-and-css-compressor.html

    Если нет, то и суда нет :)
  • 0
    > RewriteCond %{HTTP_USER_AGENT} !Safari
    > RewriteCond %{HTTP_USER_AGENT} !Konqueror

    Можно поинтересоваться, почему Safari досталось вместе с Konqueror? Вроде он адекватно воспринимает сжатые данные?
    • 0
      Встречал эту информацию в некоторых источниках. Будет время, копну глубже
  • +1
    В функции сжатия html есть недоработки: не вырезается содержимое тегов textarea, при повторной вставке забыт тег script, плюс "жадный" регэксп может захватить лишнего.
    Это ведёт к тому, что содержимое страниц с js внутри может сжиматься некорректно, у меня так и произошло.

    Предлагаю свой вариант исправления (как замену первых двух строк функции htmlCompress()):

      preg_match_all('!(<(?:code|pre|textarea|script)[^>]+>.*?</(?:code|pre|textarea|script)>)!si',$html,$pre);
      $html = preg_replace('!<(?:code|pre|textarea|script)[^>]+>.*?</(?:code|pre|textarea|script)>!si', '#pre#', $html);


    * This source code was highlighted with Source Code Highlighter.
    • 0
      Спасибо. Вприцнипе, это первый попавшийся алгоритм. В отличие от пакеров я его пока особо не тестировал
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          Одно другому не мешает
          • НЛО прилетело и опубликовало эту надпись здесь

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.