Оптимизация JavaScript и CSS-файлов в Drupal

С чего начинается сайт?

  • Для браузера сайт начинается с GET-запроса страницы.
  • Сервер на этот запрос высылает HTML-код страницы.
  • Браузер разбирает код и начинает загрузку всех внешних файлов (JS, CSS, Flash и др.) в порядке их следования в коде.
  • Обычно браузер использует не более 2х потоков для загрузки внешних файлов, а CSS и JS загружаются вообще в одном потоке.
  • Время на каждый запрос зависит от размера возвращаемого ответа, загрузки сервера и активности на каждой машине на всем пути между браузером и сервером.
  • Чем больше размер файла - тем дольше он будет доставляться браузеру.
  • Чем больше количество файлов - тем дольше будет загружаться вся страница.

Как браузер рендерит страницу?

До момента полной загрузки JS из HEAD пользователь видит "белую страницу". Когда все внешние скрипты загружены, начинается выполение JS в порядке следования на странице (сверху вниз), а пользователь уже начинает видеть контент страницы, и по мере загрузки CSS и картинок, страница отрисовывается полностью.

Таким образом, чтобы увеличить скорость загрузки страницы нужно:

  • Уменьшить размеры скриптов дабы ускорить первичный отклик страницы
  • Уменьшить количество файлов (картинки объединяются в спрайты, а JS и CSS аггрегируются)
  • Использовать HTTP-сжатие
  • Увеличить количество хостов, с которых загружается статика сайта, чтобы браузер мог увеличить лимит одновременных соединений
  • Поместить JavaScript в footer страницы, чтобы они загружались последними, а пользователь мог уже пользоваться страницей.

Оптимизация графики и создание спрайтов - работа для дизайнера, а мы займемся оптимизацией JavaScript и CSS-файлов в Drupal.

Давайте посмотрим как обстоят дела с этими файлами в Drupal.

Анализ ситуации
JavaScript
В вашем проекте количество и суммарный размер будет другой.

Pазмер ваших JS-файлов вы можете сами проверить командой:

find . -name '*.js' -exec ls -l {} \; | awk '{s+=$5} END {print s}'

В нашем проекте, кроме файлов ядра, есть ещё более 1300(!) JS-файлов, которые находятся в дополнительных модуляx и темах.

Общий размер всех JS-файлов - 14'746'899 байт.

В ядре Drupal 6 я нашел следующие Javascript-файлы:

  1. modules/comment/comment.js
  2. modules/profile/profile.js
  3. modules/openid/openid.js
  4. modules/taxonomy/taxonomy.js
  5. modules/system/system.js
  6. modules/block/block.js
  7. modules/color/color.js
  8. modules/user/user.js
  9. misc/autocomplete.js
  10. misc/drupal.js
  11. misc/collapse.js
  12. misc/batch.js
  13. misc/farbtastic/farbtastic.js
  14. misc/form.js
  15. misc/tableselect.js
  16. misc/ahah.js
  17. misc/tabledrag.js
  18. misc/textarea.js
  19. misc/progress.js
  20. misc/tableheader.js
  21. misc/teaser.js
  22. misc/jquery.form.js
  23. misc/jquery.js

Хорошо, что они не все загрузаются на одной странице, а некоторые вообще не используются. На совести разработчика модуля правильно настроить условия подключения JS и CSS-файлов на странице, чтобы бесполезный код не уменьшал скорость загрузки страницы.

CSS-файлы
В вашем проекте количество и суммарный размер будет другой.

Команда для самостоятельной проверки размера CSS файлов:

find . -name '*.css' -exec ls -l {} \; | awk '{s+=$5} END {print s}'

В нашем проекте, кроме файлов ядра, есть ещё около 450-ти в дополнительных модулях и темах.

Общий размер всех CSS-файлов - 1'674'793 байт.

