Twitter GitHub

Оптимизируем WordPress (и не только) с помощью Grunt’а

С самого момента установки WordPress’а и темы для него, меня как разработчика, очень сильно напрягло, что ни сам WordPress, ни тема никак не оптимизируют количество подгружаемых файлов стилей и скриптов — никакой минификации, никакой конкатенации, только пачка запросов к серверу на 5 файлов стилей и 12 скриптов. Все это меня удручало, но как-то все было не того.

Но вот вчера я наткнулся на отличную статью на Хабре про Grunt, в конце которой оказалась ссылка на еще более полезную статью Артёма Сапегина про Grunt как систему сборки для фронтенд-разработчиков. После ознакомления с указанными статьями я подумал, что это просто-таки отличное решение моей проблемы с Wordpress’ом и погрузился в изучение Grunt’а.

Вот что из этого получилось… Мой Gruntfile.coffee:

'use strict'

module.exports = (grunt)->
  grunt.initConfig
    concat:
      js:
        src: [
          'wp-includes/js/jquery/jquery.js',
          'wp-content/themes/memoir/includes/js/jquery.easing.1.3.js',
          'wp-content/themes/memoir/includes/fancybox/jquery.mousewheel-3.0.4.pack.js',
          'wp-content/themes/memoir/includes/fancybox/jquery.fancybox-1.3.4.pack.js',
          'wp-content/themes/memoir/includes/js/jquery.mobilemenu.js',
          'wp-content/themes/memoir/includes/js/jquery.flexslider-min.js',
          'wp-content/themes/memoir/includes/js/jquery.fitvids.js',
          'wp-content/themes/memoir/includes/js/social-likes.min.js',
          'wp-content/themes/memoir/includes/js/highlight.pack.js',
          'wp-content/themes/memoir/includes/js/highlight.my.js',
          'wp-content/themes/memoir/includes/js/memoir.js',
          'wp-includes/js/comment-reply.js'
        ]
        dest: 'wp-content/themes/memoir/combined.js'

    uglify:
      js:
        src: '<%= concat.js.dest %>'
        dest: 'wp-content/themes/memoir/combined.min.js'

    cssmin:
      css:
        src: [
          'wp-content/themes/memoir/style.css',
          'wp-content/themes/memoir/includes/fancybox/jquery.fancybox-1.3.4.css',
          'wp-content/themes/memoir/includes/js/flexslider.css',
          'wp-content/themes/memoir/includes/js/social-likes.css',
          'wp-content/themes/memoir/includes/js/highlight.css'
        ]
        dest: 'wp-content/themes/memoir/combined.css'

    shell:
      gzipJS:
        command: 'gzip --best -f -c "<%= uglify.js.dest %>" > "<%= uglify.js.dest %>.gz"'
      gzipCSS:
        command: 'gzip --best -f -c "<%= cssmin.css.dest %>" > "<%= cssmin.css.dest %>.gz"'

    copy:
      templates:
        options:
          processContent: grunt.template.process
        files:
          'wp-content/themes/memoir/header.php': 'wp-content/themes/memoir/header.tpl.php'
          'wp-content/themes/memoir/footer.php': 'wp-content/themes/memoir/footer.tpl.php'

  grunt.loadNpmTasks 'grunt-contrib-concat'
  grunt.loadNpmTasks 'grunt-contrib-cssmin'
  grunt.loadNpmTasks 'grunt-contrib-uglify'
  grunt.loadNpmTasks 'grunt-contrib-copy'
  grunt.loadNpmTasks 'grunt-shell'

  grunt.registerTask 'default', ['concat', 'uglify', 'cssmin', 'shell', 'copy']
  grunt.registerTask 'js', ['concat:js', 'uglify', 'shell:gzipJS', 'copy']
  grunt.registerTask 'css', ['cssmin', 'shell:gzipCSS', 'copy']

Я пишу на JS только в CoffeeScript, потому что попробовав его один раз, приобрел перманентное отвращение к избыточности синтаксиса JS. В файле в общем-то все очевидно, подробнее о синтаксисе можете прочитать в вышеупомянутых статьях, там же про установку Grunt’а и его плагинов. Еще хорошо помогает официальный сайт Grunt’а :)

