html/templateの「実行時エラー」問題
Goの標準html/templateは強力ですが、以下の課題があります:
- 実行時エラー: テンプレートの構文エラーは実行時まで検出されない
- 型安全性の欠如: 変数の型ミスマッチが起きやすい
- 補完が効かない: IDEの恩恵を受けにくい
「ページを表示して初めてエラーに気づく」という悪夢は、もう終わりです。
templなら、コンパイル時に全てのエラーを検出します。
最短で課題解決する一冊
この記事の内容と高い親和性が確認できたベストマッチです。早めにチェックしておきましょう。
templとは?型安全なHTMLテンプレート
templは、GoコードとHTMLを融合させる革新的なテンプレートエンジンです。
.templファイルはGoコードにコンパイルされ、完全な型チェックが行われます。
コア機能
- コンパイル時型チェック: 変数の型ミスマッチを即座に検出
- IDEサポート: VSCode拡張で補完・整形が効く
- コンポーネント指向: 再利用可能な部品として定義
- 高速レンダリング: コンパイル済みGoコードとして実行
さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
実践:templ × HTMXでTODOアプリ
HTMXと組み合わせることで、JavaScriptをほぼ書かずにインタラクティブなアプリを作れます。
プロジェクトセットアップ
# templのインストール
go install github.com/a-h/templ/cmd/templ@latest
# プロジェクト作成
mkdir todo-app && cd todo-app
go mod init example.com/todo-app型定義(types.go)
package main
type Todo struct {
ID int
Text string
Completed bool
}templコンポーネント(components.templ)
package main
// ベースレイアウト
templ Layout(title string) {
<!DOCTYPE html>
<html>
<head>
<title>{title}</title>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head>
<body>
{ children... }
</body>
</html>
}
// TODOリストコンポーネント
templ TodoList(todos []Todo) {
<div id="todo-list">
for _, todo := range todos {
@TodoItem(todo)
}
</div>
}
// 個別TODOアイテム
templ TodoItem(todo Todo) {
<div class="todo-item">
<input
type="checkbox"
checked?={todo.Completed}
hx-post={"/toggle/" + strconv.Itoa(todo.ID)}
hx-target="closest .todo-item"
hx-swap="outerHTML"
/>
<span>{todo.Text}</span>
<button
hx-delete={"/todo/" + strconv.Itoa(todo.ID)}
hx-target="closest .todo-item"
hx-swap="outerHTML"
>
削除
</button>
</div>
}
// TODOフォーム
templ TodoForm() {
<form
hx-post="/todo"
hx-target="#todo-list"
hx-swap="beforeend"
>
<input type="text" name="text" placeholder="新しいTODO" />
<button type="submit">追加</button>
</form>
}サーバー実装(main.go)
package main
import (
"net/http"
"strconv"
)
var todos = []Todo{
{ID: 1, Text: "templを学ぶ", Completed: false},
{ID: 2, Text: "HTMXを試す", Completed: true},
}
func main() {
http.HandleFunc("/", indexHandler)
http.HandleFunc("/todo", addTodoHandler)
http.HandleFunc("/toggle/", toggleTodoHandler)
http.HandleFunc("/todo/", deleteTodoHandler)
http.ListenAndServe(":8080", nil)
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
component := Layout("TODO App") {
@TodoForm()
@TodoList(todos)
}
component.Render(r.Context(), w)
}
func addTodoHandler(w http.ResponseWriter, r *http.Request) {
text := r.FormValue("text")
newTodo := Todo{
ID: len(todos) + 1,
Text: text,
}
todos = append(todos, newTodo)
// HTMXにはHTMLフラグメントだけを返す
TodoItem(newTodo).Render(r.Context(), w)
}
func toggleTodoHandler(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(r.URL.Path[len("/toggle/"):])
for i := range todos {
if todos[i].ID == id {
todos[i].Completed = !todos[i].Completed
TodoItem(todos[i]).Render(r.Context(), w)
return
}
}
}ビルドと実行
# templファイルをGoコードに変換
templ generate
# アプリケーション実行
go run .さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
templの強力な型安全性
型ミスマッチの防止
// ❌ コンパイルエラー!(stringをintに渡している)
templ BadExample(id string) {
@TodoItem({ID: id, Text: "test"})
}
// ✅ 正しい型
templ GoodExample(id int) {
@TodoItem({ID: id, Text: "test"})
}Nilチェック
templ UserProfile(user *User) {
if user != nil {
<h1>{user.Name}</h1>
} else {
<p>ユーザーが見つかりません</p>
}
}さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
パフォーマンス
templは事前コンパイルされているため、html/templateの解釈型と比べて:
- 3〜5倍高速なレンダリング
- メモリ効率が良い(テンプレートパースが不要)
- CPUオーバーヘッドが少ない
さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。
まとめ
templとHTMXの組み合わせは、Goでのサーバーサイドレンダリングに革命をもたらします。
- 完全な型安全性
- IDEの強力な支援
- JavaScriptを最小限に
- 高速なレンダリング
「Reactは複雑すぎる、でもサーバーレンダリングだけでは物足りない」 そんな方にこそ、templ × HTMXを試してほしいです。
さらに理解を深める参考書
関連記事と相性の良い実践ガイドです。手元に置いて反復しながら進めてみてください。

![[作って学ぶ]ブラウザのしくみ──HTTP、HTML、CSS、JavaScriptの裏側 (WEB+DB PRESS plusシリーズ)](https://m.media-amazon.com/images/I/41upB6FsPxL._SL500_.jpg)

