SwiftySites

SwiftySites is a library for generating static websites with Xcode or the Swift Package Manager (SPM). Write your content entirely in Markdown. Create some HTML templates using Swift's string interpolation. Combine it all in a site declaration and export for preview or publication.

Check out the DocC documentation for more. Source code available here.


DocC and Netlify

dl on 8 Sep 2021

On a previous post I discussed how to merge a DocC documentation archive into a SwiftySites-generated website.

Now Apple provides some guidelines on how to make the exported site play nice with your web server using rewrites.

But with static sites it is common not to have such control over the server side. We instead prefer services like GitHub Pages and Netlify which is the one used by this page.

There is already a great write-up on how to integrate DocC with Netlify. I had to make a few tweaks here and there but the solution pretty much worked seamessly.

Finally here's the resulting configuration used to host SwiftySites's own DocC documentation.

netlify.toml
[[redirects]]
from = "/documentation/*"
status = 200
to = "/SwiftySites.doccarchive/index.html"

[[redirects]]
from = "/tutorials/*"
status = 200
to = "/SwiftySites.doccarchive/index.html"

[[redirects]]
from = "/data/documentation.json"
status = 200
to = "/SwiftySites.doccarchive/data/documentation/root.json"

[[redirects]]
from = "/css/*"
status = 200
to = "/SwiftySites.doccarchive/css/:splat"

[[redirects]]
from = "/data/*"
status = 200
to = "/SwiftySites.doccarchive/data/:splat"

[[redirects]]
from = "/downloads/*"
status = 200
to = "/SwiftySites.doccarchive/downloads/:splat"

[[redirects]]
from = "/images/*"
status = 200
to = "/SwiftySites.doccarchive/images/:splat"

[[redirects]]
from = "/img/*"
status = 200
to = "/SwiftySites.doccarchive/img/:splat"

[[redirects]]
from = "/index/*"
status = 200
to = "/SwiftySites.doccarchive/index/:splat"

[[redirects]]
from = "/js/*"
status = 200
to = "/SwiftySites.doccarchive/js/:splat"

[[redirects]]
from = "/videos/*"
status = 200
to = "/SwiftySites.doccarchive/videos/:splat"

[[redirects]]
from = "/metadata.json"
status = 200
to = "/SwiftySites.doccarchive/metadata.json"

[[redirects]]
from = "/theme-settings.json"
status = 200
to = "/SwiftySites.doccarchive/theme-settings.json"

Theme Switch

dl on 7 Sep 2021

The websites generated by Apple's DocC tool all feature this very handy toggle for switching between dark and light themes. In a previous post the idea of merging a SwiftySites blog with a DocC web archive was introduced. Wouldn't it be nice to have that same theme-switching control on all pages?

Introducing Theme Switch by SwiftySites. Theme Switch is a web component that replicates both the look and behaviour of Apple's control with some additional features.

Theme Switch

Unlike the DocC toggle which is implemented using Vue.js, Theme Switch does not have any dependencies and instead is implemented with pure Javascript as a standard v1 HTML Custom Element.

It allows you to define your own dark mode CSS and display it only when your users wish it. When in automatic mode it will honor the system's preference. And if your browser does not support CSS color scheme preferences the component will just let the user pick between the two options.

Try it out on your own websites or better yet try it on your SwiftySites website!


DocC Website

dl on 6 Sep 2021

This site has two functions. One is to be a real-world test of the SwiftySites framework – documenting its evolution. The other is the more traditional role of hosting the tool's documentation.

The DocC Framework is brand new but a fills up a gap previously covered by open-source efforts. Since SwiftySites is also new I thought it would be the perfect fit to try out the officially sanctioned way of generating docs.

In a way DocC is its own static site generator not unlike SwiftySites. It uses comments on the source code as well as standalone Markdown files as input and it applies internal HTML templates to produce a website. So the challenge becomes how to merge the DocC-generated site into this present site.

Apple has a guide which includes how to Host a Documentation Archive on Your Website. It simply involves exporting the generated bundle from the Xcode viewer.

