Соединение JS и CSS между собой

Объединение CSS и JS файлов в один при помощи магии

Финальный этап. Мы собираемся сцепить все JS и CSS файлы в один итоговый большой файл. Как такое возможно? Спросите вы.
Многие могут подумать, что автор просто спятил и пытается реализовать не реализуемое. Ну зачем ему понадобилось сливать эти 2 файла в один?
А я вам скажу, что эта реализация будет экономить вам еще один коннект при загрузке вашего сайта на каждый логический модуль. Более того, вам больше не придется прописывать каждый раз в исходном файле линк на css файл и вспоминать, был ли он, а также переживать, что клиент может недополучить стили. В итоге мы получим единый компонент, который зашит в одном единственном файле и нам не нужно больше думать о том, все ли у клиента заработало.

Погодите. Но если стили запихнуть в скрипт - как их отлаживать? Как найти строку с ошибкой? На это есть веб-инспекторы, которые также показывают все стили загруженные inline.
Так в чем задумка - спросите вы? Все элементарно. В конце исполнения JS файла - мы просто допишем строку

document.write('<style>...</style>');

где и перечислим все наши стили. Проще некуда.
Сразу отмечу, что если в скрипте - от пользователя при загрузке что-то требуется, например alert высвечивается - заключите его в тег

$(function(){
alert('...');
})

, чтобы он сработал после полной загрузки страницы и пользователь увидел его после установки стилей.
Да, а как же поисковики? Скажите вы. И возможно, будете правы. Поисковики же оценивают стили, не совпадает ли фон с текстом и т.д. не факт, что они прочтут скрипты и могут расценить это как подмену стилей. Да, базовые стили рекомендуется оставлять в отдельных файлах. Речь идет скорее о компонентах. Поставили вы fancybox, prism.js, lazy-load. Все стили - идут как дополнение к основному, тем более не выводятся пользователю сразу же. По этому - базовые CSS стили мы оставляем на месте.
А что, если у пользователя отключен яваскрипт? Тогда он не увидит эти стили, собственно, как и сам яваскрипт. Компонент все равно не будет загружен, какой смысл грузить CSS для него.
Метод подойдет, если приложение не зависит от поисковиков. Поисковики в наше время стали слишком требовательные. Если сайту нечего терять, или мы создаем веб-приложение, которое поисковикам будет не ведомо - сам бог нам велел экономить еще одно соединение.
Эта реализация работает во всех браузерах. Другой вопрос - как мы программно встроим все это в наш уже созданный скрипт для сжатия JS и CSS. Если вы не читали прошлых статей этой серии - рекомендую ознакомится, чтобы не было вопросов по ранее полученным частям кода.
Вы скажете, что давайте тогда еще и все стили и скрипты включим просто в тело каждой страницы. А вот это уже перебор, скажу я вам) Скрипты хранятся в сжатом виде, динамические страницы же - нам придется сжимать со скриптами (не малыми) вместе каждый раз. Либо это приведет к большой нагрузки, либо к хранению больших кусков кеша на диске. Нет, это перебор. Цель данного метода - упростить себе жизнь при подключении стилей отдельных компонентов.
Вы ведь знаете, что GZIP сжатие эффективно на больших файлах (теперь уже точно знаете :) ). На файлах меньше 10кб - оно практически не ощутимо. По этому - метод также сэкономит загружаемые байты и трафик при частой загрузке.
Если вы плотно использовали ранее полученные скрипты для сжатия — вы наверняка заметили там пару недостатков. Наверняка у вас были проблемы с включением шрифтов, т. к.  скрипт ищет любые совпадения с url и заменяет их тоже. Наверняка вы замечались, удаляя кавычки в url(). Плюс ко всему модификатор e регулярного выражения немного устарел, его сейчас рекомендуется заменять функцией preg_replace_callback. Так давайте сразу все эти недостатки и исправим
Мы поставили подгрузку только gif и png файлов, т. к. Jpg – обычно часто являются большими фоновыми изображениями и есть резон подключить их загрузку старым образом. Если хотите — можете дописать все расширения, как вам будет удобнее.
Предлагаю заключительную часть скрипта для минимизации CSS

