Связка WordPress+nginx — не слишком хорошая штука, как в плане удобства, так и в плане скорости работы. Когда скорость ответа сервера (только ответа, ещё до начала отправки страницы) дошла до 1.5 секунд, я окончательно решил что нужно что–то менять. Перспектива лезть в дебри движка вордпресса и по локти испачкаться в PHP меня совершенно не прельщала, и я нашёл очень удобный выход из положения — Markdown–блог.

Архитектура {#–}

Применён паттерн «содержание–представление». Сначала я использовал модуль grunt–markdown–blog, но его некоторая кривость и необщительность разработчиков сделали своё дело — я написал свой модуль. Конечно, во многом я основывался на архитектуре grunt–markdown–blog, потому что она действительно весьма удобна.

Содержимое/написание {#–}

Каждая статья пишется простым текстом с markdown–разметкой, сохраняется в виде .md–файла в директории /posts/. В начале файла находится YAML–блок (отделённый тремя тире от текста), в котором описаны:

  • заголовок поста
  • дата создания
  • теги

Вид {#–}

В директории /templates/ лежат шаблоны всех типов страниц:

  • post.us — страница поста
  • index.us — главная (список постов)
  • archive.us — архив по тегу или по месяцам

Общий дизайн задаётся шаблоном wrapper.us, в который «оборачиваются» все страницы — он сделан довольно простым, без лишнего оформления. Для комментариев подключен блок от disqus.com — и это единственный «плагин» на странице.

Обработка {#–}

Написан node.js–скрипт, который загружает все файлы из директории /posts/ и прогоняет их через процессор постов: выделяет YAML–блок метаописания поста (с помощью js–yaml) и Markdown–блок текста, который превращается в html отличной библиотекой Marked. После создания html немного правлю типографику — заменяю «минусы» на нормальные тире.

Подсветка кода {#–}

Поскольку в моих постах часто приведены куски кода, необходимо как–то их оформлять. Для этого я, конечно, использую highlight.js.

В WordPress это было сущей мукой — необходимо было переключиться в режим html, руками ввести там теги pre и code, указать ему нужный класс с языком, и следить чтобы ничего не развалилось. А разваливалось часто, например если во вставленном js–коде был блок CDATA.

Раньше я применял стандартный способ его использования — просто подключал к странице hljs.js–скрипт, который по событию onLoad автоматически распознавал блоки кода и оформлял их нужным образом. Однако из–за этого на мгновение код отображался неоформленным, и это мигание было просто неэстетичным. К тому же эта работа выполнялась каждый раз при загрузке страницы, что нельзя назвать экономным расходованием ресурсов. Поэтому я включил в скрипт модуль hljs, который оформляет код ещё на этапе «сборки».

Также, файл hljs.css просто огромен, и содержит довольно много лишнего (я пишу только на c и js) — поэтому я выделил из него только что, что реально мне нужно и включил это в wrapper.us инлайн.

Была небольшая проблема с двойным (на этапе marked и на этапе hljs) преобразованием специальных символов, из–за которого они превращались в escape–последовательности прямым текстом. К сожалению, ни одна из этих библиотек не позволяет отключить такое преобразование, и чтобы не лезть в их код — я сделал функцию repair, которая делает обратное преобразование. Выглядит как костыль, но похоже что по–другому не сделать.
Ещё одна проблема hljs.js именно в виде node–модуля — не работает язык C. Приходится вручную выбирать C#. В client–side версии такой проблемы нет.

Шаблонизация {#–}

После этого обрабатываем метаописание — добавлям заголовок, теги, складываем пост в массив index и массив тегов. Теперь, наконец, применяем шаблоны к этим кускам html–кода, оборачиваем враппером, и сохраняем всё полученное в файлы. Весь скрипт довольно прост и занимает всего 40 строк в write–only стиле.

Grunt.js {#grunt–js}

Дальше в дело вступает Grunt.js. Точнее, весь описанный процесс сборки уже являлся первым шагом в файле Gruntfile.js, а следом за ним работает компрессор HTML. Это стандартный гугловский компрессор, который сжимает html–код, а благодаря настройкам compressCss и compressJs — ещё и стили со скриптами.

Окончательное сжатие в gzip выполняет уже nginx.

Всё это обёрнуто в grunt–цель «watch», и я получаю автопересборку после каждого изменения любых исходных файлов.


Так я добился сразу многих плюсов:

  • Очень простое создание и редактирование постов
  • Легко вставлять блоки кода, сразу с указанием языка для правильной подсветки
  • Страницы отдаются чисто nginx–ом из памяти (настроено кэширование)
  • Сверхбыстрая загрузка (Google PageSpeed оценивает в 99 баллов из ста)
  • Возможность размещения на любом хостинге
  • Лёгкое создание бекапа, которое можно автоматизировать