Moderne, HTML basierte Anwendungen nutzen meist Single-Page-Application (SPA) Frameworks wie z. B. Angular, mit denen dynamische HTML-Oberflächen erstellt werden, die dem Benutzer ein flüssiges und reaktionsfreudiges Erlebnis bieten. Anstatt bei jeder Interaktion die gesamte HTML-Seite neu zu laden, werden nur die notwendigen Daten und Inhalte dynamisch per JavaScript bzw. TypeScript aktualisiert. Der Server liefert nur Fragmente, die auf dem Client dynamisch zu einer kompletten Oberfläche zusammengesetzt werden.
SPA-Anwendungen erfordern so gut wie immer die Verwendung verschiedener Programmiersprachen. Setzt man beispielsweise auf Go/Golang als Sprache auf dem Server, muss für das Frontend JavaScript bzw. Typescript eingesetzt werden.
Diese Multi-Sprache-Entwicklung erhöht die Komplexität des Entwicklungsprozesses und führt zu Mehrarbeit, erhöhtem Wartungsaufwand und zu potenziellen Fehlerquellen. Single-Page-Application (SPA)-Frameworks erfordern z. B. zum Entwicklungszeitpunkt meist einen separaten Server der die entsprechenden HTML-Fragmente und JavaScript ausliefert. Dieser muss dann zusätzlich zum Backend, welches die Business-Logik implementiert, betrieben werden und mit diesem kommunizieren.
In großen, komplexen Anwendungen oder sehr dynamischen Umgebungen kann sich dieser Aufwand rechtfertigen. Doch in kleineren Anwendungen mit weniger Dynamik in der Oberfläche kann auf diesen Aufwand verzichtet werden.
Wenn der Server alternativ vollständige HTML-Seiten bereitstellt, ist die Verwendung von JavaScript auf der Client-Seite überflüssig. Dadurch entfällt auch die Notwendigkeit, eine weitere Programmiersprache einzusetzen.
Sollen vom Server vollständige HTML Seiten ausgeliefert werden, müssen diese bereits auf dem Server dynamisch erstellt werden. Dabei unterstützen sogenannte Templating-Frameworks diesen Prozess.
Ein Templating-Framework ermöglicht nicht nur die eigentliche Erstellung von HTML-Seiten, sondern sorgt auch für eine bessere Trennung von Inhalt und Layout. Entwickler können mithilfe des Frameworks HTML-Templates definieren, die Platzhalter für dynamische Inhalte enthalten. Diese Platzhalter werden zur Laufzeit mit Daten aus verschiedenen Quellen, zum Beispiel Datenbanken, gefüllt, um die finale HTML-Seite zu generieren.
templ ist ein modernes Templating-Framework für Go, das speziell für die Entwicklung von Webanwendungen optimiert ist und einige Vorteile bietet:
Templ geht einen eigenen Weg bei der Definition von Templates. Anstatt die Standard-Template-Syntax von Go zu verwenden, führt Templ eine eigene, intuitivere Syntax ein, die speziell auf die Bedürfnisse der Webentwicklung zugeschnitten ist.
Diese Templates werden über Kommandozeilenwerkzeuge zu Go-Code transformiert, der wiederrum in einer eigenen Anwendung integriert werden kann. Der Ablauf ist einfach und in folgendem Bild dargestellt:
go install
Um Tempel nutzen zu können, muss zunächst das Kommandozeilenwerkzeug installiert werden.
Ab Version 1.20 von Go ist dazu das folgende Kommando ausreichend:
go install github.com/a-h/templ/cmd/templ@latest
Danach sollte das Tool templ
im bin
-Ordner des Workspaces installiert sein
und aufgerufen werden können:
Der
bin
-Ordner des Workspaces sollte bei der Go-Installation auf jeden Fall in den Ausführungspfad ($PATH
) aufgenommen werden!
templ --help
Nun kann mit der Arbeit an den Templates begonnen werden. Das folgende Beispiel
zeigt eine templ-Datei (hello.templ
) mit der Definition eine Komponente:
der Hello
-Komponente. Sie ist für die Generierung des HTML-Codes zuständig:
Die Datei sieht im ersten Moment wie eine Go-Datei aus, ist es aber nicht!
//Templ Datei 'hello.templ'
package main
templ Hello(name string) {
<div>Hello, { name }</div>
}
Durch den Aufruf des templ-Kommandozeilenwerkzeugs (templ generate
hello.templ
) wird daraus die Datei hello_templ.go
mit folgendem gekürzten
Inhalt:
// Die Templ Datei in Go umgewandelt - 'hello_templ.go'
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.819
package main
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Hello(name string) templ.Component {
return templruntime.GeneratedTemplate(...)
}
Mit dem Kommando
templ generate --watch
können templ-Dateien auf Änderungen überwacht und direkt neu transformiert werden.
Wie zu sehen wird die Funktion Hello
erzeugt, die ein Objekt vom Typ
templ.Component
als Rückgabewert liefert. Innerhalb der Funktion wird über
templ-eigenen Code die HTML-Struktur erzeugt und z. B. auch das eventuell nötige
Sonderzeichen-Escaping der übergebenen Werte durchgeführt.
Der Rückgabetyp ist, wie erwähnt templ.Component
. Dabei handelt es sich um ein
Single-Method-Interface, das die Methode Render
definiert. Durch ihren
Aufruf kann der HTML-Code der Komponente in einen io.Writer
geschrieben
werden.
// Das Single-Method-Interface zum Schreiben der HTML-Daten
type Component interface {
Render(ctx context.Context, w io.Writer) error
}
Innerhalb einer Anwendung kann anschließend eine Komponente instanziiert werden
und über das Interface Component
ausgegeben werden:
package main
import (
"context"
"os"
)
func main() {
component := Hello("Kristian")
component.Render(context.Background(), os.Stdout)
}
Möchte man nicht nur statischen HTML-Code erzeugen, kann templ auch in einen HTTP-Server integriert werden. Ein Beispiel soll den Einsatz innerhalb eines Services zeigen.
Die Anwendung besteht aus zwei Seiten, deren HTML über templ erzeugt wird.
Beide HTML-Seiten werden, wie erwähnt, durch templ-Code bzw. Komponenten
erzeugt. die Komponente Form
erzeugt das Formular der ersten Seite und die
Komponente SayHello
übernimmt die Darstellung auf der zweiten Seite.
Innerhalb des Beispiels werden noch zwei weitere Komponenten definiert:
page
- Diese Komponente definiert den Seitenrahmen der HTML-Seite und
bindet das zur Darstellung benötigte CSS ein. Für die Einbindung einer der
eigentlich Inhalts-Komponente nutzt das Template eine Funktionalität von templ
zum Verschachteln von Komponenten. Diese können als Parameter angegeben werden
und innerhalb des Templates mit dem @
-Zeichen referenziert werden.
Error
- Die Komponente Error
gibt lediglich im Fehlerfall einen Text
aus.
Hier der Code des templ-Templates zur Definition der Komponenten:
package http
import "fmt"
// Komponenten können auch als Parameter verwendet werden!
// Mit dem @-Zeichen können sie dann entsprechend innerhalb
// anderer Komponenten referenziert werden.
templ page(contents templ.Component) {
<html>
<head>
<link href="...bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>Templ Application</h1>
@contents
</div>
</body>
</html>
}
templ Error(err error) {
<b>{ fmt.Sprintln(err) }</b>
}
templ Form() {
<form action="/hello" method="post">
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input id="name" type="text" name="name" class="form-control" required/>
</div>
<input type="submit">
</form>
}
templ SayHello(name string) {
<div>Hello, { name }</div>
<a href="/hello">Back</a>
}
Nach der Generierung des entsprechenden Go-Codes mit dem
templ-Kommandozeilenwerkzeug, können diese in eine Server-Implementierung
eingebunden werden. Hierzu bietet templ diverse Helper-Funktionen an. Im
Beispiel wird zum einen templ.Handler
genutzt um eine Komponente als
http.Handler
nutzbar zu machen, und zum anderen wird eine http.HandlerFunc
für die Formularauswertung genutzt.
package http
import (
"github.com/a-h/templ"
"net/http"
)
func StartServer(binding string) error {
http.Handle("GET /hello", templ.Handler(page(Form())))
http.HandleFunc("POST /hello", func(writer http.ResponseWriter, request *http.Request) {
err := request.ParseForm()
if err != nil {
page(Error(err)).Render(request.Context(), writer)
return
}
name := request.Form.Get("name")
page(SayHello(name)).Render(request.Context(), writer)
})
return http.ListenAndServe(binding, nil)
}
Zum Schluss kann der Server in einer entsprechenden Main-Funktion gestartet werden:
package main
import (
"fmt"
"golang.source-fellows.com/templ/internal/http"
)
func main() {
fmt.Println(http.StartServer(":8088"))
}
Wie das Beispiel zeigt bietet Templ eine komfortable Möglichkeit zur Generierung von HTML-Code. Wenn man auf JavaScript Code verzichten möchte bzw. muss, aber trotzdem schnelle, reaktive Web-Anwendungen erstellen möchte, ist templ sicherlich eine interessante Alternative.
Probier es einfach aus! https://templ.guide/
23.01.2025
Der Author auf LinkedIn: Kristian Köhler und Mastodon: @kkoehler@mastodontech.de
Der praktische Soforteinstieg für Developer und Softwarearchitekten, die direkt mit Go produktiv werden wollen.
zur Buchseite beim Rheinwerk Verlag Rheinwerk Computing, ISBN 978-3-8362-7559-0 (als PDF, EPUB, MOBI und Papier)
Source Fellows GmbH
Lerchenstraße 31
72762 Reutlingen
Telefon: (0049) 07121 6969 802
E-Mail: info@source-fellows.com