Skip to content

About

A modern Swift 6 framework for building fast, type-safe static websites.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

SwiftSite

A modern Swift 6 framework for building fast, type-safe static websites.

SwiftSite replaces stagnated tooling (Publish, Plot, Ink) with idiomatic Swift 6: a result-builder pipeline, an any Component HTML DSL, AST-based Markdown parsing, and first-class retina and dark mode image support. Your site's content schema, sections, and theme are all Swift types — no configuration files, no runtime reflection.

Requirements

  • macOS 15+
  • Swift 6

Installation

Add SwiftSite to your Package.swift:

dependencies: [
    .package(url: "https://github.com/your-org/swift-site.git", from: "1.0.0"),
],
targets: [
    .executableTarget(
        name: "MySite",
        dependencies: [
            .product(name: "SwiftSiteCore", package: "swift-site"),
            .product(name: "SwiftSiteHTML", package: "swift-site"),
            .product(name: "SwiftSiteMarkdown", package: "swift-site"),
        ]
    ),
]

Quick Start

1. Define your site

// MySite.swift
import SwiftSiteCore

struct MySite: Site {
    var url = URL(string: "https://example.com")!
    var name = "My Site"
}

enum MySiteSection: String, SiteSection {
    case blog
    case about
}

struct MyMetadata: ItemMetadataProtocol {
    var featured: Bool?
    var author: String?
}

2. Build a theme

// MyTheme.swift
import SwiftSiteCore
import SwiftSiteHTML

struct MyTheme: Theme {
    typealias S = MySite

    func makeIndexPage(index: SiteIndex<MySite>, context: GenerationContext<MySite>) -> HTMLDocument {
        HTMLDocument {
            TitleTag(context.site.name)
        } body: {
            H1("Welcome to \(context.site.name)")
            UL {
                for item in context.allItems {
                    LI { Link(item.title, url: item.path.absoluteString) }
                }
            }
        }
    }

    // ... makeItemPage, makeSectionPage, makeStandalonePage
}

3. Wire up the pipeline

// Main.swift
import SwiftSiteCore

@main
struct MySiteApp: SiteApplication {
    @OptionGroup var options: SiteOptions

    var site: MySite { MySite() }

    var pipeline: Pipeline<MySite> {
        Pipeline {
            CopyResources()
            ParseMarkdownFiles()
            SortItems(by: \.date, order: .descending)
            GenerateHTML(theme: MyTheme())
            GenerateSiteMap()
        }
    }
}

4. Write content

Content/
├── index.md
└── blog/
    ├── index.md
    └── hello-world.md
---
title: Hello, World!
date: 2024-06-01
featured: true
---

Your content here.

5. Generate

swift run MySiteApp --content Content --output Output

Modules

Module Purpose
SwiftSiteCore Content model, pipeline engine, built-in steps, SiteApplication
SwiftSiteHTML HTML DSL — Component protocol, result builder, all standard elements
SwiftSiteMarkdown Markdown + YAML parsing, plugin system
Bootstrap Bootstrap 5 utility DSL for themes

SwiftSiteCore

The pipeline engine. Define a Site, declare a Pipeline of PipelineStep values, and run it via the SiteApplication protocol.

Built-in steps:

Step Description
GenerateRetinaImages() Downscales @3x images to @2x and @1x using sips
CopyResources() Copies Resources/ into the output directory
ParseMarkdownFiles(plugins:) Parses all .md files, decodes frontmatter, renders Markdown
SortItems(by:order:) Sorts all items by a key path
GenerateHTML(theme:) Renders every page via your Theme
GenerateSiteMap() Writes sitemap.xml

SwiftSiteHTML

A composable HTML DSL built on any Component existentials and @HTMLBuilder. Every HTML element is a named Swift type; attributes are applied with fluent modifiers:

Article {
    H2 { Link(item.title, url: item.path.absoluteString) }
    Paragraph(item.description).class("text-muted")
    RawHTML(item.body.html)
}
.class("card", "mb-4")
.id("post-\(item.path.lastComponent)")

Retina and dark mode images:

// Retina only — serves @1x, @2x, @3x via srcset
RetinaPicture(url: "/images/hero@3x.png", alt: "Hero image")

// Retina + dark mode
RetinaPicture(url: "/images/hero@3x.png", alt: "Hero image", includeDark: true)

// With inner <img> modifier
RetinaPicture(url: "/images/hero@3x.png") { img in
    img.data("aos", value: "fade-left")
}

Provide hero@3x.png and (optionally) hero-dark@3x.png in Resources/ — GenerateRetinaImages produces the @2x and @1x variants automatically.

SwiftSiteMarkdown

Parses Markdown using Apple's swift-markdown (AST-based, CommonMark + tables + strikethrough). YAML frontmatter is decoded with Yams.

Markdown plugins intercept specific node types during rendering:

ParseMarkdownFiles(plugins: [
    RetinaImagePlugin(includeDark: true),   // @3x → <picture> with srcset
    HeadingAnchorPlugin(),                  // adds id= slugs to headings
])

Implement MarkdownPlugin to customise image, heading, or code block rendering.

Environment Values

Pass values down the component tree without threading parameters manually:

extension EnvironmentKeys {
    var currentPath: EnvironmentKey<String> { .init(defaultValue: "") }
}

// Set at the page level
Nav { /* links */ }.environmentValue(item.path.absoluteString, for: \.currentPath)

// Read anywhere in the tree
struct NavLink: BodyComponent {
    @EnvironmentValue(\.currentPath) var currentPath
    let title: String; let url: String
    var body: any Component {
        Link(title, url: url).class("active", when: url == currentPath)
    }
}

Writing Custom Pipeline Steps

struct RemoveDrafts<S: Site>: PipelineStep {
    var name: String { "Remove drafts" }
    func run(context: inout GenerationContext<S>) async throws {
        for id in S.SectionID.allCases {
            context.sections[id]?.items.removeAll {
                ($0.metadata as? DraftMetadata)?.draft == true
            }
        }
    }
}

Documentation

Full DocC documentation is available in Xcode — open the package and choose Product → Build Documentation.

Conceptual articles:

License

SwiftSite is available under the MIT license. See LICENSE for details.

About

A modern Swift 6 framework for building fast, type-safe static websites.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages