HTML Generierung mit templ mit Golang/Go

HTML Generierung mit templ mit Golang/Go

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.

Multi-Sprache-Entwicklung

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.

Lohnt der Aufwand?

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.

Komplexe Entwicklung

Komplexe Entwicklung

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.

Templating Frameworks

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 - HTML Templating in Go

templ ist ein modernes Templating-Framework für Go, das speziell für die Entwicklung von Webanwendungen optimiert ist und einige Vorteile bietet:

  • Komponentenbasierte Architektur
  • Typsicherheit
  • Verbesserte Leistung
  • Server-Side Rendering (SSR)
  • Keine Notwenigkeit von JavaScript
  • IDE-Unterstützung
  • Schleifen, Bedingungen und Variablen

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.

Vom Template zum Code

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:

Ablauf templ

Ablauf templ

Templ Installation über 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

Code-Generierung für Templates

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)
}

Go-basierter HTTP-Server liefert HTML

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.

Bestandteile der Templ-Anwendung

Die Anwendung besteht aus zwei Seiten, deren HTML über templ erzeugt wird.

  • Die erste Seite besteht aus einem Formular, in das ein Namen eingegeben werden kann. Das Formular kann durch einen Button an den Server übermittelt werden.
Screenshot 1 templ App (Form)

Screenshot 1 templ App (Form)

  • Auf der zweiten Seite wird der durch das Formular übergebene Name ausgegeben.
Screenshot 2 templ App (SayHello)

Screenshot 2 templ App (SayHello)

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.

Beispiel-Code für templ-basierte Go-Anwendung

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"))
}

Fazit

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

Kennen Sie schon das Buch zum Thema?

Der praktische Soforteinstieg für Developer und Softwarearchitekten, die direkt mit Go produktiv werden wollen.

  • Von den Sprachgrundlagen bis zur Qualitätssicherung
  • Architekturstil verstehen und direkt anwenden
  • Idiomatic Go, gRPC, Go Cloud Development Kit
  • Cloud-native Anwendungen erstellen
Microservices mit Go Buch

zur Buchseite beim Rheinwerk Verlag Rheinwerk Computing, ISBN 978-3-8362-7559-0 (als PDF, EPUB, MOBI und Papier)

Kontakt

Source Fellows GmbH

Source Fellows GmbH Logo

Lerchenstraße 31

72762 Reutlingen

Telefon: (0049) 07121 6969 802

E-Mail: info@source-fellows.com