イケてるGo版JSX,templを知っているか!?(feat. neovimでの設定)
Tutorial
templはGolangで書かれたHTML出力用のDSLです。
あらかじめ次のコマンドでtempl
を導入しておきましょう。
$ go install github.com/a-h/templ/cmd/templ@latest
では構文を確認してみましょう。
package main
import "fmt"
templ diaryCard(emoji string, title string, content string, date string, idx int) {
{{ path := fmt.Sprintf("/view/item?idx=%d", idx) }}
<div
class="bg-white rounded-lg shadow p-4 hover:shadow-md transition"
hx-trigger="click"
hx-get={ path }
hx-target="#detail-panel"
@click="open=true"
>
<div class="flex items-center mb-2">
<span class="text-3xl mr-2">{ emoji }</span>
<h2 class="text-xl font-semibold truncate">{ title }</h2>
</div>
<p class="text-sm text-gray-500 mb-1">{ date }</p>
<p class="text-gray-700 line-clamp-3">
{ content }
</p>
</div>
}
このような感じです。htmxとtailwindcssとalpine.jsを使っているので,ごちゃごちゃしていますが、Golang版JSXという雰囲気ですね。今、これをdiary_card.templ
として保存します。
保存先のフォルダで
$ templ generate
と実行すると、diary_card_templ.go
というファイルが生成されます。
あとは
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/diary", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
diaryCard("📝","日記タイトル","これは日記の本文です。","2025-01-01",0).Render(r.Context(), w)
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
のように書き、サーバーを実行し、http://localhost:8080/diary
にアクセスすると、先ほどのtemplファイルにdiaryCard関数の引数が埋め込まれた状態で返却されます。
Golang標準のhtml/template
と比較すると
- Golangにコンパイルされるのでテンプレートファイルを読み込む処理を書かなくてよい
- 関数に変換されるので型安全で、ビルド前にエラーが把握できる
- ネストなども簡単にできる
- forやif文なども実行できる
という特徴があります。まさにGolang版JSXという感じですね。
また、tinygoでも実行できるらしいのでWASMにコンパイルしてCloudflare Workersにデプロイなんてこともできるらしいです。
というわけでtemplの開発環境を整えてみましょう!
Neovimでのセットアップ
templはLSP含め開発リソースがかなり充実しているので、Neovimでも簡単にセットアップできます。
1. シンタックスハイライト
デフォルトだとtemplがシンタックスハイライトされません。nvim-treesitter/nvim-treesitter
を入れたうえで:TSInstall templ
でセットアップできます。これでtemplファイルを開くとシンタックスハイライトされるようになるはずです。
2. LSPのインストール
mason.nvimを使っている場合簡単に入れられます。:Mason
で起動してtempl
というそのまんまの名前のLSPを入れるだけです。
3. LSPのセットアップ
mason-lspconfig.nvimはバージョン2.0.0以降でsetup_handler
が使えなくなりました。これはNeovim 0.11で本体にLSP関連の機能が追加されたことに起因するそうです。
自分の場合、上記記事を概ね真似て
require('mason').setup() -- mason.nvimの読み込み
-- setup_handlerの代わり.LSPサーバーを設定する
vim.lsp.config('*', {
capabilities = require('cmp_nvim_lsp').default_capabilities(),
})
--[[
**ここで各lspの設定を行う**
]]
-- このsetupにより内部的にvim.lsp.enableが実行されLSPサーバーがロードされる。
require("mason-lspconfig").setup {}
という感じにしています。。
あとは:checkhealth vim.lsp
でtempl
がロード可能になっているのを確認できれば問題ないです。(templファイル開きながらのほうが確認しやすいかもです。)
必要に応じて、html-lsp
などもインストールすると良いと思います。
なお、場合によっては拡張子の設定が必要な場合があるので、例えばhtml-lspの場合は
-- For templ
vim.lsp.config['html'] = {
filetypes = {'html','templ'}
}
のようにtemplファイルでもhtml-lspが起動するようしてやります。tailwindcss
やhtmx
でも同様です。
4. 閉じタグの自動補完(オプショナル)
vscodeには開きタグを入力すると対応する閉じタグを自動で記述する機能があります。
個人的にはこれもneovimで使えると嬉しいのでwindwp/nvim-ts-autotagを入れます。
setup関数を呼ぶだけで動いてくれます。
require('nvim-ts-autotag').setup()
なお、templについてはプラグイン側で対応しているため、treesitterのパーサーが入っていればそれ以外にtemplに特化した設定は必要なさそうです。
5. AIコーディング(オプショナル)
設定とは少し違いますが、昨今流行りのAIコーディングだとモデルによってはtemplを知らなかったり、存在は知っていても正確なコーディングを行ってくれない場合があります。一応、GeminiとGPTは読解ができそうなのですが、In-Context Learningに基づいた、正確なコーディングを行うためのリソースとして、公式がllm.mdを用意してくれています。CopilotなどでこれをURLからの読み込み機能を使って読ませてあげれば、性能が上がるかもしれません。ただし、非常に長いファイルなのである程度コンテキストが長いモデルが必要があるのと、それ相応にAPIクレジットを消費する点には注意した方がいいかもしれません。
Discussion