Understanding how to organize templates and the package-level requirements for Muxt code generation.
Muxt requires a package-level variable of type *html/template.Template to discover and analyze your templates.
This variable can be initialized in two ways:
- Using
template.ParseFSwith anembed.FSfor file-based templates - Using
template.Parsefor inline string templates
Muxt uses Go's static analysis to find your templates at generation time. It searches for:
- A package-level variable declaration
- Of type
*html/template.Template - Initialized with
template.ParseFS,template.Parse, or wrapped withtemplate.Must(...)
This works:
//go:embed *.gohtml
var templatesDir embed.FS
var templates = template.Must(template.ParseFS(templatesDir, "*.gohtml"))This doesn't work (function-local):
func loadTemplates() *template.Template {
// Muxt can't find this
return template.Must(template.ParseFS(templatesDir, "*.gohtml"))
}The embed package has strict rules about what files it can include. These limitations affect how you organize your templates.
The //go:embed directive can only include:
- Files in the same directory as the
.gofile - Files in subdirectories (children)
It cannot include:
- Parent directories
- Sibling directories of parent directories
Valid structure:
internal/hypertext/
├── templates.go (has //go:embed)
├── index.gohtml (✓ sibling)
├── pages/
│ └── dashboard.gohtml (✓ child)
└── components/
└── nav.gohtml (✓ child)
Invalid structure:
internal/
├── hypertext/
│ └── templates.go (has //go:embed)
└── templates/ (✗ cannot embed ../templates)
└── index.gohtml
To include templates from multiple subdirectories, use multiple patterns or a wildcard:
//go:embed pages/*.gohtml components/*.gohtml partials/*.gohtml
var templatesDir embed.FS
var templates = template.Must(template.ParseFS(templatesDir, "*/*.gohtml"))Or simpler:
//go:embed */*.gohtml *.gohtml
var templatesDir embed.FS
var templates = template.Must(template.ParseFS(templatesDir, "**/*.gohtml", "*.gohtml"))//go:generate muxt generate --use-receiver-type=Client
var templates = template.Must(template.New("GET / List()").Parse(`
<ul>
{{range .Result}}
<li>{{.Name}}</li>
{{end}}
</ul>
{{- define "POST /items CreateItem(name)" -}}
<div>Item {{.Result.Name}} created</div>
{{- end -}}
`))Use when:
- Small projects or prototypes
- All templates fit comfortably in one string
- You want templates and code in the same file for quick iteration
Note: The first template name must be provided to template.New(). Additional templates are defined using {{define "name"}}...{{end}} within the string.
(See Muxt CLI Test/import_v2_module)
//go:embed *.gohtml
var templatesDir embed.FS
//go:generate muxt generate
var templates = template.Must(template.ParseFS(templatesDir, "*.gohtml"))Use when: All templates are in one directory and you want them in separate files
//go:embed pages/*.gohtml components/*.gohtml layouts/*.gohtml
var templatesDir embed.FS
//go:generate muxt generate --use-receiver-type=App
var templates = template.Must(template.ParseFS(templatesDir,
"pages/*.gohtml",
"components/*.gohtml",
"layouts/*.gohtml",
))Use when: Templates are organized into logical subdirectories
//go:embed **/*.gohtml
var templatesDir embed.FS
//go:generate muxt generate --use-receiver-type=App
var templates = template.Must(template.ParseFS(templatesDir, "**/*.gohtml"))Use when: Deep directory structure with many nested template directories
//go:embed **/*.gohtml
var templatesDir embed.FS
//go:generate muxt generate --use-receiver-type=App
var templates = template.Must(
template.New("").
Funcs(customFuncs).
ParseFS(templatesDir, "**/*.gohtml"),
)
var customFuncs = template.FuncMap{
"upper": strings.ToUpper,
"formatDate": formatDate,
}Use when: Templates need custom functions or configuration
Cause: Muxt can't find the package-level templates variable.
Fix:
- Ensure the variable is package-level (not in a function)
- Verify it's type
*template.Template - Check that it uses
template.ParseFSortemplate.Must(template.ParseFS(...))
Cause: Trying to embed files outside the package directory or in parent directories.
Fix:
- Move
templates.goto a directory that's a parent or sibling of your template files - Restructure so all templates are in the same directory or subdirectories
Cause: The glob pattern in ParseFS doesn't match your file structure.
Fix:
- Use
**/*.gohtmlfor recursive matching - List patterns explicitly if you want specific subdirectories
- Ensure the pattern matches the actual file locations relative to the embed.FS root
- Templates Variable Reference - Detailed specification
- Advanced Patterns - Production patterns for template organization