Я люблю писать тексты, люблю отлаживать примеры, пробовать, анализировать. Чего я не люблю, так это возиться с форматированием, закачиванием картинок, проверкой верстки и т.д.
По причине лени я начал использовать Блогспот. Тут тебе и море шаблонов, виджеты всякие, мгновенная индексация Гуглом, статистика разная, с какого-то времени даже комментарии стали древовидные, и прочие свистелки. Ну все бы хорошо, но, увы, не предназначен редактор Блогспота для создания программистских постов. Когда над�� вставлять код или таблицы разные, начинаются мучения. Например, для своего другого блога, не про программирование, Яйца всмятку, сэр!, «возможностей» Блогспота вполне хватает.
Еще мне хочется хранить оригиналы постов в нормальном, не в обгаженном HTML'ем виде. Получалось, что материалы по блогу раскиданы по компьютеру там и сям в нескольких копиях. Сначала ты просто пишешь текст в редакторе, только разбивая на абзацы, без ссылок и картинок, и в конце сохраняешь почти готовый документ. Потом начинается верстка в HTML, в процессе которой, помимо, собственно, HTML'я, делаются поправки в оригинальном тексте. При этом обновлять оригинальный файл уже лень, и по сути, он остается в «сыром» виде. А в «сухом» виде остается только HTML'ная помойка. Но это еще не конец истории. Часто уже после публикации замечаешь опечатку, лезешь в Блогспот и правишь прямо на странице. Опять, самый первый оригинал и его локальная об'HTML'ная версия остаются неисправленными. В итоге: актуальные версии постов находятся только на самом Блогспоте. Конечно, можно делать автоматизированный бэкап всего блога, но опять таки — все будет уже только в HTML'е.
Некоторое время назад я начал использовать ReST. Тут жизнь хоть как-то полегчала. ReST позволяет писать текст в уже более менее предсказуемой разметке (абзацы, ссылки, код), и затем из него генерируется HTML, который вставляется (опять таки вручную) в Блогспот. Попытки автоматизировать предварительный просмотр поста через googlecl фактически провалились. Опять оставалась проблема, когда после исправления опечатки на странице оригинальный документ в ReST устаревал. Кроме того, ReST не решал проблему картинок. Их надо было куда-то заранее выкладывать, чтобы можно было полностью сделать preview.
Не могу объяснить почему, но идея динамических движков типа Wordpress'а меня как-то пугала. Сама идея держать посты в базе данных мне кажется перебором.
Я почти уже было остановился на промежуточном решении — Doku Wiki, например как на vak.ru. Тут движок хоть и динамический, но содержимое страниц хранится в файлах, и есть версионность. Doku можно использовать как движок всего сайта, не только блога. Хоть и дизайн неказистый, зато картинки и произвольные аттачменты поддерживаются системой.
Был еще вариант, на который я тоже почти подписался — блог на основе TiddlyWiki. TiddlyWiki — это мой любимый инструмент на Windows для ведения записей. Я про это уже писал. Почему только на Windows? Потому что на Маке я просто делаю записи в простых текстовых файлах, располагая их по смыслу в документах или на рабочем столе, а Spotlight, который индексирует все и вся на компьютере, моментально позволяет искать по фрагментам слов. Получается, что в ключевых возможностях TiddlyWiki — мгновенном поиске, уже не особого смысла. Но я отвлекся.
Оказывается, есть фанаты, которые превратили TiddlyWiki в блог-платформу. В эдакий статико-динамический мутант.
Например, вариант блога с таким движком — Rich Signell's Work Log. Эзотерика, на мой взгляд. Например, не ясно, как прикрутить комментарии, хотя бы тот же Disqus. Но если кому интересно, есть даже публичный хостинг — tiddlyspot.
И вот реально я возбудился на идее чисто статических движков. Прелесть тут в том, что такой блог хостить можно где угодно. Тут не только база данных не нужна, но и серверное скриптование. Но дальше — больше. GitHub или Heroku позволяют не только хостить статические сайты, но и управлять контентом через git.
Например, есть статический движок Jekyll. В Jekyll посты пишутся с использованием разметки Markdown или Textile. Также можно добавлять в проект произвольные файлы, которые при генерации сайта будут выкладываться без изменений. По сути — это движок сайта, в котором еще можно некоторые файлы оформлять в виде блога.
Комментарии же, как основная «динамика» блога, может реализоваться через, например, Disqus. К слову сказать, есть эстэты статических блогов с высшей степенью дзэна — со статическими комментариями (для меня даже это словосочетание является оксюмороном). Подход тут такой: у поста внизу есть секция со статически выведенными ранее введенными комментариями, и рядом форма для ввода нового. Ты вводишь комментарий, и он отсылается автору блога. Тот его подтверждает (или нет), куда-то кликает, и комментарий помещается в виде файла в статический проект блога, все пересобирается и выкладывается на публику. Понятно, что это никакой ни разу не real-time, а больше похоже на комментарии с пре-модерированием, прич��м модератор выходит на связь раз в неделю.
Я очень ценю дискуссию, и подобный подход не для меня. И продолжаю использовать Disqus. Кстати, из Disqus можно прекрасно экспортировать базу комментариев, и, например, превратить ее в статические страницы, если вдруг придется с него уходить.
Но вернемся к Jekyll. Например, GitHub Pages напрямую поддерживает Jekyll (его автор и есть сооснователь GitHub) и умеет рендерить проекты Jekyll (хотя можно и рендерить самому локально). Заливаешь через git проект Jekyll, и сайт становится видимым в GitHub Pages.
На Heroku идея немного иная. Heroku хостит Ruby, поэтому статический сайт на Heroku — это сами страницы и программа-вебсервер, которая их отдает. Звучит страшновато, но на Ruby такой сервер выглядит весьма компактно, например так:
Как ни странно, хостинг на Heroku в целом проще, чем на GitHub. Также, на Heroku, git-репозиторий блога остается private, тогда как на GitHub'е он становиться открытым, как и все остальные проекты. Хотя для меня звучит странно держать проект блога (фактически, сайта) закрытым. Он же и так весь допупен через веб.
Да, и GitHub Pages и Heroku позволяют «прикрутить» нормальный домен второго уровня, если у вас есть таковой.
Итак, я выбрал Jekyll c хостингом на Heroku. Увы, если взять чистый Jekyll, то придется самому с нуля разрабатывать стили и макет страниц. Если этим заниматься лень, то можно взять Octopress.
Octopress — это статический движок блога на базе Jekyll, но который укомплектован красивым HTML5 макетом страниц, пачкой удобных плагинов и автоматизированной возможностью выкладывания блога на GitHub Pages и Heroku.
Итак, я взял Octopress, покрутил туда-сюда, попробовал несколько постов, протестировал рендеринг блога локально, повыкладывал на Heroku и GitHub Pages. Все вроде было на мази.
Далее была самая нудная часть марлезонского балета — перетаскивание постов из любимого Блогспота. Фактически приходилось это делать вручную через cut-and-paste. Недели три мучений, и свои несчастные триста постов я обработал.
Все было готово для запуска моего нового статического блога. Но тут меня ждало главное разочарование. Драгоценный Jekyll, написанный на Ruby, рендерил мои несчастные триста постов (внимание!) — 15 минут (на Mac Air). А как сами понимаете, по началу надо было много пробовать, пересобирать, снова пробовать, снова пересобирать и т.д. И такое время полной пересборки не лезло ни в какие ворота.
Методом тыка я нашел узкое место в движке Jekyll/Octopress — львиная доля этих 15 минут уходило на генерацию файла
Все это показалось мне каким-то абсурдом (при всей моей любви к Ruby). После небольшого размышления (я к тому времени уже более менее понимал внутренности Jekyll) и нежелания корячить Jekyll в попытках его ускорить, я задался вопросом — а не написать ли мне свой статический движок по схожей идее? Ведь это всего-навсего работа с файлами, текстом и, возможно, шаблонами. К тому же, в Jekyll нет многоязычности ни в каком виде, и у меня были планы туда ее добавить, но с собственным движком у меня полностью развязаны руки, и можно сделать все стройно и красиво.
На чем писать? Можно по-мужски: на C++/boost. Будет работать очень быстро, но скучно. Я решил на Go. Нативная, очень быстрая компиляция (фактически, у меня нет фазы компиляции, так как она совмещена с фазой запуска), удобная работа со строками и файловой системой, упрощенная работа с памятью (сборщик мусора), регулярные выражения, массивы, хэши, библиотека шаблонов, библиотека для Markdown. Все, кроме последнего, «из коробки». Каких-либо проблем с производительностью не должно быть вообще. Тут как раз вышел релиз Go 1, и теперь есть нормальные дистрибутивы под Windows и Mac.
Итак, после трех вечеров родился мой велосипед — Goblog. Весь проект открытый. Сайт и его исходные тексты находятся вместе.
Есть два основных места: проект и собранный сайт-блог. В первом лежат исходные файлы. В процессе сборки файлы из проекта копируется в собранный сайт с сохранением локальной структуры каталогов. По умолчанию файлы копируются без изменений, как двоичные. Если же какой-то файл имеет расширение
Каталоги:
Подкаталоги и файлы в каталоге
Посты — это Markdown-файлы, имеющие особый заголовок и имя. Данные файлы выкладываются в отдельный каталог
Идея layouts унаследована из Jekyll. Если пост или страница имеет в заголовке атрибут
И теперь, собственно, генератор — main.go.
Все, что я делаю для сборки (в каталоге
Выводится примерно следующее:
Если все хорошо, то в корне проекта (в каталоге
Далее можно проверить сайт локально (см. ниже).
Если все готово, можно добавить измененные файлы (как исходники из
git add ../*
git commit -m «New post about ...»
И выложить на GitHub Pages:
git push
Практически сразу после
В Makefile несколько дополнительных команд для облегчения жизни.
Чтобы запустить сайт локально, я временн�� добавляю "
Итак:
И можно тестировать сайт локально (возможно придется запустить через
В принципе, можно и не трогать
В качестве расширения Markdown у меня есть специальный тег для вставки блоков кода:
Я унаследовал этот тег из Octopress'a. Markdown уже имеет синтаксис для кода:
где
Но свой тег позволяет мне проще добавлять атрибуты, например, включение отображения номеров строк, преобразование табуляций и т.д.
Далее надо было решить вопрос подсветки синтаксиса. Я покрутил несколько онлайновых библиотек, которые через JavaScript раскрашивают прямо на странице, но в каждой была какая-то минимальная проблема, поэтому я таки решил раскрашивать код статически.
Первое, что пришло в голову — pygments. Все бы хорошо, но благодаря Питону, работает крайне медленно. Время полной сборки сайта с 15 секунд выросло до двух минут. Основное время тратилось на раскраску кода. Приходили мысли на тему кеша уже раскрашенных фрагментов и прочей ерунде, но после небольшого поиска проблема решилась радикально.
Надо было просто взять колоризатор, написанный на правильном для данной задачи языке. Отыскались две альтернативы: Source-highlight и Highlight. Обе написаны на C++, поэтому работают практически мгновенно.
Например, вот тут человек сравнивал производительность pygments и syntax-highlight.
Мне больше понравился Highlight. В нем языков больше поддерживается (например, в GNU'шном даже Go нет). После перехода на Highlight время полной сборки вернулось к ~15-16 секундам, и я удовлетворился.
Вызов колоризатора сделан через обратный вызов в регулярном выражении, которое обрабатывает тег
Полно редакторов с preview для Markdown. Я использую MarkdownPad под Windows, и Marked на Маке.
Я решил не делать теги вообще. Основываясь на собственном опыте, я понял, что никогда не пользуюсь тегами ни в своем блоге, ни в чужих. К тому же со временем взгляды на логику категоризации информации меняются, и порой приходится просто для совместимости с прошлым расставлять теги, в которых уже не видишь смысла. Какой, например, смысл в теге
Но минимализм — это не путь к усложнению жизни. Наоборот. Лично я постоянно что-то ищу у себя в блоге в старых постах. На Блогспоте я просто заходил на главную страницу, жал ⌘-F (ой, простите, CTRL-F) и искал про фрагментам слов в заголовках. Именно для этого я с некоторого в правой колонке стал выводить ссылки практически на все информативные посты.
В новом блоге все «работает» точно также прямо на первой странице с каталогом постов. При переносе постов я изменил заголовки некоторых, сделав их более информативными и пригодными для поиска.
Но! Все это уже не важно, так как теперь в блоге работает полнофункциональный контекстный поиск.
Одним из досадных неудобств Jekyll — это отстуствие каких-либо проверок чего-либо. А я прошел через это в полной мере в процессе перетаскивания постов из Блогспота. Битые ссылки, неверные даты, забытые кавычки, непроставленные языки и прочие атрибуты постов и многое другое. Поэтому Goblog везде где только можно проверяет все — форматы, ссылки, семантику и т.д. Если где-то ошибка, сборка останавливается. Когда я добавил функцию check_links(), которая проверяет все локальные ссылки по всем файлам в уже собранном сайте, я выловил изрядное количество «дохлых» ссылок.
Была еще проблема, которую, как мне кажется, удалось решить весьма элегантно: двуязычность. Мне нужен блог и сайт на двух языках. Но хардкодить «прозрачную» поддержку русского и английского как-то не хотелось, к тому же версии на разных языках могу радикально отличаться, и мне не сложно поддерживать их шаблоны независимо. В итоге, у меня есть просто понятие языка у каждого обрабатываемого файла (или поста), заданное в заголовке. Goblog не знает о языках. Он просто делает информацию о языке файла или поста доступной через шаблоны. А я уж сам решаю, где лежат какие файлы. Например, все русское лежит, начиная с корня сайта, а все английское имеет префикс "
Например, русская титульная страница и английская титульная.
Я не люблю web-программирование: javascript, css, html, и нет более web-дизайн, чего вообще делать не умею. Но тут мне таки пришлось покопаться в этом (с Octopress'ом было проще). Я за основу взял сайт автора Jekyll. Сделал все минималистично просто. К тому же все равно большинство людей читают через RSS и ходят на сайт только если хотят оставить комментарий. Следовательно, надо чтобы работал RSS и страничка поста была удобной (что для меня значит простой, без изощренных шрифтов и странного форматирования) для чтения.
Вы думаете, я сейчас буду убеждать использовать мой движок? Совсем нет. Хоть я старался сделать движок максимально гибким и непривязанным конкретно к моему блогу, но мне пришлось переносить старые посты и их комментарии, поддержать два языка и т.д. В итоге в коде есть куски, «заточенные» конкретно под мой блог (особенно в области Disqus-ссылок на комментарии к старым постам).
Только могу порекомендовать, это что статический движок персонального сайта/блога можно написать самому. Почему? А потому, что эта задача решается за несколько вечеров (раз), и в нем будет только то, что вам реально нужно (остальное вам будет лень программировать) (два). Уверен, что все можно было сделать и на Руби, и на Питоне, PHP и т.д. Но было глупо упускать возможность поупражняться на новом языке с реальной задачей.
■
P.S. Этот писался почти неделю, урывками. Параллельно я писал поиск. Внезапно я осознал, как все-таки это нереально удобно с git'ом работать с блогом. Пишешь в бэкграунде пост — работаешь в одной ветке, дописываешь функционал — другая ветка. Когда что-то готово, сливает в master и push на GitHub. Красота.
По причине лени я начал использовать Блогспот. Тут тебе и море шаблонов, виджеты всякие, мгновенная индексация Гуглом, статистика разная, с какого-то времени даже комментарии стали древовидные, и прочие свистелки. Ну все бы хорошо, но, увы, не предназначен редактор Блогспота для создания программистских постов. Когда над�� вставлять код или таблицы разные, начинаются мучения. Например, для своего другого блога, не про программирование, Яйца всмятку, сэр!, «возможностей» Блогспота вполне хватает.
Еще мне хочется хранить оригиналы постов в нормальном, не в обгаженном HTML'ем виде. Получалось, что материалы по блогу раскиданы по компьютеру там и сям в нескольких копиях. Сначала ты просто пишешь текст в редакторе, только разбивая на абзацы, без ссылок и картинок, и в конце сохраняешь почти готовый документ. Потом начинается верстка в HTML, в процессе которой, помимо, собственно, HTML'я, делаются поправки в оригинальном тексте. При этом обновлять оригинальный файл уже лень, и по сути, он остается в «сыром» виде. А в «сухом» виде остается только HTML'ная помойка. Но это еще не конец истории. Часто уже после публикации замечаешь опечатку, лезешь в Блогспот и правишь прямо на странице. Опять, самый первый оригинал и его локальная об'HTML'ная версия остаются неисправленными. В итоге: актуальные версии постов находятся только на самом Блогспоте. Конечно, можно делать автоматизированный бэкап всего блога, но опять таки — все будет уже только в HTML'е.
Некоторое время назад я начал использовать ReST. Тут жизнь хоть как-то полегчала. ReST позволяет писать текст в уже более менее предсказуемой разметке (абзацы, ссылки, код), и затем из него генерируется HTML, который вставляется (опять таки вручную) в Блогспот. Попытки автоматизировать предварительный просмотр поста через googlecl фактически провалились. Опять оставалась проблема, когда после исправления опечатки на странице оригинальный документ в ReST устаревал. Кроме того, ReST не решал проблему картинок. Их надо было куда-то заранее выкладывать, чтобы можно было полностью сделать preview.
Не могу объяснить почему, но идея динамических движков типа Wordpress'а меня как-то пугала. Сама идея держать посты в базе данных мне кажется перебором.
Я почти уже было остановился на промежуточном решении — Doku Wiki, например как на vak.ru. Тут движок хоть и динамический, но содержимое страниц хранится в файлах, и есть версионность. Doku можно использовать как движок всего сайта, не только блога. Хоть и дизайн неказистый, зато картинки и произвольные аттачменты поддерживаются системой.
Был еще вариант, на который я тоже почти подписался — блог на основе TiddlyWiki. TiddlyWiki — это мой любимый инструмент на Windows для ведения записей. Я про это уже писал. Почему только на Windows? Потому что на Маке я просто делаю записи в простых текстовых файлах, располагая их по смыслу в документах или на рабочем столе, а Spotlight, который индексирует все и вся на компьютере, моментально позволяет искать по фрагментам слов. Получается, что в ключевых возможностях TiddlyWiki — мгновенном поиске, уже не особого смысла. Но я отвлекся.
Оказывается, есть фанаты, которые превратили TiddlyWiki в блог-платформу. В эдакий статико-динамический мутант.
Например, вариант блога с таким движком — Rich Signell's Work Log. Эзотерика, на мой взгляд. Например, не ясно, как прикрутить комментарии, хотя бы тот же Disqus. Но если кому интересно, есть даже публичный хостинг — tiddlyspot.
И вот реально я возбудился на идее чисто статических движков. Прелесть тут в том, что такой блог хостить можно где угодно. Тут не только база данных не нужна, но и серверное скриптование. Но дальше — больше. GitHub или Heroku позволяют не только хостить статические сайты, но и управлять контентом через git.
Например, есть статический движок Jekyll. В Jekyll посты пишутся с использованием разметки Markdown или Textile. Также можно добавлять в проект произвольные файлы, которые при генерации сайта будут выкладываться без изменений. По сути — это движок сайта, в котором еще можно некоторые файлы оформлять в виде блога.
Комментарии же, как основная «динамика» блога, может реализоваться через, например, Disqus. К слову сказать, есть эстэты статических блогов с высшей степенью дзэна — со статическими комментариями (для меня даже это словосочетание является оксюмороном). Подход тут такой: у поста внизу есть секция со статически выведенными ранее введенными комментариями, и рядом форма для ввода нового. Ты вводишь комментарий, и он отсылается автору блога. Тот его подтверждает (или нет), куда-то кликает, и комментарий помещается в виде файла в статический проект блога, все пересобирается и выкладывается на публику. Понятно, что это никакой ни разу не real-time, а больше похоже на комментарии с пре-модерированием, прич��м модератор выходит на связь раз в неделю.
Я очень ценю дискуссию, и подобный подход не для меня. И продолжаю использовать Disqus. Кстати, из Disqus можно прекрасно экспортировать базу комментариев, и, например, превратить ее в статические страницы, если вдруг придется с него уходить.
Но вернемся к Jekyll. Например, GitHub Pages напрямую поддерживает Jekyll (его автор и есть сооснователь GitHub) и умеет рендерить проекты Jekyll (хотя можно и рендерить самому локально). Заливаешь через git проект Jekyll, и сайт становится видимым в GitHub Pages.
На Heroku идея немного иная. Heroku хостит Ruby, поэтому статический сайт на Heroku — это сами страницы и программа-вебсервер, которая их отдает. Звучит страшновато, но на Ruby такой сервер выглядит весьма компактно, например так:
require 'bundler/setup'
require 'sinatra/base'
class SinatraStaticServer < Sinatra::Base
get(/.+/) do
send_sinatra_file(request.path) {404}
end
def send_sinatra_file(path, &missing_file_block)
file_path = File.join(File.dirname(__FILE__), 'public', path)
file_path = File.join(file_path, 'index.html') unless file_path =~ /\.[a-z]+$/i
File.exist?(file_path) ? send_file(file_path) : missing_file_block.call
end
end
run SinatraStaticServer
Как ни странно, хостинг на Heroku в целом проще, чем на GitHub. Также, на Heroku, git-репозиторий блога остается private, тогда как на GitHub'е он становиться открытым, как и все остальные проекты. Хотя для меня звучит странно держать проект блога (фактически, сайта) закрытым. Он же и так весь допупен через веб.
Да, и GitHub Pages и Heroku позволяют «прикрутить» нормальный домен второго уровня, если у вас есть таковой.
Итак, я выбрал Jekyll c хостингом на Heroku. Увы, если взять чистый Jekyll, то придется самому с нуля разрабатывать стили и макет страниц. Если этим заниматься лень, то можно взять Octopress.
Octopress — это статический движок блога на базе Jekyll, но который укомплектован красивым HTML5 макетом страниц, пачкой удобных плагинов и автоматизированной возможностью выкладывания блога на GitHub Pages и Heroku.
Итак, я взял Octopress, покрутил туда-сюда, попробовал несколько постов, протестировал рендеринг блога локально, повыкладывал на Heroku и GitHub Pages. Все вроде было на мази.
Далее была самая нудная часть марлезонского балета — перетаскивание постов из любимого Блогспота. Фактически приходилось это делать вручную через cut-and-paste. Недели три мучений, и свои несчастные триста постов я обработал.
Все было готово для запуска моего нового статического блога. Но тут меня ждало главное разочарование. Драгоценный Jekyll, написанный на Ruby, рендерил мои несчастные триста постов (внимание!) — 15 минут (на Mac Air). А как сами понимаете, по началу надо было много пробовать, пересобирать, снова пробовать, снова пересобирать и т.д. И такое время полной пересборки не лезло ни в какие ворота.
Методом тыка я нашел узкое место в движке Jekyll/Octopress — львиная доля этих 15 минут уходило на генерацию файла
atom.xml, RSS-фида. Почему-то в изначальных шаблонах в этот RSS-файл включалось только последние двадцать постов. Но у меня блог небольшой, поэтому я включил туда все посты, и тогда время генерации этого файла приводилось к пятнадцати минутной сборки всего блога.Все это показалось мне каким-то абсурдом (при всей моей любви к Ruby). После небольшого размышления (я к тому времени уже более менее понимал внутренности Jekyll) и нежелания корячить Jekyll в попытках его ускорить, я задался вопросом — а не написать ли мне свой статический движок по схожей идее? Ведь это всего-навсего работа с файлами, текстом и, возможно, шаблонами. К тому же, в Jekyll нет многоязычности ни в каком виде, и у меня были планы туда ее добавить, но с собственным движком у меня полностью развязаны руки, и можно сделать все стройно и красиво.
На чем писать? Можно по-мужски: на C++/boost. Будет работать очень быстро, но скучно. Я решил на Go. Нативная, очень быстрая компиляция (фактически, у меня нет фазы компиляции, так как она совмещена с фазой запуска), удобная работа со строками и файловой системой, упрощенная работа с памятью (сборщик мусора), регулярные выражения, массивы, хэши, библиотека шаблонов, библиотека для Markdown. Все, кроме последнего, «из коробки». Каких-либо проблем с производительностью не должно быть вообще. Тут как раз вышел релиз Go 1, и теперь есть нормальные дистрибутивы под Windows и Mac.
Итак, после трех вечеров родился мой велосипед — Goblog. Весь проект открытый. Сайт и его исходные тексты находятся вместе.
Принцип работы
Есть два основных места: проект и собранный сайт-блог. В первом лежат исходные файлы. В процессе сборки файлы из проекта копируется в собранный сайт с сохранением локальной структуры каталогов. По умолчанию файлы копируются без изменений, как двоичные. Если же какой-то файл имеет расширение
html, xml или js, то этот файл прогоняется через систему шаблонов Go. Файлы с расширением markdown дополнительно перед шаблонами обрабатываются библиотекой Markdown.Каталоги:
<root>Здесь находится собранный сайт, как он видится по адресу http://demin.ws/.<root>/_engine— Это проект, тут лежат исходники и генератор сайта. Технически, этот каталог виден и через web.
Подкаталоги и файлы в каталоге
_engine:_includes— Файлы, которые можно подставлять через макрос{{include "filename"}}._layouts— Файлы-layout'ы (см. ниже)._site— Собственно, каталоги и файлы сайта. Этот каталог является корнем будущего сайта. Файлы из него при сборке перекладываются в собранный сайт. Некоторые обрабатываются шаблонами._posts— Исходники постов. Эти файлы обрабатываются особо. Помимо шаблонов, они файлы переименовываются по структуре блога, где дата является частью URL: "домен/blog/язык/год/месяц/день/название-поста/"
Посты — это Markdown-файлы, имеющие особый заголовок и имя. Данные файлы выкладываются в отдельный каталог
/blog с подкаталогами-датами. Информация о постах собирается в специальные переменные, которые делаются видимыми из шаблонов. Также по постам строится обратный индекс для поиска.Layouts
Идея layouts унаследована из Jekyll. Если пост или страница имеет в заголовке атрибут
layout (например), то для ее рен��еринга загружается указанный шаблон-layout (из каталога _layouts), тело поста или страницы вставляется в определенное место layout'а (у меня это плейсхолдер Page.child), и затем все рендерится вместе. Это позволяет единообразно оформлять группы схожих страниц (например, постов). Layout'ы могут быть вложенные.Генератор
И теперь, собственно, генератор — main.go.
Все, что я делаю для сборки (в каталоге
_engine), это:make
Выводится примерно следующее:
_engine$ make
gofmt -w=true -tabs=false -tabwidth=2 main.go
go run main.go
Go static blog generator Copyright (C) 2012 by Alexander Demin
Words in russian index: 18452
Words in english index: 3563
15.672979s
Processed 344 posts.
Если все хорошо, то в корне проекта (в каталоге
.. относительно _engine) образуются файлы, готовые для выкладки. На моем Mac Air сборка занимает 15 секунд (привет, Jekyll/Octopress, и до свидания). Tак как все находится под git, то всегда четко видно, где и какие файлы появились, исчезли или изменились.Далее можно проверить сайт локально (см. ниже).
Если все готово, можно добавить измененные файлы (как исходники из
_site/, так и собранные файлы) в локальный репозиторий:git add ../*
git commit -m «New post about ...»
И выложить на GitHub Pages:
git push
Практически сразу после
push файлы появляются на demin.ws.В Makefile несколько дополнительных команд для облегчения жизни.
Локальное тестирование
Чтобы запустить сайт локально, я временн�� добавляю "
127.0.0.1 demin.ws" в /etc/hosts и запускаю мини web-сервер. Помните, как он выглядел на Ruby? Маленький, правда? А теперь версия на Go (server.go):package main
import "net/http"
func main() {
panic(http.ListenAndServe(":80", http.FileServer(http.Dir(".."))))
}
Итак:
go run server.go
И можно тестировать сайт локально (возможно придется запустить через
sudo, чтобы «сесть» на 80-й порт).В принципе, можно и не трогать
/etc/hosts и использовать адрес localhost:80, но RSS-фид файл atom.xml содержит абсолютные ссылки c доменом, поэтому для если надо тестировать RSS, то без подмены адреса не обойтись.Подсветка синтаксиса
В качестве расширения Markdown у меня есть специальный тег для вставки блоков кода:
{% codeblock lang:xxx %}
...
{% endcodeblock %}
Я унаследовал этот тег из Octopress'a. Markdown уже имеет синтаксис для кода:
``` xxx
...
```
где
xxx — язык.Но свой тег позволяет мне проще добавлять атрибуты, например, включение отображения номеров строк, преобразование табуляций и т.д.
Далее надо было решить вопрос подсветки синтаксиса. Я покрутил несколько онлайновых библиотек, которые через JavaScript раскрашивают прямо на странице, но в каждой была какая-то минимальная проблема, поэтому я таки решил раскрашивать код статически.
Первое, что пришло в голову — pygments. Все бы хорошо, но благодаря Питону, работает крайне медленно. Время полной сборки сайта с 15 секунд выросло до двух минут. Основное время тратилось на раскраску кода. Приходили мысли на тему кеша уже раскрашенных фрагментов и прочей ерунде, но после небольшого поиска проблема решилась радикально.
Надо было просто взять колоризатор, написанный на правильном для данной задачи языке. Отыскались две альтернативы: Source-highlight и Highlight. Обе написаны на C++, поэтому работают практически мгновенно.
Например, вот тут человек сравнивал производительность pygments и syntax-highlight.
Мне больше понравился Highlight. В нем языков больше поддерживается (например, в GNU'шном даже Go нет). После перехода на Highlight время полной сборки вернулось к ~15-16 секундам, и я удовлетворился.
Вызов колоризатора сделан через обратный вызов в регулярном выражении, которое обрабатывает тег
{% codeblock %} (функция highlight()).Редакторы для Markdown
Полно редакторов с preview для Markdown. Я использую MarkdownPad под Windows, и Marked на Маке.
Теги (категории) постов
Я решил не делать теги вообще. Основываясь на собственном опыте, я понял, что никогда не пользуюсь тегами ни в своем блоге, ни в чужих. К тому же со временем взгляды на логику категоризации информации меняются, и порой приходится просто для совместимости с прошлым расставлять теги, в которых уже не видишь смысла. Какой, например, смысл в теге
c++ в моем блоге? Кто-нибудь когда-нибудь его использовал?Но минимализм — это не путь к усложнению жизни. Наоборот. Лично я постоянно что-то ищу у себя в блоге в старых постах. На Блогспоте я просто заходил на главную страницу, жал ⌘-F (ой, простите, CTRL-F) и искал про фрагментам слов в заголовках. Именно для этого я с некоторого в правой колонке стал выводить ссылки практически на все информативные посты.
В новом блоге все «работает» точно также прямо на первой странице с каталогом постов. При переносе постов я изменил заголовки некоторых, сделав их более информативными и пригодными для поиска.
Но! Все это уже не важно, так как теперь в блоге работает полнофункциональный контекстный поиск.
Проверки
Одним из досадных неудобств Jekyll — это отстуствие каких-либо проверок чего-либо. А я прошел через это в полной мере в процессе перетаскивания постов из Блогспота. Битые ссылки, неверные даты, забытые кавычки, непроставленные языки и прочие атрибуты постов и многое другое. Поэтому Goblog везде где только можно проверяет все — форматы, ссылки, семантику и т.д. Если где-то ошибка, сборка останавливается. Когда я добавил функцию check_links(), которая проверяет все локальные ссылки по всем файлам в уже собранном сайте, я выловил изрядное количество «дохлых» ссылок.
Два языка
Была еще проблема, которую, как мне кажется, удалось решить весьма элегантно: двуязычность. Мне нужен блог и сайт на двух языках. Но хардкодить «прозрачную» поддержку русского и английского как-то не хотелось, к тому же версии на разных языках могу радикально отличаться, и мне не сложно поддерживать их шаблоны независимо. В итоге, у меня есть просто понятие языка у каждого обрабатываемого файла (или поста), заданное в заголовке. Goblog не знает о языках. Он просто делает информацию о языке файла или поста доступной через шаблоны. А я уж сам решаю, где лежат какие файлы. Например, все русское лежит, начиная с корня сайта, а все английское имеет префикс "
/english".Например, русская титульная страница и английская титульная.
Чем я таки не доволен
Я не люблю web-программирование: javascript, css, html, и нет более web-дизайн, чего вообще делать не умею. Но тут мне таки пришлось покопаться в этом (с Octopress'ом было проще). Я за основу взял сайт автора Jekyll. Сделал все минималистично просто. К тому же все равно большинство людей читают через RSS и ходят на сайт только если хотят оставить комментарий. Следовательно, надо чтобы работал RSS и страничка поста была удобной (что для меня значит простой, без изощренных шрифтов и странного форматирования) для чтения.
Мораль
Вы думаете, я сейчас буду убеждать использовать мой движок? Совсем нет. Хоть я старался сделать движок максимально гибким и непривязанным конкретно к моему блогу, но мне пришлось переносить старые посты и их комментарии, поддержать два языка и т.д. В итоге в коде есть куски, «заточенные» конкретно под мой блог (особенно в области Disqus-ссылок на комментарии к старым постам).
Только могу порекомендовать, это что статический движок персонального сайта/блога можно написать самому. Почему? А потому, что эта задача решается за несколько вечеров (раз), и в нем будет только то, что вам реально нужно (остальное вам будет лень программировать) (два). Уверен, что все можно было сделать и на Руби, и на Питоне, PHP и т.д. Но было глупо упускать возможность поупражняться на новом языке с реальной задачей.
■
P.S. Этот писался почти неделю, урывками. Параллельно я писал поиск. Внезапно я осознал, как все-таки это нереально удобно с git'ом работать с блогом. Пишешь в бэкграунде пост — работаешь в одной ветке, дописываешь функционал — другая ветка. Когда что-то готово, сливает в master и push на GitHub. Красота.