Интересных момента тут два:

  1.   shell:
          gzipJS:
            command: 'gzip --best -f -c "<%= uglify.js.dest %>" > "<%= uglify.js.dest %>.gz"'
          gzipCSS:
            command: 'gzip --best -f -c "<%= cssmin.compress.dest %>" > "<%= cssmin.compress.dest %>.gz"'

    Я не нашел (может плохо искал) плагина для gzip’а файлов. Есть плагин grunt-contrib-compress, но в нем нельзя менять силу сжатия. Поэтому решил эту проблему вот так — банальным вызовом gzip в шелле. Отвечает за это плагин grunt-shell, который на самом деле открывает просто безграничные возможности для творчества :)

    В целом этот шаг не обязателен, просто у меня в nginx активирована директива gzip_static, чтобы при наличии готовых *.gz файлов nginx брал сразу их, а не занимался компрессией сам.

  2.   copy:
          templates:
            options:
              processContent: grunt.template.process
            files:
              'wp-content/themes/memoir/header.php': 'wp-content/themes/memoir/header.tpl.php'
              'wp-content/themes/memoir/footer.php': 'wp-content/themes/memoir/footer.tpl.php'

    Тут мы копируем шаблоны шапки и подвала темы, попутно прогоняя их через Lo-Dash шаблонизатор Grunt’а, чтобы иметь возможность делать вот такие штуки:

    <link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_directory'); ?>/combined.css?<%= grunt.template.today('yyddmmHHMMss') %>" media="screen" />
    <script type="text/javascript" src="<?php bloginfo('stylesheet_directory'); ?>/combined.min.js?<%= grunt.template.today('yyddmmHHMMss') %>"></script>

    Это решает проблему с обновлением кэшированных стилей и скриптов на клиенте.

Дефолтное подключение файлов стилей и скриптов естественно из темы выпиливаем (не забывая проверить файл functions.php, а заодно и все остальные *.php, на предмет подключения файлов; ключевые слова для поиска: wp_enqueue_style и wp_enqueue_script) и заменяем примером выше.

Теперь при обновлении стилей и/или скриптов темы мне достаточно выполнить:

$ grunt

Или только для скриптов:

$ grunt js

Или только для стилей:

$ grunt css

После чего залить файлы combined.* + шаблоны header.php и footer.php, и все готово. Теперь посетитель получает один файл стилей и один файл скриптов, который в лучших традициях сайтостроения находится в самом низу шаблона. YSlow после всех этих манипуляций выдал оценку в 85 баллов.

Ну и конечно так можно и нужно оптимизировать не только WordPress, но и любой другой сайт, если у него нет встроенных механизмов минификации и конкатенации файлов стилей и скриптов.

Мой package.json, если кому-то интересно:

{
  "name": "svyatov.ru",
  "version": "1.0.0",
  "devDependencies": {
    "grunt": "~0.4.0",
    "grunt-contrib-concat": "~0.1.3",
    "grunt-contrib-cssmin": "~0.4.1",
    "grunt-contrib-uglify": "~0.1.1",
    "grunt-shell": "~0.2.1",
    "grunt-contrib-copy": "~0.4.0"
  }
}

[update 06.03.2013]

Спасибо комментарию Артёма, что направил ход мыслей в более правильное русло, а заодно вооружил отличным плагином. Используя плагин Артёма, я упростил схему до следующего вида…

Плагин grunt-contrib-copy я заменил плагином grunt-fingerprint:

fingerprint:
  assets:
    src: 'wp-content/themes/memoir/combined.*'
    filename: 'wp-content/themes/memoir/assets-fingerprint.php',
    template: "<?php define('ASSETS_FINGERPRINT', '<%= fingerprint %>');"

В header.php стили теперь подключаются так:

<?php require_once(get_template_directory().'/assets-fingerprint.php'); ?>
<link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_directory'); ?>/combined.css?<?php echo ASSETS_FINGERPRINT; ?>" media="screen" />

Аналогично подключаются скрипты в footer.php:

<?php require_once(get_template_directory().'/assets-fingerprint.php'); ?>
<script type="text/javascript" src="<?php bloginfo('stylesheet_directory'); ?>/combined.min.js?<?php echo ASSETS_FINGERPRINT; ?>"></script>

После обновления заливать теперь приходтся только файлы combined.* и assets-fingerprint.php, что проще и удобнее, а кроме того не нужно держать лишних шаблонов.

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

  • Спасибо за ссылку на мою статью! Я далаю примерно так же, но вместо шаблонов использую свой же плагин fingerprint — он позволяет записать в файл метку времени самого свежего файла из сборки. Потом можно будет подключить этот файл в теме и добавить метку к подключамым файлам.

  • Позабавила матрёшка: TPL > PHP > HTM.

  • Madrid says

    If you may ask website visitors to describe Madrid using some words, itrrrs likely that « Nature » won’t come up often.
    You can see the attractive sights here, sip excellent Spanish wine, and listen to the Spanish guitar because
    you taste some delicious Spanish food. Regarding the national scene, important
    stars for example Chano Dominguez, Juan Perro, Tequila,
    Diego «El Cigala» or Tomatito may be seen.

  • Após repassando um número da blog artigos na
    seu web site , eu verdadeiramente como seu forma de
    blogging . Eu livro marcado para meu marcador site lista e será verificar volta num
    futuro próximo. Confira meu site também
    e me avise como você se sente .

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *