Создаем блог с помощью Hakyll
Дата: October 7, 2014
Hakyll является движком для генерации статических сайтов, написанном на Haskell. Именно с помощью этого движка были сгенерированы страницы этого блога. Вы просто описываете содержимое страниц в удобном формате (обычно используется markdown, но, при необходимости, можно использовать и TeX - все это достигается благодаря тесной интеграции с pandoc, тоже написанном на Haskell), затем на Haskell описываете конфигурацию сайта, по каким правилам и как нужно собрать страницы, компилируете конфигурацию и с помощью нее потом собираете страницы сайта. Благодаря pandoc в сгенерированных страницах можно использовать подсветку кода и другие полезные плюшки.
Здесь будет рассмотрено создание сайта на GitHub, а также обратим внимание на некоторые грабли, которые встречаются на пути у каждого, кто пробовал компилировать Haskell-пакеты и заводить Hakyll под Windows.
Необходимым минимумом для создании своего сайта с помощью Hakyll являются:
- Минимальные знания Haskell или желание его изучить
- Установленную Haskell Platform for Windows
- Установленный пакет Git Extensions. Этот пакет на нужен будет не только для более удобной работы с Git, но и для того, чтобы скомпилировать network пакет в Git bash. В обычной консоли его собрать не получится.
Для начала следует убедиться, что cabal прописан в путях. Для этого открываем консоль и там пишем, к примеру,
> cabal --version
Если cabal не удалось найти, прописываем в PATH (в зависимости от разрядности установленной Haskell Platform):
C:\Program Files (x86)\Haskell Platform\2014.2.0.0\lib\extralibs\bin
C:\Program Files (x86)\Haskell Platform\2014.2.0.0\bin
Убеждаемся, что теперь cabal работает и теперь мы переходим к непосредственно сборке Hakyll. Создаем каталог, в котором будем собирать Hakyll. Я в примерах буду использовать C:\Hakyll
. Переходим в созданный каталог и там создаем песочницу, в которой будет происходить сборка:
> cd C:\Hakyll
> cabal sandbox init
Cabal должен бодро сообщить, что песочница создана:
Writing a default package environment file to
C:\Hakyll\cabal.sandbox.config
Creating a new sandbox at C:\Hakyll\.cabal-sandbox
Если не создать песочницы и начать сборку, то все бинарники будут собираться в каталог %APPDATA%\cabal\bin
и там же рядом будут устанавливаться пакеты. Чтобы не было конфликтов с версиями пакетов, хорошей практикой считается создание песочницы с последующей установкой в нее всего необходимого. Причем одну песочницу можно использовать между несколькими проектами. Все дальнейшие вызовы cabal
необходимо производить исключительно из каталога, в котором мы создали песочницу, т.е. из C:\Hakyll\
.
Теперь нам нужно собрать пакет network. Собирать его нужно в unix-подобной консоли, поэтому запустим Git Extensions и там откроем Git bash (либо комбинацией Ctrl+G, либо через меню Git → Git bash). Git bash консоль я буду помечать символом $
в начале строки. Переходим в наш каталог (обращаем внимание на то как указывается путь), обновляем репозиторий cabal и собираем пакет network:
$ cd /c/Hakyll/
$ cabal update
$ cabal install network
Никаких сообщений об ошибках быть не должно. Теперь возвращаемся в обычную консоль и в ней собираем pandoc, а затем и hakyll. На данный момент есть известная проблема сборки pandoc, поэтому собирать будем с дополнительным параметром:
> cd C:\Hakyll
> cabal install pandoc -fhttps
> cabal install hakyll
После сборки в каталоге C:\Hakyll\.cabal-sandbox\bin
мы должны увидеть следующие бинарники:
aeson-pretty.exe
hakyll-init.exe
json2yaml.exe
pandoc-citeproc.exe
pandoc.exe
simple.exe
yaml2json.exe
Теперь, когда все готово к созданию сайта, нужно, если этого еще не сделали, создать репозиторий <имя пользователя>.github.io
на GitHub - это так называемый User page. В моем случае конечный путь до созданного репозитория выглядел так:
https://github.com/dimchansky/dimchansky.github.io
Все, что будет лежать в ветке master этого репозитория, будет доступно по адресу http://dimchansky.github.io/ (вместо dimchansky здесь и далее везде пишите свое имя). Понятно, что исходный код нам нужно будет положить в другую ветку, например, sources и так как содержимое веток master и sources будеть сильно отличаться и нам нужно будет постоянно копировать новую собранную версию в master, то постоянно переключаться между двумя ветками будет создавать сильные неудобства. Чтобы избежать этого, сделаем небольшой финт ушами, чтобы две ветки одного и того же репозитория лежали в разных папках:
C:\Hakyll
└── dimchansky.github.io
├── master
└── sources
Я намеренно сделал дополнительно папку dimchansky.github.io
внутри Hakyll
на случай, если я захочу создать еще какой-нибудь сайтик с использованием Hakyll. Теперь нам снова понадобится Git bash консоль, т.к. мы будем выполнять команды git. Создадим папку для работы с веткой master (не забываем вместо dimchansky везде писать своем имя):
$ cd /c/Hakyll/
$ mkdir -p dimchansky.github.io/master
$ cd dimchansky.github.io/master
$ git init
$ touch .gitignore
$ git add .
$ git commit -m "Initial commit."
$ git remote add origin git@github.com:dimchansky/dimchansky.github.io.git
$ git push origin master
Теперь в той же консоли создадим папку для работы с веткой sources:
$ cd ..
$ git clone -o unrelated master sources
$ cd sources
$ git checkout --orphan sources
$ git commit -m "Initial commit (sources)."
$ git branch -d master
$ git remote add origin git@github.com:dimchansky/dimchansky.github.io.git
$ git push origin sources
Обратите внимание, что ветку master мы удалили здесь и хоть git ругнется - это нормально. Теперь дело осталось за малым - создать начальную конфигурацию сайта, скомпилировать ее и затем с помощью полученного бинарника сгенерировать страницы сайта. Находясь в каталоге sources укажем, что мы хотим использовать уже имеющуюся песочницу:
$ cabal sandbox init --sandbox ../../.cabal-sandbox
Теперь с помощью Hakyll создадим начальную конфигурацию сайта:
$ ../../.cabal-sandbox/bin/hakyll-init.exe blog
Он в нашей папке sources создаст папку blog, нам такой вложенности не надо, поэтому поднимем все на уровень выше:
$ mv -v blog/* .
$ rmdir blog
Теперь нужно подредактировать файл .gitignore
и вписать в него такие строки:
_site
_cache
dist
.cabal-sandbox
cabal.sandbox.config
Это нужно, чтобы не пихать в ветку sources каталоги и файлы:
- _site - каталог, в котором будут сгенерированные статические страницы
- _cache - кеш страниц, который создаст для себя сборщик нашего сайта
- dist - каталог, куда будет собран наша конфигуратор сайта
- .cabal-sandbox - каталог песочницы
- cabal.sandbox.config - файл конфигурации песочницы
Можно посмотреть, какие же файлы и каталоги были созданы Hakyll’ом:
- about.rst - страница “About”
- blog.cabal - файл для сборки нашего конфигуратора или генератора статических страниц
- contact.markdown - страница “Contact”
- css - стили сайта
- images - картинки сайта
- index.html - содержимое главнойстраницы сайта
- posts - примеры заметок в формате markdown
- site.hs - описание na Haskell того, как нужно генерировать статические страницы
- templates - каталог с шаблонами страниц
В дальнейшем все можно в корне поменять, как нам будет удобно. Но пока сделаем одну модификацию в файле site.hs
, чтобы он не спотыкался на страницах с UTF-8 кодировкой. Кстати говоря, набирая страницы в UTF-8 сохраняйте их без BOM, т.е. без первых трех байтов, которые любит notepad вставлять, как указатель того, что файл в UTF-8. Можно в notepad++, например, указать Encoding → Encode in UTF-8 without BOM. Итак, открываем site.hs
и меняем строки:
--------------------------------------------------------------------------------
main :: IO ()
main = hakyll $ do
на
import GHC.IO.Encoding
--------------------------------------------------------------------------------
main :: IO ()
main = do
setLocaleEncoding utf8
setFileSystemEncoding utf8
setForeignEncoding utf8
runHakyll
runHakyll :: IO ()
runHakyll = hakyll $ do
Для подсветки синтаксиса кода в папкe css создать файл syntax.css
. Как пример, можно взять дефолтный Pandoc syntax CSS file, а если хватает смелости, то можно его допилить до нужной радуги. Как оформлять код в markdown можно почитать в документации по Pandoc, код можно и инлайнить. Также нужно не забыть сослаться на этот CSS файл в файле templates\default.html
:
<link rel="stylesheet" type="text/css" href="/css/default.css" />
<link rel="stylesheet" type="text/css" href="/css/syntax.css" />
Теперь можно сохранить все изменения в ветке sources:
$ git add -A .
$ git commit -m "Initial hakyll site"
$ git push origin sources
Собираем наш генератор сайта:
> cabal build
С его помощью генерируем страницы сайта:
> dist\build\site\site.exe build
Все сгенерированные страницы окажутся в каталоге _site. Можно теперь локально запустить сервер, который по адресу http://127.0.0.1:8000/ покажет, как выглядит наш сайт
> dist\build\site\site.exe watch
Кстати, при изменении, например, заметок, сервер автоматически перегенерирует измененные страницы. Однако, при изменении site.hs
нужно сначала пересобрать генератор, а потом сам сайт:
> cabal build
> dist\build\site\site.exe rebuild
Если порт 8000 уже занят чем-то, можно указать другой порт:
$ dist/build/site/site.exe watch --port 8080
Если нас все устраивает, можно все содержимое каталога _site скопировать в каталог master, перейти в него и отправить на github:
$ cd ../master
$ git add -A .
$ git commit -m "Initial hakyll site"
$ git push origin master
Теперь по адресу http://dimchansky.github.io/ можно будет увидеть наш созданный сайт.
Если вдруг потребуется отредактировать и перегенерировать сайт на другом компе, то для этого нужно:
- Установить Haskell Platform for Windows
- Установить Git Extensions
- Создать песочницу для cabal в каталоге Hakyll
- Собрать в ней Hakyll
После этого создать каталоги для master и sources, клонировать в них только нужные ветки, и, находясь в каталоге sources, указать cabal, чтобы он использовал уже имеющуюся песочницу:
$ cd /c/Hakyll/
$ mkdir -p dimchansky.github.io/master
$ cd dimchansky.github.io/master
$ git clone git@github.com:dimchansky/dimchansky.github.io.git -b master --single-branch .
$ cd ..
$ mkdir sources
$ cd sources
$ git clone git@github.com:dimchansky/dimchansky.github.io.git -b sources --single-branch .
$ cabal sandbox init --sandbox ../../.cabal-sandbox
Ну а дальше, как и ранее, собираем конфигуратор и с его помощью генерируем страницы.