Go&#s template engine 'templ” is convenient (it also works with TinyGo)

Barbara Streisand
Release: 2024-10-30 20:31:30
Original
1062 people have browsed it

Synopsis

I wanted to run an application in Go that returned plain HTML,
I decided to use Cloudflare Workers, which can convert it to Wasm and deploy it.

I recommend syumai/workers's template for deploying Go applications to Cloudflare Workers.

syumai/workers: Go package to run an HTTP server on Cloudflare Workers.

Go text/template

First, let's build using text/template in a straightforward manner.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

It was almost 8 MB.

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

Cloudflare Workers has worker size limits depending on the plan.

The free slot is 1MB, and the paid slot ($5~) is 10MB.

Even with the final limit based on size after compression, it will be tough to fit into the free quota starting at 8MB.

TinyGo text/template

So I decided to switch to TinyGo, which is supposed to be for WebAssembly (Wasm).

After building, the size is about 0.75 MB, which seems to fit into the free frame.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

Oops!

But here is where tragedy strikes.

When I try to access the built application, I get an error.

[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()
Copy after login
Copy after login

The method MethodByName, which is called when a template variable is passed in template.ExecuteTemplate(), is not yet It seems to be unimplemented.

Since TinyGo is a subset of the original, there are many unsupported features,
I found that text/template was calling unsupported methods.

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

Now, I would like to be cool and say p-r for TinyGo, but this time I'm going to look for a quick alternative.

TEMPL

So I was looking for another template engine to replace text/template and came across templ.

Go a-h / templ

A language for writing HTML user interfaces in Go.

Go

An HTML templating language for Go that has great developer tooling.

Go

Documentation

See user documentation at https://templ.guide

Go Go Go Go

Tasks

build

Build a local version.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Enter fullscreen mode Exit fullscreen mode

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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Enter fullscreen mode Exit fullscreen mode

install-snapshot

Build and install current version.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Enter fullscreen mode Exit fullscreen mode

build-snapshot

Use goreleaser to build the command line binary using 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Enter fullscreen mode Exit fullscreen mode

generate

Run templ generate using local version.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Enter fullscreen mode Exit fullscreen mode

test

Run Go tests.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Enter fullscreen mode Exit fullscreen mode

test-short

Run Go tests.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Enter fullscreen mode Exit fullscreen mode

test-cover

Run…


View on GitHub


Features

Here is a summary of TEMPL.

Own DSL

It is not difficult to write a unique program, but it can be written like 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

It looks like a very familiar writing style.

❯ 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
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

When you use it, you call Go functions generated from the DSL by templ generate on a component-by-component basis.

[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()
Copy after login
Copy after login
go run ./get-version > .version
cd cmd/templ
go build
Copy after login

The function of the generated component inherits the argument types defined in the template, so it can be safely called.
Unlike some ExecuteTemplate, this is safe.

VSCode Extensions

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

Syntax Highlight and LSP completion will be very useful.

TinyGo templ

Just to be sure, I checked and found that it only depends on reflect's TypeOf, which is already implemented in TinyGo.

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

Now let's try using templ.
The build seemed to have enough room.

gomod2nix
Copy after login

Here is the actual application.

goworkers-demo.ergofriend.workers.dev

When accessed, the HTML can be returned without error.

<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
Copy after login

The final deployed size is also 187.91 KiB, so there is plenty of room to expand the application.

This verification is left in this repository.
ergofriend/goworkers-demo


This article is a translation from Japanese.
https://ergofriend.hatenablog.com/entry/2024/08/08/230603

The above is the detailed content of Go&#s template engine 'templ” is convenient (it also works with TinyGo). For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template