Noveo

Наш блог Создаем блог на Swift с помощью Publish с размещением на GitHub Pages

Создаем блог на Swift с помощью Publish с размещением на GitHub Pages

Старший iOS-разработчик Noveo Александр испытывает новые инструменты для создания собственного блога.

Noveo Senior iOS developer Alexander

У меня уже есть блог, он на WordPress, и я устал от всей этой свистопляски с обновлением версии, плагинов, возможности взлома и прочего. Это буквально убивает желание продолжать его развивать. Моя цель — делиться с миром своими мыслями и находками, но при этом иметь полный контроль над своим сайтом. С недавних пор GitHub Pages предоставила возможность хранить простенькие сайты у них. Никаких баз данных и PHP, статический сайт, как в старые добрые. Для блога — идеально. А т.к. процесс деплоя будет проходить через GitHub, будет прозрачная история всех изменений и полный контроль над тем, что реально находится на сайте: трояны и прочая нечисть не пройдут.

 

Но они предлагают использовать Jekyll, статический генератор сайтов, написанный на Ruby. Все же хочется оттачивать мастерство в том языке, который ты используешь ежедневно, поэтому в качестве альтернативы я взял свежий статический генератор, написанный на Swift, от John Sundell.

 

Нам предстоит сделать 3 вещи:

  1. Создать блог на GitHub Pages.
  2. Разобраться, как работать с Publish.
  3. Залить свой новый блог на GitHub Pages.

 

Итак, перейдем к пункту 1.

1. Создадим блог на GitHub Pages

Официальная инструкция доступна по адресу https://pages.github.com.

Основное условие — login блога должен совпадать с вашим логином на GitHub (в моем случае это sparklone). Наши действия:

  • логинимся в GitHub,
  • идем по адресу https://github.com/new,
  • в качестве имени репозитория вводите login.github.io, в моем случае было sparklone.github.io,
  • убеждаемся, что он будет Public,
  • жмем Create Repository,
  • все, наш блог уже доступен по адресу https://login.github.io.

 

Но пока на сайте нет ни одного файла. Переходим ко второму пункту.

2. Разберёмся, как работать с Publish

Еще раз: Publish — это статический генератор сайтов, написанный на Swift, что позволяет выстраивать любую логику при генерации сайта: теги, карта сайта, rss, специфическая перелинковка… — все, на что нам хватит фантазии. Одна из моих идей на будущее — попробовать писать статьи на двух языках, и чтобы настроенный шаблон умел это понимать и вставлять переключатель в статью, к примеру. Не знаю, дойдут ли когда-нибудь до этого руки, но как идея — интересно.

 

Я предпочел установить напрямую через git, создал папку ~/Developer/tools и там выполнил

git clone https://github.com/JohnSundell/Publish.git
cd Publish
make

Далее я создал папку, где планирую хранить свой сайт (точнее, исходники его генератора), в моем случае это ~/Developer/my/blog. Внутри этой папки запускаем команду

publish new

Это создаст новый сайт, а список опций для команды можно узнать, просто запустив в консоли publish.

 

publish run скомпилирует все исходники и запустит веб-сервер на питоне (если прервать посредством Ctrl+C, веб-сервер не умрет и придется ковыряться в процессах, чтобы убить Python).

 

Первая сборка занимает какое-то время (подливаются нужные репозитории, все компилируется), при последующих запусках publish run все происходит намного быстрее.

 

Открываем в браузере http://localhost:8000 и видим, что за сайт получился:

Noveo Blog on Swift

Не густо, но мы еще ничего, собственно, и не сделали, чтобы ожидать чего-то большего.

 

Настройку стилей и прочие моменты я оставлю на потом. На сегодня вижу перед собой следующие задачи:

  1. сделать изначальную настройку генератора для нашего сайта,
  2. поменять пути, по которым будут лежать записи, и настроить меню,
  3. добавить подсветку для исходных файлов и создание своей темы.

1. Изначальная настройка генератора для нашего сайта

Посмотрим, что нам сгенерировал Publish. Внутри папки будет файл Package.swift, его открываем XCode’ом (можно в консоли набрать open Package.swift), и это запускает процесс подтягивания всех нужных библиотек. На скрине видно, что должно получится в итоге.

Noveo Blog on Swift publish-initial-screen

Тестовая запись лежит в Content/posts/first-post.md. Проверим, что мы можем что-то изменить и это отразится на сайте: подправим текст в first-post.md (можно поменять дату, теги, описания и сам контент).

 

В Xcode выбираем Mac в качества таргета, для которого надо запускать, и делаем Run проекту.

Noveo Blog on Swift blog-how-to-run

После этого рефрешим веб-страницу http://localhost:8000.

2. Меняем пути, по которым будут лежать записи, и настраиваем меню

Почему это важно сделать сразу? Если вы решите поменять пути после того, как уже зальете часть постов, входящие ссылки на эти страницы станут невалидными, а т.к. это не свой сервер/VPS, будет довольно проблематично сделать редирект со старых ссылок на новые пути. Не невозможно (вот, к примеру, плагин для Jekyll), но зачем создавать себе головную боль в будущем, если можно ее избежать.

 

По умолчанию все записи лежат в папке posts. Учитывая, что в дальнейшем хочется бить на категории, а posts — общее название, лучше переименовать папку в articles. Также не помешает добавить страницу about. Но наш генератор пока ничего не знает про это.

 

В main.swift поменяем на

struct Blog: Website {
    enum SectionID: String, WebsiteSectionID {
        case articles
        case about
    }
}

Добавим файл about.md в папку Content и заполним немного информации о себе.

К слову, эту статью я пишу в XCode, редактируя md-файл и периодически запуская проект, чтобы посмотреть в браузере, как это смотрится.

Я долго колебался, заморачиваться ли с датой у файлов *.md, т.е. называть не my-article.md, а, к примеру, 2020-07-10-my-article.md. И все же решил отказаться от этой идеи: т.к. в самих md-файлах есть метаданные (поле date), это при желании позволит в будущем добавлять дату автоматически. И не придется следить за корректностью даты в имени файла, к тому же это убережет от расхождений, если в имени файла одна дата, а в метаданных внутри — другая. Недостатком такого решения я вижу то, что гипотетически могут в будущем быть коллизии в именах md-файлов, но все-таки это маловероятно, к тому же мы об этом узнаем при создании поста, а не сохранении.

3. Добавляем подсветку для исходных файлов

Автором генератора Publish так же была написана библиотека Splash, позволяющая делать подсветку исходных кодов. Подключается она как package в Swift Package Manager.

 

Открываем файл Package.swift и добавляем поддержку, по сути нужно добавить 2 строки. Вот что получилось у меня:

let package = Package(
    name: "Blog",
    products: [
        .executable(
            name: "Blog",
            targets: ["Blog"]
        )
    ],
    dependencies: [
        .package(name: "Publish", url: "https://github.com/johnsundell/publish.git", from: "0.6.0"),
        .package(name: "SplashPublishPlugin", url: "https://github.com/johnsundell/splashpublishplugin", from: "0.1.0")
    ],
    targets: [
        .target(
            name: "Blog",
            dependencies: [
                "Publish",
                "SplashPublishPlugin"
            ]
        )
    ]
)

А чтобы подсветка начала применяться при генерации, нужно подключить плагин в main.swift:

try Blog().publish(withTheme: .foundation)

Я поменял на

try Blog().publish(
    withTheme: .foundation,
    plugins: [.splash(withClassPrefix: "")]
)

Не забываем добавить в main.swift импорт плагина import SplashPublishPlugin.

 

Если сгенерировать сайт сейчас, мы увидим, что блоки с кодом будут выделяться, но не подсвечиваться: это связано с тем, что нужно добавить CSS, будем использовать тот, который по умолчанию используется автором плагина.

 

Но вот проблема: куда добавлять этот CSS? Если покопаться в исходниках, то станет видно, что все это решается на уровне темы. Тема у нас стандартная: foundation, и она лежит в самом пакете Publish по пути Sources/Publish/API/Theme+Foundation.swift.

 

Внутри своего проекта (Blog) в папке, где лежит main.swift, я создал подобный файл Theme+Blog.swift. Также внутри папки Resources я создал папку Blog и поместил туда файл styles.css. Внутрь файла я поместил содержимое CSS от темы Foundation, ну и CSS от Splash. Да, лучше было бы разделить, а может, вообще темы вынести в отдельный package, но не будем усложнять раньше времени.

 

Итого у меня в файле темы пришлось поменять таким образом:

import Plot
import Publish

public extension Theme {
    static var blog: Self {
        Theme(
            htmlFactory: BlogHTMLFactory(),
            resourcePaths: ["resources/blog/styles.css"]
        )
    }
}

Если бы мы добавили еще один css, нам потребовалось бы не только добавить его в resourcePaths, но также добавлять в каждый head страниц, чего мне делать совершенно не хотелось в данный момент.

.head(for: item, on: context.site, stylesheetPaths: ["/styles.css", "/splash.css"])

В итоге сейчас у меня в проекте файловая структура выглядит как-то так:

Noveo Blog on Swift final-structure

3. Зальём свой новый блог на GitHub Pages

Итак, воспользуемся встроенным инструментом Publish для заливки нашего блога. В main.swift добавим

.deploy(using: .gitHub("login/login.github.io", useSSH: false))

У меня получилось

try Blog().publish(
    withTheme: .blog,
    deployedUsing: .gitHub("sparklone/sparklone.github.io", useSSH: false),
    plugins: [.splash(withClassPrefix: "")]
)

Проверяем в последний раз, что все работает. Последний штрих — мне кажется, что нет смысла хранить в git нашего репозитория с темплейтами, как строить сайт, содержимое папки Output, для этого у нас будет отдельный репозиторий, как раз таки login.github.io. Если вы согласны — исключим эту папку из .gitignore, добавив туда строку /Output в конце. Если все ок, выполняем в консоли (из папки, где мы выполняли publish new)

git add .
git commit -m "post title or some description"
git push origin
publish deploy

В течение минуты GitHub Pages подхватит ваши изменения, и все появится онлайн.

 

Поздравляю! :)

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

НазадПредыдущий пост ВпередСледующий пост

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: