İçindekiler
GoUI, Go’nun native html/template katmanı üzerine Blade benzeri bir template
motoru sunar. .goui.html dosyalarına tanıdık direktifler yazarsınız (@if,
@extends, @component, …); uygulama açılışında bunlar bir kez native Go
template’e çevrilir ve bellekte tutulur. Runtime’da string eval yoktur;
Go ifade dili yeniden yazılmaz — {{ .Field }} pipeline’ları olduğu gibi
kopyalanır, böylece context-aware auto-escaping korunur.
Ayrıca: RenderTemplate migrasyonu,
örnek examples/counter-view.
1. Felsefe
Motor bir yapısal önişlemcidir:
| GoUI’nin işi | html/template’e bırakılan |
|---|---|
@if / @foreach / @extends / @include / @component |
{{ .Field }}, pipeline, eq, fonksiyonlar |
| Dizin → dot-path adları | Auto-escaping |
| Derleme zamanı bağımlılık grafiği | Çalıştırma |
2. Kurulum
- Uzantı:
.goui.html - Dot-path:
views/pages/home.goui.html→"pages.home"(Root’a göre)
import gouitemplate "github.com/zatrano/goui/template"
reg, err := gouitemplate.NewRegistry(gouitemplate.Config{
Root: "./views",
StrictProps: true, // prod’da önerilir
})
if err != nil {
log.Fatal(err)
}
defer reg.Close()
html, err := reg.Render("pages.home", data)
3. Direktif referansı
Koşullar
@if(.User.IsAdmin)
<span>Admin</span>
@elseif(.User.Moderator)
<span>Mod</span>
@else
<span>User</span>
@endif
@unless(.Hidden)
görünür
@endunless
Döngüler
Her zaman $ ile isimlendirin (. yeniden bağlamaya güvenmeyin):
@foreach(.Items as $item)
<li>{{ $item.Name }}</li>
@empty
<li>Yok</li>
@endforeach
@foreach(.Items as $key, $item)
<li>{{ $key }}: {{ $item }}</li>
@endforeach
Switch
@switch(.Status)
@case("ok")
OK
@break
@default
Diğer
@endswitch
Çıktı
{{ .Name }} <!-- escape -->
{!! .TrustedHTML !!} <!-- ham; Güvenlik bölümüne bakın -->
{{-- yorum --}}
@@literal <!-- tek @ yazar -->
Yardımcılar (BaseFuncMap)
{{ default "Guest" .User.Name }}
{{ dict "Type" "submit" "Label" "Save" }}
{{ list 1 2 3 }}
4. Layout (@extends / @section / @yield)
layouts/app.goui.html:
<html>
<head><title>@yield("title", "App")</title></head>
<body>
@yield("content")
</body>
</html>
pages/home.goui.html:
@extends("layouts.app")
@section("title", "Home")
@section("content")
<h1>Hoş geldiniz</h1>
@endsection
@extends varken kök seviyede yalnızca @section (ve boşluk) serbesttir.
5. Include
@include("partials.nav")
@include("partials.user", .User)
@includeIf("partials.optional") <!-- yoksa derleme zamanında atlanır -->
Eksik @include hedefi NewRegistry’yi düşürür. @includeIf düşürmez.
6. Component ve slot
components/card.goui.html:
@props(Title string)
<div class="card">
@if(.Slots.header)
<header>{{ .Slots.header }}</header>
@endif
<div>{{ .DefaultSlot }}</div>
</div>
Çağıran:
@component("components.card", dict "Title" "Hi")
@slot("header")
{{ .PageTitle }}
@endslot
Varsayılan gövde
@endcomponent
Component içinde . bir Dot’tur: .Props.*, .Slots.name, .DefaultSlot.
Slot gövdeleri çağıranın veri bağlamında render edilir.
İç içe component desteklenir.
7. @props ve StrictProps
@props(Name string, Count int = 0)
StrictProps: true iken NewRegistry, dosyadaki her .Props.X kullanımının
beyan edildiğini kontrol eder (yazım hataları “did you mean …?” ile açılışta
yakalanır). Kullanılmayan beyanlar reg.Warnings() ile yumuşak uyarıdır.
StrictProps false (varsayılan) ise bu kontroller çalışmaz.
8. Hot reload (geliştirme)
hub := ws.NewHub()
reg, err := gouitemplate.NewRegistry(gouitemplate.Config{
Root: "./views",
WatchForChanges: true, // prod’da false
OnReload: func() {
hub.Broadcast(ws.PushMessage{
Kind: "reload",
Text: "templates updated",
})
},
OnReloadError: func(err error) {
log.Printf("template reload: %v", err)
},
})
defer reg.Close()
template paketi ws import etmez; callback’i siz bağlarsınız.
Başarısız reload son iyi derlemeyi korur.
9. ViewComponent entegrasyonu
type Counter struct {
core.BaseComponent
Count int
}
func (c *Counter) View() string { return "counter" }
func (c *Counter) Render() (string, error) {
return "", gouitemplate.ErrViewRenderDirect
}
tmplReg, _ := gouitemplate.NewRegistry(gouitemplate.Config{Root: "./views"})
coreReg.Register("counter", gouitemplate.Wrap(tmplReg, func() core.Component {
return &Counter{}
}))
Örnek: examples/counter-view.
10. Güvenlik
- Tercihen
{{ }}(escape’li). {!! !!}/rawauto-escape’i kapatır — yalnızca güvenilir HTML.- Kullanıcı girdisini sanitize etmeden raw’dan geçirmeyin.
11. Blade karşılaştırması
| Blade | GoUI |
|---|---|
@if / @foreach / @extends |
Aynı fikir → native html/template |
@component / @slot |
Desteklenir (iki aşamalı render) |
@includeIf |
Derleme zamanı |
@props |
Opt-in isim kontrolü (StrictProps) |
@php / keyfi PHP |
Yok (bilinçli tasarım) — template’de keyfi kod yok |
| İstek başına mtime cache | Process ömrü boyunca bellek içi derleme |
@php tarzı kaçışların olmaması kasıtlıdır: template veri + yapı, mantık Go’da kalır.
Performans
Tipik bir dizüstünde mertebe (go test ./template/ -bench=.):
| İşlem | Kabaca maliyet |
|---|---|
Render düz sayfa |
düşük µs / op |
Render + extends |
düşük–orta µs / op |
Render ~20 component |
onlarca µs / op |
NewRegistry ~100 dosya |
onlarca–yüzlerce ms |
Açılışta bir kez derleyin (veya hot reload); Render disk I/O yapmaz.