Generates Go html/template files (.tmpl) and type definitions (_types.go) from the compiler's IR.
npm install @barefootjs/go-template#Basic Usage
import { compile } from '@barefootjs/jsx'
import { GoTemplateAdapter } from '@barefootjs/go-template'
const adapter = new GoTemplateAdapter()
const result = compile(source, { adapter })
// result.template → .tmpl file content
// result.types → _types.go file content
// result.clientJs → .client.js file content#Options
const adapter = new GoTemplateAdapter({
packageName: 'views',
})| Option | Type | Default | Description |
|---|---|---|---|
packageName |
string |
'components' |
Go package name for generated type files |
#Output Format
#Server Component
Source:
export function Greeting(props: { name: string }) {
return <p>Hello, {props.name}!</p>
}Output (.tmpl):
{{define "Greeting"}}
<p bf-s="{{bfScopeAttr .}}" {{bfPropsAttr .}} bf="s1">
Hello, {{bfTextStart "s0"}}{{.Name}}{{bfTextEnd}}!
</p>
{{end}}bfScopeAttr— generates thebf-sscope IDbfPropsAttr— serializes props for client hydrationbfTextStart/bfTextEnd— text node markers (rendered as<!--bf:s0-->...<!--/-->)
#Client Component
Source:
"use client"
import { createSignal } from '@barefootjs/client'
export function Counter(props: { initial?: number }) {
const [count, setCount] = createSignal(props.initial ?? 0)
return (
<div>
<span>Count: {count()}</span>
<button onClick={() => setCount(n => n + 1)}>+1</button>
</div>
)
}Output (.tmpl):
{{define "Counter"}}
{{if .Scripts}}{{.Scripts.Register "/static/client/barefoot.js"}}{{.Scripts.Register "/static/client/Counter.client.js"}}{{end}}
<div bf-s="{{bfScopeAttr .}}" {{bfPropsAttr .}}>
<span bf="s1">Count: {{bfTextStart "s0"}}{{.Count}}{{bfTextEnd}}</span>
<button bf="s2">+1</button>
</div>
{{end}}#Expression Translation
#Property Access
props.name → .Name
props.user.email → .User.EmailField names are automatically capitalized to follow Go conventions.
#Comparisons
| JavaScript | Go Template |
|---|---|
a === b |
eq .A .B |
a !== b |
ne .A .B |
a > b |
gt .A .B |
a < b |
lt .A .B |
a >= b |
ge .A .B |
a <= b |
le .A .B |
#Arithmetic
| JavaScript | Go Template |
|---|---|
a + b |
bf_add .A .B |
a - b |
bf_sub .A .B |
a * b |
bf_mul .A .B |
a / b |
bf_div .A .B |
#Logical Operators
| JavaScript | Go Template |
|---|---|
a && b |
and .A .B |
a || b |
or .A .B |
!a |
not .A |
#Array Methods
#`.map()`
{items().map(item => <li>{item}</li>)}{{range $_, $item := .Items}}
<li>{{bfTextStart "s0"}}{{.Item}}{{bfTextEnd}}</li>
{{end}}#`.filter().map()`
{items().filter(item => item.active).map(item => <li>{item.name}</li>)}{{range $_, $item := .Items}}{{if .Active}}
<li>{{bfTextStart "s0"}}{{.Item.Name}}{{bfTextEnd}}</li>
{{end}}{{end}}For complex filter predicates, the adapter generates template block functions.
#`.sort().map()` / `.toSorted().map()`
{items.toSorted((a, b) => a.priority - b.priority).map(t => <li>{t.name}</li>)}{{range bf_sort .Items "Priority" "asc"}}
<li>{{bfTextStart "s0"}}{{.Name}}{{bfTextEnd}}</li>
{{end}}#Other Array Methods
| JavaScript | Go Template |
|---|---|
arr.find(fn) |
bf_find |
arr.findIndex(fn) |
bf_find_index |
arr.every(fn) |
bf_every |
arr.some(fn) |
bf_some |
arr.length |
len .Arr |
#Type Generation
For each component, the adapter generates:
- Input struct — external API
- Props struct — internal representation (includes hydration fields)
- Constructor —
New{Component}Props()with defaults
#Type Mapping
| TypeScript | Go |
|---|---|
string |
string |
number |
int (or float64 for decimals) |
boolean |
bool |
T[] |
[]T |
T | undefined |
Pointer type *T or zero value |
| Object type | Named struct |
#Nested Components
export function TodoList({ items }: { items: TodoItem[] }) {
return (
<ul>
{items.map(item => <TodoItem key={item.id} {...item} />)}
</ul>
)
}#Conditional Rendering
Ternaries become {{if}}...{{else}}...{{end}}:
Source:
{loggedIn() ? <span>Welcome back!</span> : <span>Please log in</span>}Output:
{{if .LoggedIn}}<span bf-c="s0">Welcome back!</span>{{else}}<span bf-c="s0">Please log in</span>{{end}}Element branches use bf-c for conditional markers. Text-only ternaries use bfComment markers instead.
#Script Registration
Client components register their scripts via the .Scripts interface:
{{if .Scripts}}{{.Scripts.Register "/static/client/barefoot.js"}}{{.Scripts.Register "/static/client/Counter.client.js"}}{{end}}The ScriptCollector tracks needed scripts and renders <script> tags at page end. Each script loads at most once.
#Go Helper Functions
These helper functions must be in the Go template FuncMap:
| Function | Purpose |
|---|---|
bf_add, bf_sub, bf_mul, bf_div |
Arithmetic operations |
bf_neg |
Unary negation |
bf_filter |
Filter a slice by field/value |
bf_sort |
Sort a slice by field/direction |
bf_find, bf_find_index |
Find element/index in a slice |
bf_every, bf_some |
Test if all/any elements match |
bf_json |
JSON-encode a value for props serialization |
bf_concat |
String concatenation |
Provided by the BarefootJS Go runtime package.