Website Transition to Publish
Website Transition to Publish
This is a classic blow-by-blow blog of the steps to recreate the vation.ca website from a Hugo publishing theme to a Publish based delivery. This is not strictly required but I have plans to use the Publish toolset in a combined static-dynamic website publishing mode in the future. So the best way to learn the capabilities of Publish is to learn by moving a site, rather than just doing a new site from a "Hello World" example. This blog won't age well and may only be of interest to any other early adopters of Publish.
Well, I wrote this first paragraph in early 2020 and am coming back to the article in 2021. I originally had taken a path of modifying the Publish tools to deal with transition issues. The rest of the content did not age well as I predicted and I am rewriting it all. My 2021 attack is to use Publish as-is as a challenge. I will accumulate issues that I cannot find a workaround for and negotiate/contribute fixes after. That way I will have more experience with the strengths and intent of John Sundell's toolset and stay as close to the main branch and focus on the items I need.
Copy the Markdown content files
I needed to convert the TOML based metadata to YAML that was more parse friendly to the Ink tool. I used a web-based tool https://toolkit.site/format.html to convert the TOML to YAML and paste it back into the markdown source.
Permalink preservation
The Publish tool currently publishes to links derived from the Content folder structure and filenames. I had been using the Hugo permalink setup. The permalinks can be preserved by adding folders Post and subfolder 2020, inside the Content folder. The filename for the markdown file is changed to what I had specified as "slug" in the Hugo front-matter.
The markdown files do not parse
The YAML has some formatting not understood by Ink. To fix this for now, I implemented a YAML parse for the subset of simple cases that were generated by the conversion tool. You can see the code on my Ink fork. I am using this fork to implement some basic parsing updates to do some CommonMark conformance. Other people that are porting sites from Hugo may need these too?
Match the existing Vation.ca theme
Now comes the fun bit. The website is defined in Swift code. There did not exist any hint on custom theme development, so I did some Swift code bashing.
First I copied the Theme+Foundation.swift module into a Theme+Vation.swift file in my Vationsite folder. Here is the hacking I did to use my theme, .vation
public extension Theme {
/// The default "Foundation" theme that Publish ships with, a very
/// basic theme mostly implemented for demonstration purposes.
static var vation: Self {
Theme(
htmlFactory: VationHTMLFactory(),
resourcePaths: ["Resources/VationTheme/css/style.css"]
)
}
}
private struct VationHTMLFactory<Site: Website>: HTMLFactory {
func makeIndexHTML(for index: Index,
context: PublishingContext<Site>) throws -> HTML {
HTML(
)
Making the theme components
)
)
)
)
)
)
)
)
}
An old Lisp joke: Above is my code for the end of the header. Took more than 20 minutes to get the commas and ")"s in the right place. Next time I will add a comment after each ")", like:
)//button
)//form
)//section
)//div flex-column )
)//div-inline-flex
)//div-flex-row
)//div-container
}
This might save the 20 minutes with 2 minutes of extra typing. Liberal use of Editor>Structure>Re-indent will probably help too.
breadcrumbs
I tried to use XCode breakpoints to discover the path info that I could use to format a breadcrumb component. My attempts have been unsuccessful as lldb gives these failures:
Printing description of section:
(Publish.Section<Site>) section = {
id = <extracting data from value failed>
items = <extracting data from value failed>
I will have to publish without breadcrumbs for now, while I wait for patience to single step the publishing steps to find the info structure.
I looked a little harder and I could do the breadcrumbs but the HTML Factory calls for all the page types are different, so I would have to declare a shared Breadcrumb struct to pass to the .header builder.
For now I will have to make the Vation.ca site look like swiftbysundell, with a master nav menu, and move the search to its own page to make room in the page header for the nav menu.
I hope that Publish evolves to a product like Gatsby and will start to be compatible with upstream headless CMS data sources. The upstream source would likely handle the management of multi-lingual content and the hiding of draft documents.
Publish could produce up-to-date static content with all URLs pointing to the latest content. It would be a Swift coded deployment operation tool. The use of a file folder structure would be a basic case when no headless CMS is used. The ultimate publishing tree would be managed in the headless CMS and Publish would be able to rebuild any desired site from content separated from presentation.
Support for draft and future date publishing
I am missing the draft option from Hugo. I was expecting to be able to edit the Content folder for item not ready to publish. A draft metadata item would allow optional production of the site with and without drafts so that they can be polished with respect to any html additions.
The production generation of the site would not include them. The missing functionality in publish is to be able to remove items that have a draft status. This is needed because the new tags from a draft cannot leak.
This logic can be used to handle publishing deferred release articles using a metadata date and some logic.
Other things like waiting for a translated version of the page before release. You could publish the draft site or item so that the translator can see the page context.
The latest JSON-LD structured data
A modern method of structured data uses JSON-LD as the format. It can replace the jumble of <meta> elements and microdata markup that is hard to sprinkle into the html.
I generate this into the <head> section. I had to hack the HTMLFactory to get a more general injection of the metadata needed to pass to the JSON-LD builder. All the Factory methods have a different function signature that seems pretty specific to the blog structure. The JSON-LD needs to have access to section and website metadata.
Most of the schema.org definitions have dates that are ISO8601 format > A combination of date and time of day in the form [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] (see Chapter 5.4 of ISO 8601)
Curiously, Apple now have a recommendation to use a new class ISO8601DateFormatter : Formatter recommendation that is not the current DateFormatter. The format looks like it can be handled by DateFormatter.
Secondary issue is that markdown traps and failures probably need to have a handler that can indicate filename and line number to help. And perhaps continue on so that they don't need one at a time fixer.
[step] Add Markdown files from 'Content' folder[path] /Users/hume/Developer/VationSite/Content/index.md[info] Invalid metadata value for key 'date': file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1100.8.280/swift/stdlib/public/core/ErrorType.swift, line 200
Fixed with
.step(named: "Use custom DateFormatter") { context in
let RFC3339DateFormatter = DateFormatter()
RFC3339DateFormatter.locale = Locale(identifier: "en_US_POSIX")
RFC3339DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
RFC3339DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
context.dateFormatter = RFC3339DateFormatter
},
and repairing all the date formats back to the ISO form that I will need in the JSON-LD.
Copyright ©2021 Steve Hume
Tagged with: