In deel 1 heb ik de ontwikkelomgeving ingericht. Nu ga ik verder met het thema — hoe ik een bestaand HTML-template heb omgebouwd naar een werkend Hugo-thema.
Een nieuw thema aanmaken
hugo new theme portfolio
Dit genereert themes/portfolio/ met de volgende structuur:
themes/portfolio/
├── assets/
├── layouts/
│ ├── _default/
│ │ ├── baseof.html
│ │ ├── list.html
│ │ └── single.html
│ └── index.html
├── static/
└── theme.toml
Activeer het in hugo.yaml:
theme: portfolio
Start de dev server — je ziet een lege pagina. Dat klopt: er zit nog geen HTML in.
Van HTML naar layouts
Mijn startpunt was een bestaand HTML/CSS/JS template: één index.html, een stylesheet en wat JavaScript. Het ombouwen doe je in drie stappen:
- Splits de gezamenlijke HTML op in
baseof.htmlen partials - Vervang statische inhoud door Hugo-template-variabelen
- Zet de assets op de juiste plek
baseof.html
baseof.html is het geraamte van elke pagina — alles wat altijd terugkomt: <html>, <head>, navigatie, footer. Het centrale element is het block-slot:
<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">
<head>{{ partial "head.html" . }}</head>
<body>
{{ partial "header.html" . }}
<main>{{ block "main" . }}{{ end }}</main>
{{ partial "footer.html" . }}
</body>
</html>
Andere templates vullen dat slot met {{ define "main" }}...{{ end }}. Zo erft elke pagina het geraamte zonder de HTML te herhalen.
index.html en partials
De homepage vult alleen het main-blok in:
{{ define "main" }}
<section id="hero">
<h1>{{ .Params.greeting | default .Site.Title }}</h1>
</section>
<section id="about">{{ .Content }}</section>
{{ end }}
Alles wat op meerdere pagina’s terugkomt — de <head> met CSS-links, de navigatie, de footer — splits je op in partials. Inladen doe je met:
{{ partial "header.html" . }}
De punt (.) is de context die je meegeeft. Zonder punt heeft de partial geen toegang tot paginadata zoals .Site.Params of .Translations.
Hugo Pipes: assets verwerken
CSS en JS die je in static/ plaatst, worden onbewerkt geserveerd. Voor productiebuilds wil je echter minificatie en fingerprinting (unieke hash in de bestandsnaam om caching te doorbreken). Dat doe je met Hugo Pipes.
Verplaats je CSS van static/css/ naar assets/css/. Dan in je head.html partial:
{{ $css := resources.Get "css/main.css" }}
{{ if hugo.IsProduction }}
{{ $css = $css | minify | fingerprint }}
{{ end }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}">
In ontwikkeling laadt Hugo de originele, leesbare bestanden. In productie (hugo zonder flags) wordt de CSS automatisch geminificeerd en krijgt het bestand een unieke hash in de naam, zodat browsers altijd de nieuwste versie ophalen.
Hetzelfde patroon werkt voor JavaScript:
{{ $js := resources.Get "js/main.js" }}
{{ if hugo.IsProduction }}
{{ $js = $js | minify | fingerprint }}
{{ end }}
<script src="{{ $js.RelPermalink }}"></script>
Let op: gebruik altijd .RelPermalink — nooit een hardcoded pad. Het gefingerprintde bestand krijgt immers een naam als main.min.17dddb29e510cff4144ac1eb3708c4d0.css.
Content koppelen
Hugo kent twee soorten content-bestanden:
_index.md(mét underscore) — een sectie-pagina. Kan child-pagina’s bevatten en dient als de root van een sectie.index.md(zonder underscore) — een pagina-bundle. Een op zichzelf staande pagina, zoals een blogpost.
De homepage gebruikt content/_index.md omdat de siteroot een sectie is die later child-pagina’s kan hebben.
De inhoud van de homepage komt uit dat bestand:
---
greeting: "Hallo, ik ben Sander"
---
Tekst die in de about-sectie verschijnt.
Front matter parameters zijn beschikbaar via {{ .Params.greeting }}, de Markdown-inhoud via {{ .Content }}.
Naast page-specifieke parameters zijn er ook site-brede parameters. Die definieer je in hugo.yaml onder params::
params:
nameOfPerson: "Sander Dam"
profession: "IT Consultant"
In templates zijn ze beschikbaar via {{ .Site.Params.nameOfPerson }} — handig voor gegevens die op meerdere pagina’s terugkomen, zoals je naam of sociale links.
Volgende stap
In het volgende deel laat ik zien hoe ik de site meertalig heb gemaakt: Nederlandse en Engelse content naast elkaar, een taalschakelaar in de navigatie, en vertaalstrings via de i18n/ map.