<?php
error_reporting(E_ALL);
if ($handle=opendir('.')){
  while(false !== ($file=readdir($handle))){
    if ($file == '.' or $file == '..' or is_dir($file)) continue;
    if (substr($file,-4) != '.css') continue;
    if (substr($file,-7) == '.p2.css') continue;
    if (substr($file,-7) == '.p3.css') continue;
    echo $file;
    $filename=substr($file,0,-4);
    $css=file_get_contents($file);
    if (file_exists($filename.'.p2.css'))$css.="\n".file_get_contents($filename.'.p2.css');
    if (file_exists($filename.'.p3.css'))$css.="\n".file_get_contents($filename.'.p3.css');
    $filepart=explode('/****IMAGES****/',$css);
    if (isset($filepart[1]))file_put_contents($filename.'_ie.cssgz',gzencode(compress($filepart[1]),9));
    $csscompress=compress($css);
    $cssimages=addimages($csscompress);
    file_put_contents($filename.'.cssgz',gzencode($cssimages,9));
  }
  closedir($handle);
}
function compress($buffer){
  $buffer=preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!','',$buffer);
  $buffer=preg_replace('/\s\s+/', ' ', $buffer);
  return str_replace(array("\r\n","\r","\n","\t"),'',$buffer);
}
function to_pic($matches){
  if (strtolower(substr($matches[1],0,4))!='http'){
    if (!file_exists($matches[1])){
      echo 'file '.$matches[1].' dont exists<br>';
      return $matches[0]; 
    }
  }
  return "url(data:image/".$matches[2].";base64,".base64_encode(file_get_contents($matches[1])).')';
}
function addimages($buffer){
  return preg_replace_callback('/url\([\'"]?([\w\:\-\/\.]*\.(png|gif))[\'"]?\)/iuU','to_pic',$buffer);
}

А теперь ближе к делу. Мы получили качественные CSS файлы. Как же их подгрузить в Javascript? Чтобы не создавать путаницы и качественно управлять включением и отключением стилей, которые нужно включить в скрипты — создадим для себя правило. Если файл стилей совпадает с названием скрипта и оканчивается на .js.cssgz – автоматически включать его в конец нашего скрипта.
Например:
скрипт называется jquery.fancybox.js
Чтобы подцепить к нему соответствующий стиль — переименуем файл стилей в jquery.fancybox.js.css
После обработки и сжатия — файл будет называться jquery.fancybox.js.cssgz и именно его будет искать наш второй обработчик — для яваскриптов.
Да, теперь нам надо после малейшей правки — запускать сразу 2 скрипта последовательно, сначала стили, затем скрипты. Но это не проблема, т. к. предполагается использовать такую модификацию только на продакшене, либо только после того как скрипты окончательно отлажены. Занимайтесь отладкой на исходных js и css файлах.
На последок остается еще одна небольшая проблема. Для старых браузеров — у нас создавался отдельный файл с прямыми ссылками на изображения. Файл небольшой, но в случае старого браузера — имеет смысл его тоже подгрузить. По логике — схема остается прежней, но в случае, если браузер ниже IE9 – желательно подтягивать и этот файл. Новый jquery не позволяет определить версию браузера, для простоты решения — мы можем сослаться на версию Jquery. Замечу, что для всех новых браузеров — мы грузим версию Jquery 2, по этому мы можем в зависимости от мажорной версии — заставлять скрипт загружаться. Вы можете использовать свое решение, если вам такое не подходит. Полный текст скрипта для сжатия яваскриптов - приведен ниже:

<?php
error_reporting(E_ALL);
require '../jsmin.php';
if ($handle=opendir('.')){
  while(false !== ($file=readdir($handle))){
    if ($file == '.' or $file == '..' or is_dir($file)) continue;
    if (substr($file,-3) != '.js') continue;
    if (substr($file,-6) == '.p2.js') continue;
    if (substr($file,-6) == '.p3.js') continue;
    echo $file;
    $filename=substr($file,0,-3);
    $js=file_get_contents($file);
    if (file_exists($filename.'.p2.js'))$js.="\n".file_get_contents($filename.'.p2.js');
    if (file_exists($filename.'.p3.js'))$js.="\n".file_get_contents($filename.'.p3.js');
    if 
(file_exists('../css/'.$filename.'.js.cssgz'))$js.="\ndocument.write(\"<style>".str_replace('"','\"',gzdecode(file_get_contents('../css/'.$filename.'.js.cssgz')))."</style>\");";
    if (file_exists('../css/'.$filename.'.js_ie.cssgz'))$js.="\nif 
(jQuery.fn.jquery[0]==1){document.write(\"<style>".str_replace('"','\"',gzdecode(file_get_contents('../css/'.$filename.'.js_ie.cssgz')))."</style>\");};";
    $jscompress=JSMin::minify($js);
    file_put_contents($filename.'.jsgz',gzencode($jscompress,9));
  }
  closedir($handle);
}

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

  • Автор: kosmom
  • Рейтинг: 0
  • Просмотров: 717
  • Комментариев: 0
  • Создан: 31.03.2014 15:01

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