Tutorial: How to use Leaf

Martin Lasek
Mar 8, 2018 Β· 6 min read

Yeey time to learn leaf β€” a templating language to easily generate views!

You can find the result of this tutorial on github here

This tutorial is a natural follow-up of How to set up a Vapor 3 project. You can either go for that tutorial first and come back or just skip it and read on 😊


Index

1. Create a new project
2. Generate the Xcode project
3. Configure your project to use Leaf
4. Create your first template / view
5. Implement a route to serve the view
6. BONUS: Passing data to the view
7. Where to go from here


1. Create a new project

Vapor toolbox is so nice it let’s you easily create new projects using any git-repo as a template. Since we will build upon the outcome of the aforementioned tutorial, we will create a new project using it as a template:

vapor new projectName --template=vaporberlin/my-first-route

Our command will create a project with the name projectName using my-first-route from vaporberlin as a template (thanks vapor toolbox 🀜🏻 πŸ€›πŸ» ).


2. Generate the Xcode project

Before we generate an Xcode project we would have to add Leaf as a dependency and also change the package name within Package.swift:

// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "projectName", // changed
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
.package(url: "https://github.com/vapor/leaf.git", from: "3.0.0") // added
],
targets: [
.target(name: "App", dependencies: ["Vapor", "Leaf"]),
.target(name: "Run", dependencies: ["App"]),
.testTarget(name: "AppTests", dependencies: ["App"]),
]
)

Now in the terminal at the root directory projectName/ execute:

vapor update -y

It may take a bit fetching the dependency, generating the Xcode project and opening it for you. But when done you should have a project structure like this:

projectName/
β”œβ”€β”€ Package.swift
β”œβ”€β”€ Sources/
β”‚ β”œβ”€β”€ App/
β”‚ β”‚ β”œβ”€β”€ app.swift
β”‚ β”‚ β”œβ”€β”€ boot.swift
β”‚ β”‚ β”œβ”€β”€ configure.swift
β”‚ β”‚ └── routes.swift
β”‚ └── Run/
β”‚ └── main.swift
β”œβ”€β”€ Tests/
β”œβ”€β”€ Public/
β”œβ”€β”€ Dependencies/
└── Products/

3. Configure your project to use Leaf

We will have to register the LeafProvider within our configure.swift:

import Vapor
import Leaf // added
public func configure(
_ config: inout Config,
_ env: inout Environment,
_ services: inout Services
) throws {
// Register routes to the router
let router = EngineRouter.default()
try routes(router)
services.register(router, as: Router.self)
let leafProvider = LeafProvider() // added
try services.register(leafProvider) // added
config.prefer(LeafRenderer.self, for: ViewRenderer.self)
}

And also to set the LeafRenderer as our preferred ViewRenderer πŸƒ
This will allow us to access the renderer from within our routes very easy.


4. Create your first template / view

Our view renderer leaf is expecting a directory called Resources/ and right underneath it a directory called Views/ to hold all view-files. So you will end up with a folder structure like this:

projectName/
β”œβ”€β”€ Package.swift
β”œβ”€β”€ Sources/
β”‚ β”œβ”€β”€ App/
β”‚ β”‚ β”œβ”€β”€ app.swift
β”‚ β”‚ β”œβ”€β”€ boot.swift
β”‚ β”‚ β”œβ”€β”€ configure.swift
β”‚ β”‚ └── routes.swift
β”‚ └── Run/
β”‚ └── main.swift
β”œβ”€β”€ Resources/
β”‚ └── Views/
β”œβ”€β”€ Tests/
β”œβ”€β”€ Public/
β”œβ”€β”€ Dependencies/
└── Products/

You may have to re-generate your Xcode project with vapor xcode -y in order to let Xcode see your new directories. When done in Resources/Views/ create a new file named welcome.leaf with following code:

<!DOCTYPE html>
<html>
<head>
<title>Leaf</title>
</head>
<body> <h1> Welcome to my first leaf template! </h1> </body>
</html>

5. Implement a route to serve the view

In your routes.swift add a new route and call it.. hmmm.. πŸ€”

import Vaporpublic func routes(_ router: Router) throws {  router.get("name") { req in
return "Ethan Hunt"
}
router.get("age") { req in
return 23
}
router.get("json") { req in
return Person(name: "Martin J. Lasek", age: 26)
}
router.get("view") { req -> Future<View> in
return try req.view().render("welcome")
}

}
struct Person: Content {
var name: String
var age: Int
}

The function req.view() creates and returns a ViewRenderer. And since we configured LeafRenderer as our ViewRenderer we can use .leaf files πŸƒ!

If you now hit cmd + r or the play button on top of Xcode, it will start the application. The console in Xcode tells you where. For me it’s localhost:8080.

Note: make sure to select Run as a scheme next to your button before running the app

If you now fire up localhost:8080/view in your browser you will get a view served using Leaf as a templating language! πŸ™ŒπŸ»


6. BONUS: Passing data to the view

It’s super easy to pass data into a view. And this is how it looks like:

import Vaporpublic func routes(_ router: Router) throws {  router.get("name") { req in
return "Ethan Hunt"
}
router.get("age") { req in
return 23
}
router.get("json") { req in
return Person(name: "Martin J. Lasek", age: 26)
}
router.get("view") { req -> Future<View> in
return try req.view().render("welcome")
}
router.get("bonus") { req -> Future<View> in
let data = ["name": "Ethan", "age": "26"]
return try req.view().render("whoami", data)
}

}
struct Person: Content {
var name: String
var age: Int
}

If you now create a new file in Resources/Views/ called whoami.leaf you can access the passed data in it like so:

<!DOCTYPE html>
<html>
<head>
<title>Leaf</title>
</head>
<body>
<h1> You rule #(name)! Can't believe you're already #(age)!</h1>
</body>
</html>

If you have a class or struct that conforms to content your are also able to pass an instance of it into the view like so:

import Vaporpublic func routes(_ router: Router) throws {  router.get("name") { req in
return "Ethan Hunt"
}
router.get("age") { req in
return 23
}
router.get("json") { req in
return Person(name: "Martin J. Lasek", age: 26)
}
router.get("view") { req -> Future<View> in
return try req.view().render("welcome")
}
router.get("bonus") { req -> Future<View> in
let developer = Person(name: "Martin", age: 26)
return try req.view().render("whoami", developer)
}
}
struct Person: Content {
var name: String
var age: Int
}

Now re-run your application and fire up localhost:8080/bonus πŸš€
That’s it! You successfully implemented a leaf template project πŸŽ‰ !


7. Where to go from here

You can find a list of all tutorials with example projects on Github here:
πŸ‘‰πŸ» https://github.com/vaporberlin/vaporschool


I am really happy you read my article! If you have any suggestions or improvements of any kind let me know! I’d love to hear from you! 😊

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium β€” and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store