Простой блог с помощью Swift и Publish
Раньше мой сайт работал с помощью Jekyll и бесплатно хостился на GitHub. В принципе меня это вполне устраивало. Но некоторое время назад я наткнулся на классную утилиту от John Sundell под названием Publish. Это аналог Jekyll и является таким же генератором статических вебстраниц, но написанным на Swift. И в этом посте я постарался описать процесс от создания сайта до деплоя на GitHub Pages.
Итак мои требования к будущему сайту:
- Markdown разметка
- Блог с тэгами
- Подсветка кода, в первую очередь Swift
- Бесплатный хостинг на GitHub Pages
Как устроен Publish?
Сайт в Publish представляет собой отдельный Swift Package. Поэтому в качестве IDE придётся использовать знакомый iOS-разработчикам Xcode.
Publish тянет за собой несколько зависимостей. Вот наболее важные из них:
Создаем сайт из шаблона
Качаем утилиту с GitHub и устанавливаем.
$ git clone https://github.com/JohnSundell/Publish.git
$ cd Publish
$ make
Создаем папку для будущего сайта, генерируем Swift Package и открываем в Xcode.
$ mkdir Blog
$ cd Blog
$ publish new
$ open Package.swift
Структура Swift Package в Xcode выглядит следующим образом:
- Content (все markdown странички)
- Output (сгенерированные HTML и ресурсы),
- Resourses (картинки, видео, аудио и стили)
- Sources (исходники на Swift)
Для генерации сайта есть схема в Xcode.
Чтобы посмотреть локально сгенерированный сайт, нужно воспользоваться командой run в директории проекта.
$ publish run
Вот так выглядит сайт сразу после создания. 👾
Настраиваем deploy в GitHub Pages
Создаем репозиторий на GitHub и называем его в определённом формате {login}.github.io
. Если вы хотите использовать свой домен, то название репозитория может быть любым.
Возвращаемся в Xcode. Теперь нам надо научить Publish деплоить сгенерированные странички в созданный репозиторий.
Для взаимодействия Publish с GitHub у вас заранее должны быть настроены deploy keys. Инструкция о том, как это сделать, есть тут.
В Publish есть структура DeploymentMethod, которая как раз отвечает за деплой сайта. Нам нужно сконфигурировать деплой. Для этого в файле main.swift делаем такие изменения.
struct Blog: Website {
enum SectionID: String, WebsiteSectionID {
case posts
}
struct ItemMetadata: WebsiteItemMetadata {
// Add any site-specific metadata that you want to use here.
}
var url = URL(string: "https://bestk1ngArthur.github.io")!
var name = "bestk1ngArthur"
var description = "My name is Artem, I am an iOS developer and you are on my webpage"
var language: Language { .russian }
var imagePath: Path? { nil }
}
try Blog().publish(using: [
.addMarkdownFiles(),
.copyResources(),
.generateHTML(withTheme: .foundation),
.generateSiteMap(),
.deploy(using: .git("https://github.com/bestK1ngArthur/bestk1ngArthur.github.io.git"))
])
Теперь при вызове deploy файлы из Output будут заливаться в репозиторий в ветку master.
$ publish deploy
Возвращаемся в GitHub и в настройках репозитория включаем Pages, чтобы после пуша сайта в ветку master автоматически запускался деплой GitHub Pages.
Ура! Сайт уже должен появиться на домене {login}.github.io
. 🚀
Подключаем свой домен
В настройках репозитория в разделе GitHub Pages задаем свой домен. Не забываем сменить DNS для домена на гитхабовские. Как это сделать написано вот тут.
Теперь у нас в репозиторий добавился файл CNAME.
Возвращаемся в Xcode. При стандатном деплое с помощью .git каждый раз происходит очистка папки репозитория. В том числе и удаляется файл CNAME. Нам нужно это исправить. Для этого создаем свой собственный DeploymentMethod.
extension DeploymentMethod {
static func gitHubPages(_ remote: String) -> Self {
DeploymentMethod(name: "GitHub Pages (\(remote))") { context in
let folder = try context.createDeploymentFolder(withPrefix: "Git") { folder in
if !folder.containsSubfolder(named: ".git") {
try shellOut(to: .gitInit(), at: folder.path)
try shellOut(
to: "git remote add origin \(remote)",
at: folder.path
)
}
try shellOut(
to: "git remote set-url origin \(remote)",
at: folder.path
)
_ = try? shellOut(
to: .gitPull(remote: "origin", branch: "master"),
at: folder.path
)
try folder.empty()
try shellOut(
to: "echo \(context.site.url.absoluteString) > CNAME",
at: folder.path
)
}
do {
try shellOut(
to: """
git add . && git commit -a -m \"🚀 Publish deploy" --allow-empty
""",
at: folder.path
)
try shellOut(
to: .gitPush(remote: "origin", branch: "master"),
at: folder.path
)
} catch let error as ShellOutError {
throw PublishingError(infoMessage: error.message)
} catch {
throw error
}
}
}
}
Я оставил очистку папки, чтобы не возникало мусора и артефактов. Но после очистки добавил команду для создания файла CNAME.
Меняем в файле main.swift метод деплоя на созданный и указываем в конфиге блога новый URL.
struct Blog: Website {
enum SectionID: String, WebsiteSectionID {
case posts
}
struct ItemMetadata: WebsiteItemMetadata {
// Add any site-specific metadata that you want to use here.
}
var url = URL(string: "https://bestk1ng.ru")!
var name = "bestk1ngArthur"
var description = "My name is Artem, I am an iOS developer and you are on my webpage"
var language: Language { .russian }
var imagePath: Path? { nil }
}
try Blog().publish(using: [
.addMarkdownFiles(),
.copyResources(),
.generateHTML(withTheme: .foundation),
.generateSiteMap(),
.deploy(using: .gitHubPages("https://github.com/bestK1ngArthur/bestk1ngArthur.github.io.git"))
])
Теперь деплой сайта происходит на кастомный домен. 🎉
Делаем подсветку синтаксиса Swift
В Publish есть поддержка плагинов. Чтобы добавить подсветку синтаксиса есть классный плагин Splash.
Добавляем плагин в Package.swift.
import PackageDescription
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"]
)
]
)
Теперь в стили нужно добавить цвета для подсветки. Для этого нам придется создать кастомную тему оформления.
Создаем в папке Resourses папку CodeTheme и копируем в неё файл styles.css из стандартной темы.
Добавляем в этот файл цвета из примера.
И создаем новую тему в Sources/Blog/Theme+Code.swift на основе стандартной.
public extension Theme {
static var code: Self {
Theme(
htmlFactory: CodeHTMLFactory(),
resourcePaths: ["Resources/CodeTheme/styles.css"]
)
}
}
private struct CodeHTMLFactory<Site: Website>: HTMLFactory {
...
}
Устанавливаем плагин во флоу публикации сайта в main.swift.
import SplashPublishPlugin
...
try Blog().publish(using: [
.installPlugin(.splash(withClassPrefix: "")),
.addMarkdownFiles(),
.copyResources(),
.generateHTML(withTheme: .code),
.generateSiteMap()
])
Готово. Теперь код на Swift будет иметь подсветку синтаксиса. 🌈
Пишем первый пост
Посты хранятся в папке Content/posts/ и представляют собой Markdown файлы.
Отредактируем уже созданый пост first-post.
---
date: 2020-06-24 12:00
description: Ребята, у меня теперь есть блог.
tags: introduction, fun
---
# Первый пост на моём блоге
Ребята, у меня теперь есть блог.
И я могу вставлять код на Swift.
````swift
import Blog
let myBlog = Blog()
myBlog.publish()
````swift
Сгенерируем сайт и увидим наш пост с кодом. 😎