9.6 KiB
TankStopp Templ Optimization
Overview
This document describes the optimization of TankStopp's template system using a-h/templ - a compile-time template system for Go that generates type-safe HTML templates.
Migration Summary
The application has been migrated from traditional HTML templates to a-h/templ templates, providing:
- Type Safety: Templates are compiled to Go code with full type checking
- Performance: Templates are compiled at build time, eliminating runtime parsing
- Component Reusability: Modular components that can be composed together
- Developer Experience: IDE support, auto-completion, and compile-time error checking
Project Structure
The new template organization follows a clean architecture:
tankstopp/internal/views/
├── components/
│ ├── layout.templ # Base layout, navbar, footer, cards, etc.
│ ├── forms.templ # Form components, inputs, buttons
│ └── icons.templ # Icon components with SVG definitions
└── pages/
├── auth.templ # Authentication pages (login, register)
├── dashboard.templ # Dashboard page with statistics
├── fuelstops.templ # Add/edit fuel stop pages
├── vehicles.templ # Vehicle management pages
└── settings.templ # Settings page
Component Architecture
Layout Components (components/layout.templ)
Base Layout
templ BaseLayout(title string, user *models.User, username string) {
// Full HTML document structure with navbar, footer, and content area
}
Navigation Components
Navbar()- Main navigation barNavItem()- Individual navigation itemsUserDropdown()- User account dropdownFooter()- Application footer
UI Components
Card()- Reusable card componentAlert()- Alert messages (success, error, warning, info)EmptyState()- Empty state placeholderPageHeader()- Page header with title and subtitleBadge()- Status badgesProgressBar()- Progress indicatorsModal()- Modal dialogsTabs()- Tab navigationPagination()- Pagination controls
Form Components (components/forms.templ)
Input Components
Input()- Basic text inputsNumberInput()- Number inputs with validationDateInput()- Date picker inputsTextArea()- Multi-line text areasSelect()- Dropdown selectsPasswordInput()- Password inputs with visibility toggle
Specialized Selects
CurrencySelect()- Currency dropdownVehicleSelect()- Vehicle dropdownFuelTypeSelect()- Fuel type dropdown
Form Layout
Form()- Form wrapperFormGroup()- Input group with label and hintsFormRow()- Form row wrapperFormCol()- Form column wrapperFormButtons()- Form action buttonsInputGroup()- Input with prefix/suffix
Icon Components (components/icons.templ)
Comprehensive icon system with 40+ icons:
Icon(name, size)- Basic icon componentIconWithClass(name, size, class)- Icon with custom classes
Available icons include: fuel, plus, home, car, settings, location, edit, trash, save, user, lock, etc.
Page Templates
Authentication Pages (pages/auth.templ)
LoginPage()- User login formRegisterPage()- User registration formAuthLayout()- Shared layout for auth pages
Dashboard (pages/dashboard.templ)
DashboardPage()- Main dashboard with statistics and fuel stops tableFuelStopsTable()- Reusable fuel stops table componentDashboardScript()- JavaScript for dashboard functionality
Fuel Stops (pages/fuelstops.templ)
AddFuelStopPage()- Add new fuel stop formEditFuelStopPage()- Edit existing fuel stop formAddFuelStopScript()- JavaScript for form functionality including:- Auto-calculation of total costs
- Current date/time defaults
- Nearby gas station finder using Overpass API
- Form validation
Vehicles (pages/vehicles.templ)
VehiclesPage()- Vehicle management dashboardVehicleCard()- Individual vehicle card componentAddVehiclePage()- Add new vehicle formEditVehiclePage()- Edit vehicle formVehicleBrandSelect()- Vehicle brand dropdown- Helper functions for vehicle statistics
Settings (pages/settings.templ)
SettingsPage()- Comprehensive settings page with:- Profile settings
- Application preferences
- Security settings
- Data management (import/export)
- Account management
SettingsScript()- JavaScript for settings functionality
JavaScript Integration
The templ templates include embedded JavaScript using the script template type:
script DashboardScript() {
function applyFilters() {
// JavaScript functionality
}
}
This approach provides:
- Type-safe JavaScript embedding
- Scoped functionality per page
- Compile-time validation of JavaScript references
Usage Examples
Basic Page Structure
templ MyPage(user *models.User, data MyData) {
@components.BaseLayout("My Page", user, user.Username) {
@components.PageHeader("Subtitle", "My Page Title")
<div class="page-body">
<div class="container-xl">
@components.Card("Card Title", "icon-name") {
// Card content
}
</div>
</div>
}
}
Form with Validation
templ MyForm(data FormData) {
@components.Card("Form Title", "form-icon") {
@components.Form("post", "/submit") {
@components.FormGroup("Field Label", "Help text") {
@components.Input("field_name", "text", "Placeholder", data.Value, true)
}
@components.FormButtons("/cancel", "Save", "save")
}
}
}
Data Table
templ DataTable(items []Item) {
@components.TableResponsive() {
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
for _, item := range items {
<tr>
<td>{ item.Field1 }</td>
<td>{ item.Field2 }</td>
<td>
@components.ButtonGroup() {
@components.EditButton("/edit/" + item.ID)
@components.DeleteButton("/delete/" + item.ID, item.Name)
}
</td>
</tr>
}
</tbody>
}
}
Build Integration
To generate the Go code from templ files:
# Install templ CLI
go install github.com/a-h/templ/cmd/templ@latest
# Generate templates
templ generate
# Or use the shorthand
templ fmt . # Format templates
templ generate . # Generate Go code
Handler Integration
In your HTTP handlers, use the generated template functions:
func DashboardHandler(w http.ResponseWriter, r *http.Request) {
// Get data...
// Render template
component := pages.DashboardPage(user, username, stops, vehicles, totalStops, totalCost, avgConsumption, lastFillUp)
component.Render(r.Context(), w)
}
Benefits
Performance
- Templates are compiled to Go code at build time
- No runtime template parsing
- Minimal memory allocation
- Type-safe rendering
Developer Experience
- Full IDE support with auto-completion
- Compile-time error checking
- Refactoring support
- Hot reload during development
Maintainability
- Component-based architecture
- Clear separation of concerns
- Reusable UI components
- Consistent styling and behavior
Security
- Automatic HTML escaping
- XSS protection by default
- Type-safe data binding
- Compile-time validation
Migration from HTML Templates
Before (HTML Templates)
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}} - TankStopp</title>
<!-- CSS links -->
</head>
<body>
<!-- Navbar HTML -->
<div class="page-body">
{{range .Items}}
<div class="card">
<div class="card-body">
<h4>{{.Name}}</h4>
<p>{{.Description}}</p>
</div>
</div>
{{end}}
</div>
<!-- Footer HTML -->
</body>
</html>
After (Templ Templates)
templ MyPage(title string, items []Item) {
@components.BaseLayout(title, user, username) {
<div class="page-body">
<div class="container-xl">
for _, item := range items {
@components.Card(item.Name, "icon") {
<p>{ item.Description }</p>
}
}
</div>
</div>
}
}
Best Practices
- Component Composition: Build complex UIs by composing smaller components
- Type Safety: Leverage Go's type system for template data
- Reusability: Create reusable components for common UI patterns
- Performance: Use templ's compile-time optimization
- Maintainability: Keep templates focused and well-organized
- Security: Rely on templ's automatic escaping and validation
Future Enhancements
- Internationalization: Add multi-language support
- Theming: Dynamic theme switching
- Progressive Enhancement: Enhanced JavaScript functionality
- Accessibility: ARIA labels and keyboard navigation
- Performance Monitoring: Template rendering metrics
Conclusion
The migration to a-h/templ provides a modern, type-safe, and performant template system that improves developer experience while maintaining excellent runtime performance. The component-based architecture makes the application more maintainable and provides a solid foundation for future enhancements.