Usually developers prefer to segregate backend and frontend. Several frameworks allow to develop frontend and backend together, Vapor is one of them (i.e. Ruby on Rails, Django, etc).
Time to time heated debates start about the “best” method how to style your frontend. Whether writing CSS totally from scratch is the best or using CSS frameworks(i.e. Bootstrap, Foundation, Bulma).
My favourite CSS framework is TailwindCSS, as I hardly do any web development, my CSS skills are very limited. It helps me a lot, if I need to put together HTML+CSS very fast.
Create a new Vapor project:
vapor new tailwind_vapor -n
Add Leaf, the templating language, to Package.swift
:
dependencies: [
// π§ A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.89.0"),
// Leaf templating language
.package(url: "https://github.com/vapor/leaf.git", from: "4.0.0")
],
targets: [
.executableTarget(
name: "App",
dependencies: [
.product(name: "Vapor", package: "vapor"),
// Leaf templating language
.product(name: "Leaf", package: "leaf")
]
),
Leaf has multiple purposes, one of them is βto generate dynamic HTML pages for a front-end website or generate rich emails to send from an APIβ as written in the documentation.
Create PagesController.swift
We will store the routes and templates in this new controller.
Create the file, PagesController.swift
under Sources/App/Controllers
:
import Leaf
import Vapor
struct PagesController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
routes.get(use: index)
}
func index(_ req: Request) -> EventLoopFuture<View> {
return req.view.render("index")
}
}
We set the route and ready to render the file called index.leaf
Create index.leaf
template
Create two new folders Resources/Views
. So your folder structure will look like this:
.
βββ Dockerfile
βββ Package.resolved
βββ Package.swift
βββ Public
βββ Resources
β βββ Views
βββ Sources
β βββ App
β βββ Controllers
β β βββ PagesController.swift
β βββ configure.swift
β βββ entrypoint.swift
β βββ routes.swift
βββ Tests
β βββ AppTests
β βββ AppTests.swift
βββ docker-compose.yml
Add index.leaf
file to your new folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Vapor 4 and Tailwind CSS</title>
</head>
<body>
<h1>It works...perfectly π</h1>
</body>
</html>
We need to register our new controller and remove the default /index
route.
Register the Pages
controller
Remove the content of routes
function in the routes.swift
and update with the following:
import Vapor
func routes(_ app: Application) throws {
try app.register(collection: PagesController())
}
The last thing you need to add to import Leaf
and app.views.use(.leaf)
to configure.swift
:
import Leaf
import Vapor
// configures your application
public func configure(_ app: Application) async throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
// use Leaf
app.views.use(.leaf)
// register routes
try routes(app)
}
You can test your application now:
Add Tailwind CSS
The easiest way to use Tailwind CSS in your project is SwiftyTailwind. It has a simple but understandable documentation.
Update the Package.swift
:
dependencies: [
// π§ A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.89.0"),
// Leaf templating language
.package(url: "https://github.com/vapor/leaf.git", from: "4.0.0"),
// Tailwind CSS
.package(url: "https://github.com/tuist/SwiftyTailwind.git", .upToNextMinor(from: "0.5.0"))
],
targets: [
.executableTarget(
name: "App",
dependencies: [
.product(name: "Vapor", package: "vapor"),
// Leaf templating language
.product(name: "Leaf", package: "leaf"),
// Tailwind CSS
.product(name: "SwiftyTailwind", package: "SwiftyTailwind")
]
),
]
Create tailwind.swift
file
Under Sources/App
create a file called, tailwind.swift
and add:
import SwiftyTailwind
import TSCBasic
import Vapor
func tailwind(_ app: Application) async throws {
let resourecesDirectory = try AbsolutePath(validating: app.directory.resourcesDirectory)
let publicDirectory = try AbsolutePath(validating: app.directory.publicDirectory)
let tailwind = SwiftyTailwind()
try await tailwind.run(
input: .init(validating: "Styles/app.css", relativeTo: resourecesDirectory),
output: .init(validating: "styles/app.generated.css", relativeTo: publicDirectory),
options: .content("\(app.directory.viewsDirectory)/**/*.leaf")
)
}
Update configure.swift
First uncomment this line to use Public folder:
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
Then add try await tailwind(app)
to use the earlier created tailwind
function.
Your final configure.swift
file looks:
// configures your application
public func configure(_ app: Application) async throws {
// uncomment to serve files from /Public folder
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
// use Leaf
app.views.use(.leaf)
// use Tailwind CSS
try await tailwind(app)
// register routes
try routes(app)
}
Add stylesheet to index.leaf
Add the following to the <head>
section:
<link rel="stylesheet" href="/styles/app.generated.css" />
Your final index.leaf
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Vapor 4 and Tailwind CSS</title>
<link rel="stylesheet" href="/styles/app.generated.css" />
</head>
<body>
<div class="flex h-screen justify-center items-center bg-black">
<div class="text-center">
<h1 class="text-xl text-white">It works...perfectly π</h1>
</div>
</div>
</body>
</html>
Add app.css
Add the initial app.css
to /Resources/Styles
folder:
@tailwind base;
@tailwind components;
@tailwind utilities;
If you run your application now, you will see:
Final folder structure looks like:
.
βββ Dockerfile
βββ Package.resolved
βββ Package.swift
βββ Public
β βββ styles
β βββ app.generated.css
βββ Resources
β βββ Styles
β β βββ app.css
β βββ Views
β βββ index.leaf
βββ Sources
β βββ App
β βββ Controllers
β β βββ PagesController.swift
β βββ configure.swift
β βββ entrypoint.swift
β βββ routes.swift
β βββ tailwind.swift
βββ Tests
β βββ AppTests
β βββ AppTests.swift
βββ docker-compose.yml
With the help of Tailwind CSS we can create beautiful webpages, without writing a lots of CSS codes.
Source code is here.