Что касается CSS-файлов в ядре Drupal 6, то вот они:

  1. modules/locale/locale.css
  2. modules/aggregator/aggregator-rtl.css
  3. modules/aggregator/aggregator.css
  4. modules/update/update.css
  5. modules/update/update-rtl.css
  6. modules/poll/poll.css
  7. modules/poll/poll-rtl.css
  8. modules/comment/comment-rtl.css
  9. modules/comment/comment.css
  10. modules/tracker/tracker.css
  11. modules/forum/forum-rtl.css
  12. modules/forum/forum.css
  13. modules/book/book.css
  14. modules/book/book-rtl.css
  15. modules/profile/profile.css
  16. modules/search/search-rtl.css
  17. modules/search/search.css
  18. modules/openid/openid.css
  19. modules/node/node-rtl.css
  20. modules/node/node.css
  21. modules/taxonomy/taxonomy.css
  22. modules/system/system-menus-rtl.css
  23. modules/system/admin-rtl.css
  24. modules/system/admin.css
  25. modules/system/maintenance.css
  26. modules/system/defaults-rtl.css
  27. modules/system/defaults.css
  28. modules/system/system-rtl.css
  29. modules/system/system-menus.css
  30. modules/system/system.css
  31. modules/block/block.css
  32. modules/color/color.css
  33. modules/color/color-rtl.css
  34. modules/help/help.css
  35. modules/help/help-rtl.css
  36. modules/dblog/dblog.css
  37. modules/dblog/dblog-rtl.css
  38. modules/user/user.css
  39. modules/user/user-rtl.css
  40. misc/print-rtl.css
  41. misc/farbtastic/farbtastic.css
  42. misc/print.css
  43. themes/bluemarine/style.css
  44. themes/bluemarine/style-rtl.css
  45. themes/garland/print.css
  46. themes/garland/style.css
  47. themes/garland/minnelli/minnelli.css
  48. themes/garland/color/preview.css
  49. themes/garland/style-rtl.css
  50. themes/garland/fix-ie.css
  51. themes/garland/fix-ie-rtl.css
  52. themes/pushbutton/style.css
  53. themes/pushbutton/style-rtl.css
  54. themes/chameleon/common-rtl.css
  55. themes/chameleon/style.css
  56. themes/chameleon/marvin/style.css
  57. themes/chameleon/marvin/style-rtl.css
  58. themes/chameleon/common.css
  59. themes/chameleon/style-rtl.css

Суммарный размер CSS-файлов на порядок меньше, чем размер JS-файлов. Но нужно учесть, что CSS-файлов на странице намного больше, чем JS-файлов - примерно в 2 раза больше. Кроме того, стили, как правило, загружаются для всех страниц (это стили темы) и только стили модулей могут загружаться для определённых страниц. Таким образом и файлы стилей, и скрипты нуждаются в нашем внимании в одинаковой степени.

Ограниченный Internet Explorer

Браузер IE 6-8 имеет ограничение на количество и размер CSS-файлов:

  • Все теги добавления стилей после первых 31 тегов игнорируются.
  • Все CSS-правила после первых 4,095 правил игнорируются.
  • На страницах, которые используют правило @import для импорта внешних таблиц стилей, которые импортируют другие внешние таблицы стилей, таблицы стилей с уровнем вложенности больше 3 - игнорируются.

Ограничение протокола HTTP

Интересно есть ли у браузеров ограничение на количество АJAX-соединений?

Согласно спецификации HTTP 1.1 браузер должен устанавливать не более 2 одновременных соединений (и это справедливао для IE6/7) к одному хосту. В Firefox и Opera этот параметр настраиваемый и составляет не меньше 4 по умолчанию. По некоторым данным в IE8 - 6 соединений с одним хостом.

Источник информации: Raising network.http.max-persistent-connections-per-server?

  • Firefox 2: 2
  • Firefox 3 beta 4: 4
  • Opera 9.26: 4
  • Opera 9.5 beta: 4
  • Safari 3.0.4 Mac/Windows: 4
  • IE 7: 2
  • IE 8: 6

