Оптимизация сайта для Amazon S3

18 April 2013 #amazon #hosting #html #jekyll

После размещения сайта на Amazon S3, задумался об его оптимизации. Во-первых, Liquid, используемый по умолчанию язык разметки, оставляет в результирующем html-коде массу пустых строк. Можно, конечно и оставить все это в таком виде, но я не мог оставить это просто так.

И во-вторых, всегда ведь хочется чего-то большего?? Не правда ли?

Оптимизация HTML

Как оказалось, вариантов по оптимизации html-кода очень мало. С большим трудом нашел расширение для Jekyll, которое занимается удалением из html и js кода символов переносов строк. Причем нашел уже модифицированный вариант, который позволял исключать этот алгоритм для блоков <pre><code>.

Но когда попробовал в деле, оказалось, что сжатие js-файлов приводит к неработоспособности расширения shadowbox, которое я использую на сайте для показа изображений. Пришлось немного вмешаться в код, и убрать все лишнее. В итоге получил compressor.rb. Данный файл достаточно сохранить в директорию _plugins и после каждой генерации сайта уже будем получать оптимизированные html-страницы.

Оптимизация css и js файлов

Ранее я использовал для оптимизации js и css – jammit. Но данное расширение не позволяет использовать технологию cache-busting.

Сама технология заключается в том, что при генерации файлов производится расчет их контрольной суммы. И затем эта сумма подставляется в имя файла. К примеру, был файл с именем master.css, после генерации и оптимизации получаем нечто вроде master-cc56fd3da8c477d2bc00397664ca243f.css. Это позволяет задать для js и css файлов довольно большой срок кеширования, а при обновлении файлов не беспокоится о том, что у пользователей будет показываться старая версия сайта.

Пришлось опять искать замену.

В итоге наткнулся на расширение matthodan/jekyll-asset-pipeline, которое позволяет без использования сторонних gem-ов собирать несколько css или js файлов в один, и при этом сжимать его.

Для использования расширения необходимо в Gemfile добавить строку:

require 'jekyll-asset-pipeline'

И использовать команду:

$ bundle install

Затем в директории _plugins создаем новый файл, к примеру jekyll_assets_ppeline.rb, в который первой строкой добавляем:

require 'jekyll_asset_pipeline'

Обратите внимание на то, что в Gemfile добавляли файл с тире, а в коде используем уже файл с подчеркиванием.

В этом же файле можно прописать модули данного расширения, которые описаны на официальной странице. Таким образом я подключил возможность использования дополнительного сжатия за счет yui-compressor, и задал, в каком именно формате будут вставляться на страницы сайта теги script и link.

Для вставки подготовленных тегов необходимо в шаблон страницы добавить в нужные места следующие блоки кода:

{% css_asset_tag global %}
- /_assets/foo.css
- /_assets/bar.css
{% endcss_asset_tag %}

{% javascript_asset_tag global %}
- /_assets/foo.js
- /_assets/bar.js
{% endjavascript_asset_tag %}

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

Для управлением поведением расширения в файле _config.yml добавляется следующий блок кода:

asset_pipeline:
  bundle: true            # Default = true
  compress: true          # Default = true
  output_path: assets     # Default = assets
  display_path: nil       # Default = nil
  gzip: false             # Default = false

В коммментариях указаны значения по умолчанию.

GZip

При использовании Amazon S3 в качестве хостинга сайтов, одной из проблем, с которыми приходиться сталкиваться, остается невозможность задействовать сжатие GZip, которое обычно по умолчанию используется на веб-серверах Apache. Контент раздается в том виде, в котором он был доставлен на сервер. Но поискав по интернету, нашел решение.

Для этого перед загрузкой сайта на сервер амазона, все файлы предварительно сжимаются с помощью GZip, затем переименовываются, убирая дополнительное расширение gz. И затем при загрузке на сервер передается дополнительный заголовок --add-header "Content-Encoding: gzip".

Для всего этого организовал отдельные Rake-задачи:

desc "GZip HTML"
task :gzip_html do
  puts "## GZipping HTML"
  system 'find public/ -type f -name \*.html -exec gzip -9 {} \;'
  # Batch rename .html.gz to .html
  Dir['**/*.html.gz'].each do |f|
    test(?f, f) and File.rename(f, f.gsub(/\.html\.gz/, '.html'))
  end
end

desc "GZip Assets"
task :gzip_assets do
  puts "## GZipping Assets"
  styles_dir = "public/assets"
  system "gzip -9 #{styles_dir}/*"
  Dir["#{styles_dir}/*.css.gz"].each do |f|
    test(?f, f) and File.rename(f, f.gsub(/\.css\.gz/, '.css'))
  end
  Dir["#{styles_dir}/*.js.gz"].each do |f|
    test(?f, f) and File.rename(f, f.gsub(/\.js\.gz/, '.js'))
  end
end

Главное что все получилось, и в итоге значение Page Speed для моего сайта поднялось до 99 из 100. Замечательный результат!

Итоги

Если вы думаете, что все так легко и безоблачно, как было описано выше, то тут вас ждет небольшое разочарование. В результате эксперимента мне пришлось отказаться от использования сжатия GZip. Почему??

Во-первых, при использовании GZip становится невозможным проверять сайт локально. Нет, можно конечно разделить генерацию сайта и его сжатие, и в итоге нормально использовать локальный сайт, но как оказалось дальше, проблемы только начинались.

И во-вторых, я надеялся на то, что современные браузеры умеют работать со страницами, сжатыми GZip. И да, они умеют это делать, еще примерно с 2011 года. Но помимо обычных пользователей остаются еще веб-роботы поисковых систем, которые, как оказалось, с GZip не очень-то любят работать. Помимо них есть и другие веб-сервисы, которые просто отказываются работать с сайтом при использовании GZip сжатия.

Об этом я сразу не подумал, и обратил внимание на проблему только в том случае, когда у меня статистика посещаемости вдруг резко просела.

Пришлось отказаться от принудительного сжатия страниц, естественно, что тут же потерял довольно значительно в Page Speed, теперь он составляет всего порядка 83 баллов из 100. Но лучше иметь чуть менее быстрый сайт, чем малопосещаемый, ведь так?

Но в целом убрав лишние переносы строк, я несколько уменьшил размеры страниц, а использовав jekyll-assets-pipeline значительно упростил себе работу по оформлению сайта. Кроме того, получил возможность использования CloudFront для раздачи js и css файлов.