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

    В этом топике я постараюсь обобщить материал про сжатие данных. Сжиматься будет 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: архивируем все!
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 17
    • +3
      читал уже довольно много о сжатии на хабре, но все равно думаю стоит сказать автору спасибо за статью =)
      • 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
                        Одно другому не мешает
                        • НЛО прилетело и опубликовало эту надпись здесь

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