Итог анализа

  • Большинство JS и CSS-файлов не оптимизированы.
  • Файлов много и их суммарные размеры значительны.
  • Имеем проблемы с браузером IE, который ограничивает количество CSS-файлов на странице.
  • Проблемы со скоростью загрузки страницы из-за большого количества внешних файлов и ограничение браузеров на количество одновременных соединений с сервером.

Разберемся с терминологией.

Виды оптимизации

Минимизация скрипта — это удаление из кода всех несущественных символов с целью уменьшения объема файла скрипта и ускорения его загрузки. В минимизированном коде удаляются все комментарии и незначащие пробелы, переносы строк, символы табуляции. В случае с JavaScript, это уменьшает время загрузки страницы, так как размер файла уменьшается. Две самых популярных утилиты для минимизации JavaScript — JSMin и YUI Compressor.

Обфускация является альтернативным способом сокращения исходного кода. Также, как минимизация, она удаляет пробельные символы и вырезает комментарии, но в дополнение она измененяет сам код. К примеру, во время обфускации имена функций и переменных заменяются на более короткие, что делает код более компактным, но менее читабельным. Обычно этот прием используется для усложнения реверс-инжиниринга программы. Но обфускация помогает также уменьшить код настолько, насколько это не получится сделать одной минимизацией. С выбором средства для обфускации JavaScript не все так ясно, но я думаю, что самая распространенная утилита для этого — Dojo Compressor (ShrinkSafe).

Минимизация JavaScript — безопасный и довольно простой процесс. С другой стороны, обфускация из-за своей сложности может вносить в код ошибки. Обфускация также требует правки вашего кода для выделения в нем API-функций и других элементов, которые не должны быть изменены.

Аггрегация - это объединение нескольких файлов на странице в один. Аггрегация безопасна также как и минимизация, потому что код не меняется. Иногда "склейка" файлов может давать сбой из-за некорректных комментариев в конце файлов. Аггрегация позволяет уменьшить количество файлов подключаемых на странице. Начиная с Drupal 6 аггрегация CSS и JS-файлов встроена в ядро, а до этой версии нужно было установить дополнительный модуль.

HTTP-cжатие - это способ сжать контент (в основном текстовый), который передается с веб-серверов через интернет в браузеры. Основное преимущество сжатия в том, что уменьшается количество байт, которые передаются и таким образом достигается большая производительность. HTTP-сжатие использует общедоступные алгоритмы сжатия, чтобы кодировать HTML, XML, JavaScript, CSS и другие форматы файлов на стороне сервера. Этот метод доставки сжатого контента основан на стандартах и включен в HTTP/1.1 и все современные браузеры поддерживают протокол HTTP/1.1. Таким образом они могут распаковывать сжатые файлы автоматически на стороне клиента. Это означает, что никакого дополнительного ПО или участия пользователя на стороне клиента не нужно.

Запрос на сервер без использования сжатия

Запрос на сервер и сервер отдает сжатый контент

Для каскадных таблиц стилей можно применять только минимизацию, аггрегацию и HTTP-сжатие. Обфускация для CSS-файлов не используется. А вот для JavaScript-файлов любой из методов подходит.

Обзор существующих Javascript-компрессоров.

Сравнить степень сжатия одного и того же файла можно с помощью онлайн-сервиса: JavaScript Compressor and Comparison Utility.

  • JSMin - традиционный компрессор, написанный несколько лет назад Дугласом Крокфордом (Douglas Crockford). Утилита безопасна (особенно, если вы перед использованием проверили ваш код с помощью JSLint), потому что утилита не пытается изменять имена переменных.
  • Dojo shrinksafe - это очень популярный JavaScript компрессор, написанный на Java. Он парсит кода используя библиотеку rhino и изменяет имена локальных переменных.
  • Packer написан Дином Эдвардсом (Dean Edwards). Ещё один очень популярный JavaScript компрессор, который может ещё больше обычного сжатия и также добавляет распаковку "на лету" во время выполнения JavaScript.
  • YUI Compressor - это новыейший компрессор, написанный Люлиен Лекомт (Julien Lecomte), который ставит своей целью объединить безопасность JSMin с высочайшим уровнем сжатия, который достигается Dojo Shrinksafe. Подобно Dojo shrinksafe, он написан на Java и основан на библиотеке rhino.

