Go&#sのテンプレートエンジン「templ」が便利(TinyGoでも動作します)

Barbara Streisand
リリース: 2024-10-30 20:31:30
オリジナル
1062 人が閲覧しました

あらすじ

プレーン HTML を返すアプリケーションを Go で実行したかったのですが、
Wasm に変換してデプロイできる Cloudflare Workers を使用することにしました。

Go アプリケーションを Cloudflare Workers にデプロイするには、syumai/workers のテンプレートをお勧めします。

syumai/workers: Cloudflare Workers で HTTP サーバーを実行するための Go パッケージ。

Go テキスト/テン​​プレート

まず、テキスト/テン​​プレートを使用して簡単に構築してみましょう。

❯ ls -lh . /build
   total 15656
   -rwxr-xr-x 1 ergofriend staff 7.6M 8 8 20:12 app.wasm
   -rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:12 shim.mjs
   -rw-r--r-- 1 ergofriend staff 16K 8 8 20:12 wasm_exec.js
   -rw-r--r-- 1 ergofriend staff 160B 8 8 20:12 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ほぼ 8 MB でした。

https://developers.cloudflare.com/workers/platform/limits/#account-plan-limits

Cloudflare Workers には、プランに応じてワーカーのサイズ制限があります。

無料スロットは 1MB、有料スロット ($5~) は 10MB です。

圧縮後のサイズに基づく最終制限があっても、8MB から始まる無料割り当てに収まるのは困難です。

TinyGo テキスト/テン​​プレート

そこで、WebAssembly (Wasm) 用であるはずの TinyGo に切り替えることにしました。

ビルド後のサイズは約0.75MBで、空き枠に収まりそうです。

❯ ls -lh . /build
total 1160
-rwxr-xr-x 1 ergofriend staff 556K 8 8 20:23 app.wasm
-rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:23 shim.mjs
-rw-r--r-- 1 ergofriend staff 15K 8 8 20:23 wasm_exec.js
-rw-r--r-- 1 ergofriend staff 160B 8 8 20:23 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

おっと!

しかし、ここで悲劇が起こります。

ビルドされたアプリケーションにアクセスしようとすると、エラーが発生します。

[wrangler:inf] GET / 200 OK (35ms)
✘ [ERROR] Uncaught (in response) RuntimeError: unreachable

      at main.runtime._panic (wasm://wasm/main-0022bc46:wasm-function[35]:0x2b4a)
      at main.(*text/template.state).evalField
  (wasm://wasm/main-0022bc46:wasm-function[540]:0x6c5f4)
      at main.(*text/template.state).evalFieldChain
  (wasm://wasm/main-0022bc46:wasm-function[531]:0x697fe)
      at main.(*text/template.state).evalFieldNode
  (wasm://wasm/main-0022bc46:wasm-function[530]:0x6959a)
      at main.(*text/template.state).evalPipeline
  (wasm://wasm/main-0022bc46:wasm-function[535]:0x6a1d2)
      at main.(*text/template.state).walk (wasm://wasm/main-0022bc46:wasm-function[569]:0x72cdd)
      at main.(*text/template.state).walk (wasm://wasm/main-0022bc46:wasm-function[569]:0x730b0)
      at main.main (wasm://wasm/main-0022bc46:wasm-function[261]:0x2ac52)
      at main.(net/http.HandlerFunc).ServeHTTP
  (wasm://wasm/main-0022bc46:wasm-function[463]:0x5973a)
      at
  main.interface:{ServeHTTP:func:{named:net/http.ResponseWriter,pointer:named:net/http.Request}{}}.ServeHTTP$invoke
  (wasm://wasm/main-0022bc46:wasm-function[459]:0x56f72)

panic: unimplemented: (reflect.Value).MethodByName()
ログイン後にコピー
ログイン後にコピー

template.ExecuteTemplate() でテンプレート変数が渡されたときに呼び出されるメソッド MethodByName はまだ実装されていないようです。

TinyGo はオリジナルのサブセットであるため、サポートされていない機能が多数あります。
テキスト/テン​​プレートがサポートされていないメソッドを呼び出していることがわかりました。

https://github.com/tinygo-org/tinygo/blob/1154212c15e6e97048e122068730dab5a1a9427f/src/reflect/type.go#L1086-L1088

ここで、冷静になって TinyGo について感謝の意を表したいと思いますが、今回は簡単な代替手段を探すつもりです。

テンプル

そこで、テキスト/テン​​プレートを置き換える別のテンプレート エンジンを探していたところ、templを見つけました。

Go ああ / 寺院

Go で HTML ユーザー インターフェイスを記述するための言語。

Go

優れた開発者ツールを備えた Go 用の HTML テンプレート言語。

Go

ドキュメント

https://templ.guide でユーザードキュメントを参照してください

Go Go Go Go

タスク

ビルド

ローカル バージョンをビルドします。

❯ ls -lh . /build
   total 15656
   -rwxr-xr-x 1 ergofriend staff 7.6M 8 8 20:12 app.wasm
   -rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:12 shim.mjs
   -rw-r--r-- 1 ergofriend staff 16K 8 8 20:12 wasm_exec.js
   -rw-r--r-- 1 ergofriend staff 160B 8 8 20:12 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します

nix-update-gomod2nix

❯ ls -lh . /build
   total 15656
   -rwxr-xr-x 1 ergofriend staff 7.6M 8 8 20:12 app.wasm
   -rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:12 shim.mjs
   -rw-r--r-- 1 ergofriend staff 16K 8 8 20:12 wasm_exec.js
   -rw-r--r-- 1 ergofriend staff 160B 8 8 20:12 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します

インストールスナップショット

現在のバージョンをビルドしてインストールします。

❯ ls -lh . /build
total 1160
-rwxr-xr-x 1 ergofriend staff 556K 8 8 20:23 app.wasm
-rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:23 shim.mjs
-rw-r--r-- 1 ergofriend staff 15K 8 8 20:23 wasm_exec.js
-rw-r--r-- 1 ergofriend staff 160B 8 8 20:23 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します

ビルドスナップショット

goreleaser を使用して、goreleaser を使用してコマンド ライン バイナリをビルドします。

❯ ls -lh . /build
   total 15656
   -rwxr-xr-x 1 ergofriend staff 7.6M 8 8 20:12 app.wasm
   -rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:12 shim.mjs
   -rw-r--r-- 1 ergofriend staff 16K 8 8 20:12 wasm_exec.js
   -rw-r--r-- 1 ergofriend staff 160B 8 8 20:12 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します

生成

ローカル バージョンを使用して templ 生成を実行します。

❯ ls -lh . /build
total 1160
-rwxr-xr-x 1 ergofriend staff 556K 8 8 20:23 app.wasm
-rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:23 shim.mjs
-rw-r--r-- 1 ergofriend staff 15K 8 8 20:23 wasm_exec.js
-rw-r--r-- 1 ergofriend staff 160B 8 8 20:23 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します

テスト

Go テストを実行します。

❯ ls -lh . /build
   total 15656
   -rwxr-xr-x 1 ergofriend staff 7.6M 8 8 20:12 app.wasm
   -rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:12 shim.mjs
   -rw-r--r-- 1 ergofriend staff 16K 8 8 20:12 wasm_exec.js
   -rw-r--r-- 1 ergofriend staff 160B 8 8 20:12 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します

ショートテスト

Go テストを実行します。

❯ ls -lh . /build
total 1160
-rwxr-xr-x 1 ergofriend staff 556K 8 8 20:23 app.wasm
-rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:23 shim.mjs
-rw-r--r-- 1 ergofriend staff 15K 8 8 20:23 wasm_exec.js
-rw-r--r-- 1 ergofriend staff 160B 8 8 20:23 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
全画面モードに入る 全画面モードを終了します

テストカバー

実行…


GitHub で表示


特徴

TEMPL の概要は次のとおりです。

独自のDSL

独自のプログラムを書くのは難しくありませんが、templ ≈ Go JSX のように書くことができます。

❯ ls -lh . /build
   total 15656
   -rwxr-xr-x 1 ergofriend staff 7.6M 8 8 20:12 app.wasm
   -rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:12 shim.mjs
   -rw-r--r-- 1 ergofriend staff 16K 8 8 20:12 wasm_exec.js
   -rw-r--r-- 1 ergofriend staff 160B 8 8 20:12 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

非常に見慣れた文体のように見えます。

❯ ls -lh . /build
total 1160
-rwxr-xr-x 1 ergofriend staff 556K 8 8 20:23 app.wasm
-rw-r--r-- 1 ergofriend staff 1.2K 8 8 20:23 shim.mjs
-rw-r--r-- 1 ergofriend staff 15K 8 8 20:23 wasm_exec.js
-rw-r--r-- 1 ergofriend staff 160B 8 8 20:23 worker.mjs
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これを使用する場合、コンポーネントごとに templ generated によって DSL から生成された Go 関数を呼び出します。

[wrangler:inf] GET / 200 OK (35ms)
✘ [ERROR] Uncaught (in response) RuntimeError: unreachable

      at main.runtime._panic (wasm://wasm/main-0022bc46:wasm-function[35]:0x2b4a)
      at main.(*text/template.state).evalField
  (wasm://wasm/main-0022bc46:wasm-function[540]:0x6c5f4)
      at main.(*text/template.state).evalFieldChain
  (wasm://wasm/main-0022bc46:wasm-function[531]:0x697fe)
      at main.(*text/template.state).evalFieldNode
  (wasm://wasm/main-0022bc46:wasm-function[530]:0x6959a)
      at main.(*text/template.state).evalPipeline
  (wasm://wasm/main-0022bc46:wasm-function[535]:0x6a1d2)
      at main.(*text/template.state).walk (wasm://wasm/main-0022bc46:wasm-function[569]:0x72cdd)
      at main.(*text/template.state).walk (wasm://wasm/main-0022bc46:wasm-function[569]:0x730b0)
      at main.main (wasm://wasm/main-0022bc46:wasm-function[261]:0x2ac52)
      at main.(net/http.HandlerFunc).ServeHTTP
  (wasm://wasm/main-0022bc46:wasm-function[463]:0x5973a)
      at
  main.interface:{ServeHTTP:func:{named:net/http.ResponseWriter,pointer:named:net/http.Request}{}}.ServeHTTP$invoke
  (wasm://wasm/main-0022bc46:wasm-function[459]:0x56f72)

panic: unimplemented: (reflect.Value).MethodByName()
ログイン後にコピー
ログイン後にコピー
go run ./get-version > .version
cd cmd/templ
go build
ログイン後にコピー

生成されたコンポーネントの関数は、テンプレートで定義された引数の型を継承するため、安全に呼び出すことができます。
一部の ExecuteTemplate とは異なり、これは安全です。

VSCode 拡張機能

https://marketplace.visualstudio.com/items?itemName=a-h.templ

構文ハイライトと LSP 補完は非常に便利です。

TinyGo テンプル

念のため確認してみたところ、TinyGoに実装済みのreflectのTypeOfのみに依存していることが分かりました。

https://github.com/tinygo-org/tinygo/blob/1154212c15e6e97048e122068730dab5a1a9427f/src/reflect/type.go#L494-L500

次に、templ を使用してみましょう。
ビルドには十分な余裕があるようでした。

gomod2nix
ログイン後にコピー

実際のアプリケーションは次のとおりです。

goworkers-demo.ergofriend.workers.dev

アクセスすると、エラーなしで HTML を返すことができます。

<span class="pl-c"># Remove templ from the non-standard ~/bin/templ path</span>
<span class="pl-c"># that this command previously used.</span>
rm -f ~/bin/templ
<span class="pl-c"># Clear LSP logs.</span>
rm -f cmd/templ/lspcmd/*.txt
<span class="pl-c"># Update version.</span>
go run ./get-version > .version
<span class="pl-c"># Install to $GOPATH/bin or $HOME/go/bin</span>
cd cmd/templ && go install
ログイン後にコピー

デプロイされた最終的なサイズも 187.91 KiB であるため、アプリケーションを拡張する余地は十分にあります。

この検証はこのリポジトリに残ります。
エルゴフレンド/ゴーワーカーデモ


この記事は日本語からの翻訳です。
https://ergofriend.hatenablog.com/entry/2024/08/08/230603

以上がGo&#sのテンプレートエンジン「templ」が便利(TinyGoでも動作します)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート