Wednesday, February 8, 2023
HomeiOS DevelopmentBuilding stylesheets using Leaf - The.Swift.Dev.

Building stylesheets using Leaf – The.Swift.Dev.


A quick CSS demo project

The very first step is to add Leaf as a dependency to your project. You should note that Leaf 4 is not finished yet and these brand new features are only available from the tau pre-release.

import PackageDescription

let package = Package(
    name: "myProject",
    platforms: [
    dependencies: [
        .package(url: "", from: "4.32.0"),
        .package(url: "", .exact("4.0.0-tau.1")),
        .package(url: "", .exact("1.0.0-tau.1.1")),
    targets: [
        .target(name: "App", dependencies: [
            .product(name: "Leaf", package: "leaf"),
            .product(name: "Vapor", package: "vapor"),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: [
            .target(name: "App"),
            .product(name: "XCTVapor", package: "vapor"),

We are ready to import Leaf in your Swift files, since there is a new LeafFileMiddleware available as part of Leaf we’re going to create some publicly available template files and use this middleware to render them. Create a new Public directory inside the root folder of the project and place an new index.html file there. You can also use a .leaf extension, but for the sake of simplicity (and Xcode syntax highlighting reasons) we’re going to use the .html extension this time.

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/css/style.css">

Pretty basic HTML5 boilerplate code, except that we’ll print the title using a Leaf tag. We’re going to set a value for this context variable through some Swift code in a moment. In the head section we also import our css/style.css stylesheet file. Now you should create a css folder inside the Public directory and place a style.css file inside of it.

* {
    margin: 0;
    padding: 0;
body {
    font-family: -apple-system, system-ui, BlinkMacSystemFont, "Helvetica", "Segoe UI", Roboto, Ubuntu;
    font-size: 16px;
    line-height: 1.4em;
    background: #(background);
h1 {
    padding: #(padding);
@media (max-width: 599px) {}
@media (min-width: 600px) {}
@media (min-width: 900px) {}
@media (min-width: 1200px) {}
@media (min-width: 1800px) {}

Since this file is “secretly” a leaf template file we can use the #(variable) syntax to print out values. We are going to pass a background color key and a padding key with some custom values as context variables.

Now let me show you how to configure this new LeafFileMiddleware, so we can render both our html and css templates.

import Vapor
import Leaf
public func configure(_ app: Application) throws {

    if !app.environment.isRelease {
        LeafRenderer.Option.caching = .bypass

    LeafFileMiddleware.defaultMediaType = .html
    LeafFileMiddleware.processableExtensions = ["leaf", "html", "css", "js"]
    LeafFileMiddleware.contexts = [
        .css: [
            "background": "#eee",
            "padding": "16px",
        .html: [
            "title": "Hello world!"
    if let lfm = LeafFileMiddleware(publicDirectory: {

First we disable the cache, but that’s a pretty obvious chunk of code, next we set the default media type to html. This will be used to set the Content-Type header if the file extension in the request is an unknown type. The processableExtensions property will tell the LeafFileMiddleware to process and render only these files, everything else with a different extension will be streamed just like when you use a regular FileMiddleware.

As you can see we can set different context values for specific media types, in our case all the css files can use the background and padding properties and every html file can take advantage of the title context variable. It is also possible to set them through a subscript syntax:

LeafFileMiddleware[.css] = [
    "background": "green",
    "padding": "16px",

LeafFileMiddleware[.html] = [
    "title": "Hello world!"

The very last step is to create the actual middleware with a publicDirectory argument. This directory is the location where the system will look for publicly available files and if needed they can be processed as regular Leaf templates. You can also setup directory indexing through the LeafFileMiddleware, but that’s a different topic.

If you navigate to the http://localhost:8080/index.html address you should see your rendered index.html file with the right stylesheet applied to it. Of course you can register a custom route and render your templates using the usual Resources / Views location if needed, but I just wanted to show you this cool trick, since it enables us to serve public files using a more dynamic approach.


Source link



Please enter your comment!
Please enter your name here

Most Popular

Recent Comments