Степень сжатия у всех компрессоров разная, потому как и методы сжатия тоже разные. Сжатие маленьких файлов, как правило, дает очень незначительное сжатие, а файлы больше 10Кбайт сжимаются очень хорошо. На диаграмме ниже показана зависимость степени сжатия от размера файла:

Подробности тестирования степени сжания разными компрессорами -- в статье JavaScript: жать или не жать?. Использована диаграмма из этой статьи.

Варианты решения проблемы

Итак, у нас есть достаточно большое количество файлов, которые можно сжать и нам нужно разобраться с тем, что Drupal уже может нам предложить (в ядре и в дополнительных модулях) и найти наиболее оптимальное решение.

Начнем с анализа того, что мы уже имеем "из коробки".

Стандартные возможности Drupal

В ядре Drupal 6 реализованы аггрегация JavaScript и СSS-файлов и HTTP-сжатие.

На странице "Performance" ("Производительность" - admin/settings/performance) есть возможность включить/выключить оптимизацию CSS и JavaScript файлов:

Если оптимизация CSS и JS-файлов заблокирована - это значит, что кеш аггрегированных файлов не удается записать в файлы. Проверьте верно ли указан путь к папке files и права записи для этой папки на странице File System (Файловая система - admin/settings/file-system).

Как работает оптимизация JS и CSS-файлов в ядре Drupal?

Чтобы начать пользоваться этой возможностью - нужно включить оптимизацию JavaScript или CSS-файлов на странице настройки производительности.

Тогда во время темизации страницы из функции template_preprocess_page() будет вызвана фукнция drupal_get_css(). Именно эта функция и делает основную работу для CSS-файлов.

Как работает функция drupal_get_css()?

  • Оптимизация CSS не делается, когда сайт находится в режиме Maintenance ("Обслуживание") или запущено обновление (update.php).
  • К оптимизированным файлам добавляется строка в виде параметра, которая позволяет контролировать кеширование файлов браузером. Когда запускается update.php или делается полный сброс кеша, - меняется эта строка, что заставляет браузеры перезагрузить новые версии файлов, так как они считают, что URL изменился.
  • Будет ли файл участвовать в оптимизации решает 4й аргумент функции drupal_add_css() - $preprocess, который определяет будет ли данный файл участвовать в оптимизации, если она будет включена. По умолчанию файл будет участвовать в оптимизации.
  • Сначала формируется 2 списка файлов, которые не участвуют в оптимизации CSS - отдельно (1) для модулей и отдельно (2) для тем.
  • Далее создается имя файла, который будет хранить оптимизированный CSS и вызывается функция drupal_build_css_cache(), которая аггрегирует и оптимизирует CSS файлы.
  • Полученный файл сохраняется в папке sites/default/files/css (в мультисайтовой установке будет другой путь, но,- я думаю,- что вы и сами знаете где они будут сохраняться).

Что в себя включает оптимизация?

  • Все @import инструкции проходят обработку в drupal_load_stylesheet() и заменяются контентом файла, который должен был импортироваться.
  • Находятся все комментарии с одиночными и двойными кaвычками и отправляются на обработку в функцию _process_comment(), которая пытается определить можно ли этот комментарий удалить или это хак для IE-Mac.
  • Удаляются пробелы вокруг разделителей, но сохраняются вокруг круглых скобок.

Итак, оптимизация, которую нам предлагает ядро Drupal является на самом деле минимизацией с аггрегацией в один файл.

Недостатки метода оптимизации в ядре Drupal

Метод оптимизации, который используется в ядре Drupal безопасен, то есть он не приводит к ошибкам в коде. Но метод не настолько эффективен, как кажется.

Дело в том, что на странице может быть десятка 2 разных скриптов, которые собираются в уникальный файл, который для данной страницы кешируется. Скрипты на странице могут подгружаться в зависимости от прав доступа пользователя или ещё каких-либо условий, что увеличивает количество вариантов для одной-единственной страницы.



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

Оптимизация JavaScript в ядре Drupal

Оптимизация JavaScript делается подобно оптимизации CSS-файлов.

Именно такой способ склейки может породить ошибки в аггрегированном файле, когда в конце скрипта последней строкой был комментарий.

При оптимизации JavaScript-файлов они объединяются в один большой файл несколько иначе - после каждого файла добавляется ";\n".

Сам код JS-файла никак не изменяется - это можно увидеть в коде функции drupal_build_js_cache(), а просто объединяется в один большой файл.

То есть ядро Drupal не делает даже минимизации JavaScript!

Использование HTTP-сжатия

На странице настройки производительности ("Perfomance") можно включать и выключать HTTP-сжатие:

Фукнция page_set_cache() сохраняет сжатый контент страницы в кеше, если:

  • Если выбрано использование сжатия трафика на странице настройки производительности,
  • Расширение PHP zlib ) присутствует в системе,

Drupal кеширует контент страницы, а при выполнении условий, указанных выше, сжимает и затем кеширует контент страницы..

Если браузер поддерживает HTTP-сжатие, то в запросе страницы он указывает с какими видами сжатия он умеет работать:

Accept-Encoding: gzip,deflate

A simple online web page compression / deflate / gzip test tool - сервис, который проверяет отдает ли сервер файл с использованием HTTP-сжатия и степень сжатия.

Если сервер использует HTTP-сжатие, то он будет сам сжимать и отдавать браузеру сжатую версию контента.

Но Drupal может и сам при наличии библиотеки zlib сжимать и кешировать уже сжатую версию HTML-страницы, но не JS и не CSS-файлы.

Это значит, что если веб-сервер настроен сжимать контент и браузер поддерживает такое сжатие, то сервер будет "на лету" сжимать JS и CSS-файлы. Но намного эффективнее было бы хранить сжатые копии этих файлов с максимально большой степенью сжатия, а не сжимать их "на лету" (в этом случае по умолчанию используется не максимальная степень сжатия).

Дополнительные модули
Модуль JavaScript Aggregator

Модуль делает минимизацию JS-файлов, используя JSMin

Модуль может сжимать аггрегированные и минимизированные JS-файлы, используя gzip-сжатие. Сжатая копия хранится в файле на сервере и отдается браузеру вместо того, чтобы веб-сервер сжимал этот файл самостоятельно.

Пример сжатия:

FILENAME SIZE DESCRIPTION
6e13ccb6262e06b9f890414db56d3b1f.js 289.558 Bytes > Aggregated by Drupal Core
6e13ccb6262e06b9f890414db56d3b1f.jsmin.js 173.243 Bytes > Minified with JSMin
6e13ccb6262e06b9f890414db56d3b1f.jsmin.js.gz 47.618 Bytes > Minified and gzipped

Модуль CSS Gzip

  • Модуль сжимает аггрегированные CSS-файлы, как это делает с JS-файлами модуль Javascript Aggregator.
  • Сжимает контент один раз и сохраняет результат -- это уменьшает нагрузку на процессор сервера.
  • Использует 9й уровень сжатия так как это нужно сделать только 1 раз для каждого файла, что дает меньший размер файла.
  • Требует включенные "Чистые ссылки" (mod_rewrite).
  • Требует, чтобы метод скачивания был "Публичный" (см admin/settings/file-system).
  • Вошел в ядро Drupal 7.

Модуль Parallel

  • Позволяет браузеру параллельно загружать внешние файлы страницы.
  • Для этого создается 3 новых поддомена, которые указывают на одну корневую папку сайта.
  • Включить модуль Parallel.
  • На странице "Производительность" ("Performance") нужно указать эти поддомены.
  • Не требует хакать ядро Drupal.
  • Модуль Parallel работет только с JavaScript, картинками и CSS.

Модуль IE CSS Optimizer

  • Модуль дает возможность разработчикам исключать отдельные файлы модулей, а также CSS-файлы тем, из аггрегации.
  • Требует, чтобы метод скачивания был "Публичный" (см admin/settings/file-system).
  • В Drupal 7 модуль не нужен: http://drupal.org/node/228818.
  • Другие модули могут перезаписать $vars['styles'] и это нейтрализует модуль. Чинится изменением веса модуля.

Модуль IE Unlimited CSS Loader

"don’t use @import" -- статья о том, почему использование @import не желательно с точки зрения производительности.

Модуль делает примерно тоже самое, что и IE CSS Optimizer, но немного иначе - использует @import, чтобы обойти ограниченность браузера IE в 31 СSS-файл.

Модуль CSSTidy

  • Модуль автоматически запускает CSSTidy в максимальным уровнем сжатия.
  • Можно настроить так, чтобы код оставался читабельным.
  • Модуль не совместим с Pressflow.
  • Новый CSS3 может вызывать проблемы (см. http://drupal.org/node/763730). Некоторые из них уже решены: http://drupal.org/cvs?commit=432558

Что оптимизируется:

  • Цвета типа black или rgb(0,0,0) конвертируются в hex-коды типа #000, когда только возможно. Некоторые hex-коды заменяются их цветовыми именами, если они короче (#f00 -> red).
  • a{property:x;property:y;} становится a{property:y;} (все повторяющиеся аттрибуты объединяются).
  • margin:1px 1px 1px 1px; становится margin:1px;.
  • margin:0px; становится margin:0;.
  • a{margin-top:10px; margin-bottom:10px; margin-left:10px; margin-right:10px;} становится a{margin:10px;}.
  • margin:010.0px; становится margin:10px;.
  • Все не нужные пробелы удаляются.
  • Все свойства background: объединяются.
  • Все комментарии удаляются.
  • Последняя точка с запятой в каждом блоке удаляется.
  • Недостающие точки с запятой добавляются, некорректные переносы строк в строках исправляются, неверные цвета (и имена цветов) исправляются.
  • property:value ! important; становится property:value !important;

CSS-хаки, которые работают:

Тестирование скорости загрузки страницы

Был проведен замер времени загрузки страницы, чтобы выяснить насколько изменится среднее время загрузки при разных методах оптимизации JS-файлов. Тестовый сайт имеет более 1300 JS-файлов и почти 450-CSS-файлов. Установлено 227 модулей (включая модули ядра). Были исследованы разные методы оптимизации:

  • Optimize JavaScript files: Disabled - оптимизация JS-файлов ядром Drupal отключена
  • Optimize JavaScript files: Enabled - оптимизация JS-файлов ядром Drupal включена
  • Optimize and Minify JavaScript files: Enabled - оптимизация JS-файлов ядром Drupal включена и дополнительно установлен модуль Javascript Aggregator, который сильнее минимизирует JS-код.

Условия проведения теста
Настройки браузера

  • Проверяемая страница: главная страница тестируемого сайта
  • Браузер: Firefox 3.6.13
  • Кеш браузера: 500М
  • Инструмент замера: Yslow 2.1.0
  • Прокси сервер: не использовался

Настройки сервера

  • На сервере используется: Accelerator
  • Операционная система: Linux
  • Версия ядра: 2.6.29-5
  • Архитектура: x86_64

Настройки в Drupal

  • Пользователь в Drupal: суперадмин
  • Caching mode: Normal
  • Minimum cache lifetime: none
  • Page compression: enabled
  • Block cache: enabled
  • Optimize CSS files: enabled

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

Диаграмма времени загрузки страницы в разных режимах

Анализ результатов тестирования

  • Аггрегация уменьшает количество запросов к серверу (при пустом кеше) на 23 штуки.

    Это значит, что когда пользователь впервые загружает страницу (кеш пустой), то загрузка будет выполнена быстрее.
  • Использование кеша браузера позволяет снизить количество запросов до 13.

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

    Кеш, как правило, включен по умолчанию, но управлять кешированием браузера мы не можем и он может быть просто отключен.
  • Gzip-сжатие делается не с максимальным уровнем сжатия.

    Аггрегированный JS-файл имеет точно такой же размер, как и суммарный размер всех неаггрегированных JS-файлов страницы. Аггрегированный файл на сервере имеет размер 326,9Кбайт, а полученный браузером и сжатый gzip - 108,9Кбайт. При этом сжатие утилитой gzip того же файла вручную дает размер около 90Кбайт. Причина в том, что библиотека zlib, которая используется для сжатия на сервере имеет по умолчанию степень сжатия (zlib.output_compression_level) равную "-1", хотя максимальная степень сжатия - это "9", а "-1" - это наилучшее быстродействие. Таким образом мы получаем худшее сжатие, но благодаря этому быстродействие сервера выше.
  • Использование модуля JavaScript Aggregator вместе с аггрегацией и Gzip-сжатием дает файл намного меньшего размера, чем не аггрегированные файлы.

Таким образом экспериментальным путем было установлено, что оптимизация ядром Drupal JS-файлов не всегда показывает хороший результат. В нашем случае (без применения модуля JavaScript Aggregator) мы получили незначительное увеличение скорости загрузки (за счет сокращения количества запросов) и увеличение (по сравнению с исходными файлами) размера аггрегированного (и сжатого) файла.

Учитывая то, на многих страницах загружаются одни и те же JS и СSS-файлы, а добавляются/удаляются только несколько специфичных, то кеширование одного большого файла не даст прироста производительности. При этом кеширование браузером отдельных файлов стилей и скриптов на одной странице даст экономию на загрузке этих файлов на последующих страницах.

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

Что можно сделать, чтобы улучшить ситуацию?

  • Хранить сжатые JS-файлы с максмальным уровнем сжатия, чтобы не заставлять сервер сжимать их для каждого запроса.
  • Использовать более эффективные методы упаковки JS и CSS-файлов.
  • Можно использовать выборочную аггрегацию общих для разных страниц сайта скриптов и стилей, а специфичные файлы загружать отдельно, но этот метод трудоемкий.
  • Переместить Javascript в footer, чтобы ускорить момент показа страницы пользователю.
  • Использовать CDN или модуль Parallel, чтобы увеличить количество одновременных соединений, которые может позволить себе браузер.

Перенос JavaScript в footer

В самом начале статьи мы выяснили, что браузер загружает весь CSS и весь JS из HEAD и только потом показывает страницу пользователю и начинает выполнение JS. Именно поэтому есть смысл переместить JS-файлы в footer, чтобы приблизить момент появления контента страницы в браузере. Это уменьшит время, когда пользователь видит "белую страницу" и визуально ускорит загрузку страницы (фактически страница будет загружаться столько же времени).

JS-файлы в Drupal подключаются следующим образом:

drupal_add_js($data = NULL, $type = 'module', $scope = 'header', $defer = FALSE, $cache = TRUE, $preprocess = TRUE)

здесь

$scope (optional) The location in which you want to place the script. Possible values are 'header' and 'footer' by default. If your theme implements different locations, however, you can also use these.

По умолчанию $scope равно "header" и, если не указано иное, то все скрипты загружаются в HEAD...

Таким образом нужно во всех модулях поменять $scope = 'header' на $scope = 'footer'.

Простое перемещение <?php print $scripts ?> в footer результата не даст, потому что в HEAD страницы останутся inline-скрипты, которые ожидают наличия jquery.js и других скриптов в HEAD и при выполнении будут давать ошибки.

Для 7й версии Drupal, было обсуждение возможности сделать значением по умолчанию для $scope - 'footer' (Make 'footer' the default scope for drupal_add_js() so that pages render fast), но скорее всего это будет уже в 8й версии Drupal.

Полезные ссылки
Компрессоры скриптов

HTTP-сжатие

Порядок загрузки элементов страницы браузером

Перенос Javascript в footer

Разное