My solution was to straightforwardly dump the exported DocC archive into the static folder of this very site's source repo. SwiftySites will copy all static contents and only then generate the new outputs on top so we only need to be careful not to call things with the same name.

The final result can be seen here in all its glory.


Syntax Highlighting

dl on 5 Sep 2021

After overcomming the first big challenge of implementing Markdown support I found out rather quickly that this did not include any type of syntax hightlighting.

All pre blocks were rendered with no color and the code block info string was largely ignored by my basic stylesheet.

Once again I turned to Apple and noticed they were using highlight.js to generate the code blocks used in DocC.

I decided to customize my download to include only the languages I would need for this blog. I also picked one of the many color schemes they have available.

To put it to the test what better way than including a chunk of the code used to generate this exact page with SwiftySites. Lo and behold the coloring magically appears.

main.js
let homePage = Page("Home Page", path: "/") { """
_Some markdown here…_
"""

let pageTemplate = BasicSite.templateA { site, page in """
<!doctype html>
<html lang="en">
    …
    <title>\(site.title)</title>
    …
    <main>\(page.content)</main>
    …
</html>
""" }

BasicSite(
    SiteConfig(title: "SwiftySites"),
    contentA: [homePage],
    templates: [pageTemplate]
).render()

Now having inspected a DocC-generated site I have noticed that Apple is using a custom language definition for highlight.js. Since the code is obfuscated I couldn't extract it to incorporate into this site. Still the default Swift definition is decent enough and all of the other languages render nicely.


Supporting Markdown

dl on 4 Sep 2021

One of the first challenges one encounters when building a static site generator is Markdown support.

I knew Apple had just announced during WWDC21 support for Markdown in attributed strings and other APIs but offered no interface for directly converting Markdown to HTML.

A bit of digging in the developer forums led me to this answer by an Apple engineer. Now I knew for a fact that internally they were using the fantastic cmark-gfm library.

cmark-gfm itself is a fork of the cmark C library. GFM stands for GitHub Flavor Markdown and consists of a set of extensions to the CommonMark specification.

Having some experience in integrating C code into Swift applications I started adapting cmark-gfm for my purposes. The endeavour involved cross-compiling for the relevant architectures and linking to a custom Objective-C framework.

Since cmark-gfm lacked a simplified interface for straightforwardly converting GFM to HTML – which the original cmark had – I decided to write my own Swift protocol around it. I decided to expose all the options and extensions available from the underlying libraries.

While the whole effort was open-source I decided to publish the final result as a binary XCFramework. This makes it really easy to include – via Swift Package Manager (SPM) – in SwiftySites or any other project that needs it without the hassle of having to build everything from C sources.


Hello, World!

dl on 3 Sep 2021

Hello and welcome to the humble SwiftySites Blog. As a first post I thought it would be nice to share some of my motivation for building this library.

Nowadays it's pretty common for a programmer to want to show their work and process to the world. It's also common for us to write our own tools.

In the past I had used everything from traditional content management systems to popular publishing platforms. For the past few years I settled for the awesome Hugo static site generator which I used to build the original Swift You and I publication.

Hugo has a lot of amazing features which I love but it dows require some knowledge of the Go Language for writing the more advanced templates. For a long time I tried my best to learn but never felt as at home as I do when I write Swift.

Looking for options I quiclky landed in John Sundell's tool Publish. To be perfectly honest this would have been the tool to choose from the beginnig – had it existed a couple of years back.

At this point I had gotten accustomed to many of the niceties of Hugo and wanted to keep some of them around. John's DSL approach showed me that the Swift compiler can really be helpful when defining a website's structure so I came up with a hybrid concept.

Instead of declaring everything straight in Swift I decided to split the problem in two. For the content's metadata – which Hugo implements with Front Matter – I would leverage the full power of Swift's type system. For the templates I thought of something else…

Swift already has a great templating solution called string interpolation. This was the last piece of the puzzle. From the first proof of concept I noticed how nicely the structured metadata merged with the more free string composition.

In the coming weeks I will use this very site to test the concept and document the process of building a framework that hopefully other people find useful.

Cheers!