tempo

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2025 License: MIT

README ΒΆ

tempo

A lightweight CLI for managing assets and scaffolding components in templ-based projects.

CI Coverage Status go report card version go reference license Built with Devbox

tempo is a lightweight CLI for managing assets and scaffolding components in templ-based projects. Inspired by the Italian word for "time", it streamlines CSS & JS workflows while preserving a smooth developer experience.

tempo

πŸ“– Table of Contents

✨ Features

  • Automated CSS & JS management – Keeps styles and scripts in separate files while seamlessly injecting them into .templ components.
  • Structured asset workflow – Ensures a clean, maintainable approach to managing CSS and JS within templ projects.
  • Fast, lightweight component scaffolding – Quickly generate components and variants with predefined templates and actions.
  • Extensible templating system – Supports custom function providers (local or remote) to enhance tempo's capabilities.

πŸ’‘ Motivation

While building a UI component library in Golang with templ, I deliberately chose to use plain CSS and vanilla JavaScript. This decision introduced two key challenges:

The Problem

  1. Managing CSS & JS assets – While templ excels at Go/HTML templating, it lacks a structured approach for handling standalone styles and scripts. Although you can write CSS and JS directly within .templ files, this comes at the cost of losing native tooling benefits such as syntax highlighting, formatting, and autocompletion. As a result, maintaining styles and scripts efficiently while keeping them separate from .templ files required a better workflow.
  2. Scaffolding new components – Every component followed the same folder structure, but manually copying files and folders was inefficient. I initially used Plop.js, but it required setting up a full Node.js project.

The Solution

tempo solves both problems natively in Go, eliminating the need for Node.js while providing a structured, opinionated workflow for component and asset management.

✨ Preserving the Developer Experience

With tempo, CSS and JS files remain untouched during development, allowing developers to continue using their preferred tools:

  • Linters & formatters (e.g., Prettier, ESLint, Stylelint)
  • IDE features like syntax highlighting, error detection, and inline code suggestions (e.g., in VSCode).
  • Existing workflows remain intactβ€”ensuring a familiar, efficient experience.

When you run tempo, CSS and JS files are injected into .templ components automatically, but the original source files remain unchanged. This approach preserves developer productivity while enabling seamless integration into templ-based projects.

πŸ’» Installation

go install

Requires Go v1.23+

go install github.com/indaco/tempo@latest

Manually

Download the pre-compiled binaries from the releases page and place it in a directory available in your system's PATH.

πŸš€ Usage

To start using tempo, initialize your project and define your components. Below are the key steps:

1. Initialize tempo

tempo init

Generates a tempo.yaml configuration file. Customize it to fit your project. See the Configuration section for details.

2. Define a Component or Variant

tempo component define
tempo variant define

Generates templates for components/variants inside .tempo-files/templates/ along with an action JSON file inside .tempo-files/actions/. See the Templates & Actions section for details.

3. Create a Component

tempo component new --name button

Creates a new component:

  • assets/button/ β†’ Holds CSS and JS files.
  • components/button/ β†’ Contains .templ and .go file

4. Sync Assets with Components

tempo sync

Injects CSS & JS into .templ files using guard markers.

πŸ”Ή Example mapping:

assets/button/css/button.css          β†’ components/button/css/button.templ
assets/button/css/variant/outline.css β†’ components/button/css/variant/outline.templ

πŸ› οΈ CLI Commands & Options

NAME:
   tempo - A lightweight CLI for managing assets and scaffolding components in templ-based projects.

USAGE:
   tempo <subcommand> [options] [arguments]

VERSION:
   v0.1.0

DESCRIPTION:
   tempo simplifies asset management in templ-based projects, providing a seamless workflow for
   handling CSS and JS files. It automatically extracts and injects styles and scripts into .templ
   components while preserving the original source files, ensuring a smooth developer experience.
   Additionally, it offers a lightweight scaffolding system to quickly generate component and variant
   templates with predefined structures.

COMMANDS:
   init       Initialize a Tempo project
   component  Define component templates and generate instances from them
   variant    Define variant templates and generate instances from them
   register   Register is used to extend tempo
   sync       Process & sync asset files into templ components
   help       Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

init

Initialize a tempo project by generating a tempo.yaml configuration file. This file allows you to customize how components and assets are generated and managed.

For a full list of configuration options, See the Configuration section for details.

component

Define reusable component templates and generate instances from them.

Define a Component
tempo component define

Creates a scaffold for defining a UI component, including template files and an action JSON file.

These definitions are later used by tempo component new to generate real components.

Flags (tempo component define)
--force
Force overwriting if already exists (default: false)
--dry-run
Preview actions without making changes (default: false)
--js
Whether or not JS is needed for the component (default: false)
Generate a Component
tempo component new --name button

Uses the templates and actions created with tempo component define to generate a real component inside assets/ and components/.

Example: Running tempo component new --name dropdown will generate:

  • assets/dropdown/ (CSS & JS files)
  • components/dropdown/ (with .templ and .go files)
Flags (tempo component new)
--package (-p) value
The Go package name where components will be generated (default: components)
--assets (-a) value
The directory where asset files (e.g., CSS, JS) will be generated (default: assets)
--name (-n) value
Name of the component
--js
Whether or not JS is needed for the component (default: false)
--force
Force overwriting if the component already exists (default: false)
--dry-run
Preview actions without making changes (default: false)

variant

Define component variant templates and create instances based on them.

Define a Variant
tempo variant define

Creates a scaffold for defining a variant of an existing component (e.g., an outline button variant), including template files and an action JSON file.

These definitions are later used by tempo variant new to generate real component variants.

Flags (tempo variant define)
--force
Force overwriting if the variant definition already exists (default: false)
--dry-run
Preview actions without making changes (default: false)
Generate a Variant
tempo variant new --name outline --component button

Uses the templates and actions created with tempo variant define to generate a real instance of a variant inside the corresponding component folder.

Example: Running tempo variant new --name outline --component button will generate:

  • components/button/variant/outline.templ
  • assets/button/css/variant/outline.css
Flags (tempo variant new)
--package (-p) value
The Go package name where components will be generated (default: components)
--assets (-a) value
The directory where asset files (e.g., CSS, JS) will be generated (default: assets)
--name (-n) value (required)
The name of the variant being generated
--component (-c) value (required)
Name of the component or entity to which this variant belongs
--force
Force overwriting if the variant already exists (default: false)
--dry-run
Preview actions without making changes (default: false)

register

Extend tempo with the register command.

tempo register -h
Register a function provider

Enhance tempo’s templating capabilities by adding custom function providers. You can register a provider from either a local Go module or a remote Git repository.

tempo register functions --name sprig --url https://github.com/indaco/tempo-provider-sprig.git
Flags (tempo register functions)
--name (-n) value
Name for the function provider
--url (-u) value
Repository URL
--path (-p) value
Path to a local go module provider

sync

Automatically sync CSS and JS assets with .templ components.

tempo sync

The sync command scans the input folder for CSS and JS files, then injects their content into the corresponding .templ files in the output folder:

  • Extracts CSS and JS from source files.
  • Injects them into .templ files inside sections marked by guard markers.
  • Keeps components up to date without manual copying.

Whenever you update your CSS or JS files, simply run tempo sync to propagate the changes.

Flags
--input value
The directory containing asset files (e.g., CSS, JS) to be processed (default: assets)
--output value
The directory containing the `.templ` component files where assets will be injected (default: components)
--exclude value
Subfolder (relative to input directory) to exclude from the processing
--workers value
Number of concurrent workers processing asset files (default: numCPUs * 2)
--prod
Enable production mode, minifying the injected content (default: false)
--force
Force processing of all files, ignoring modification timestamps (default: false)
--summary (-s) value
Specify the summary format: text, json, or none (default: "text")
--verbose
Show detailed information in the summary report (default: false)
--report-file (--rf) value
Export the summary to a JSON file

[!TIP] Live Reload: If you're using a live reload tool like air, templier, or watchexec, pass --summary none to reduce unnecessary output.

[!NOTE] Want to use tempo without scaffolding? Check out Using tempo sync as a Standalone Command.

⚑ Using tempo sync as a Standalone Command

The sync command can be used independently of the scaffolding flow (define, new, register). All it requires is:

  • A valid tempo.yaml file.
  • A project folder structure matching the paths defined in tempo.yaml.
  • Guard markers in your .templ files to specify where assets should be injected.

This makes tempo sync a great option for developers who simply want to synchronize CSS and JS assets with their .templ files, without using the full scaffolding features.

πŸ’₯ Use Cases for Standalone sync

  • Already have components but want automated asset injection.
  • Only need asset handling without using the full scaffolding flow.
  • Maintain existing folder structures while benefiting from tempo’s synchronization features.

πŸ› οΈ Example Standalone Workflow

Start by creating a Go module using the go mod init command.

  1. Initialize tempo.yaml:

    tempo init
    
  2. Set up your folders:

    .
    β”œβ”€β”€ assets/
    β”‚   └── button/
    β”‚       └── button.css
    └── components/
        └── button/
            └── button.templ
    
  3. Prepare .templ file with guard markers:

    package button
    
    var buttonCSSHandle = templ.NewOnceHandle()
    
    templ Button() {
      @buttonCSSHandle.Once() {
        <style type="text/css">
        /* [tempo] BEGIN - Do not edit! This section is auto-generated. */
        /* [tempo] END */
        </style>
    }
    
  4. Run the sync command:

    tempo sync
    
  5. Result:

CSS and JS are injected into the corresponding .templ files, replacing the content between the guard markers.

πŸ“‹ Guard Markers Explained

tempo sync uses guard markers in .templ files to locate where CSS and JS should be injected.

By default, it looks for the following markers:

/* [tempo] BEGIN - Do not edit! This section is auto-generated. */
/* [tempo] END */

Only the text inside square brackets ([tempo]) can be customized in your tempo.yaml file under the templates.guard_marker setting.

[!IMPORTANT] If no guard markers are present, tempo sync will skip the file, ensuring only intended sections are updated.

βš™οΈ Configuration

πŸ“„ View Default tempo.yaml Configuration
# The root folder for Tempo files
tempo_root: .tempo-files

app:
  # The name of the Go module being worked on.
  go_module: <FROM_GO.MOD>

  # The Go package name where components will be organized and generated.
  go_package: components

  # The directory where asset files (CSS, JS) will be generated.
  assets_dir: assets

  # Indicates whether JavaScript is required for the component.
  # with_js: false

  # The name of the CSS layer to associate with component styles.
  # css_layer: components

processor:
  # Number of concurrent workers (numCPUs * 2).
  workers: 4

  # Summary format: long, compact, json, none.
  summary_format: compact

templates:
  # A text placeholder or sentinel used in template files to mark auto-generated content.
  guard_marker: tempo

  # File extensions used for template files.
  extensions:
    - .gotxt
    - .gotmpl
    - .tpl

Configuration Options

Project Structure
Key Default Description
tempo_root .tempo-files Root folder where tempo stores its templates and actions.
Application-Specific Settings
Key Default Description
app.go_module Name of the Go module being worked on read from go.mod.
app.go_package components Go package name where components will be generated.
app.assets_dir assets Directory where asset files (CSS, JS) will be generated.
app.with_js false Whether JavaScript is required for the component.
app.css_layer components CSS layer name to associate with component styles.
Files Processing Options
Key Default Description
processor.workers 4 Number of concurrent workers.
processor.summary_format long Summary format: long, compact, json, none.
Templates Options
Key Default Description
templates.guard_marker tempo Placeholder used in templates to mark auto-generated content.
templates.extensions .gotxt, .gotmpl, .tpl File extensions used for template files.
templates.function_providers [] (empty) A list of external function providers that can be loaded from a local path or a remote URL.
Function Provider Format

Each function provider entry follows this format:

templates:
  function_providers:
    - name: default
      type: path
      value: ./providers/default
    - name: custom
      type: url
      value: https://github.com/user/custom-provider.git
Fields
Field Type Description
name string (Optional) The name of the function provider.
type string Specifies if the provider is a local path or a remote url (Git repo).
value string The actual path or URL where the provider is located.
πŸ› οΈ Example Use Case

If your project follows a custom structure, you can update tempo.yaml like this:

app:
  go_module: myproject
  package: ui/components
  assets_dir: static/assets
  with_js: true
  css_layer: my-layer

This ensures:

  • Assets are stored in static/assets
  • Components are generated under ui/components
  • JavaScript support is enabled
  • CSS styles are associated with the my-layer layer

πŸ—οΈ Templates & Actions

πŸ“Œ The tempo component define and tempo variant define commands generate:

  • Templates stored in .tempo-files/templates/, using Go’s text/template.
  • Actions defined in .tempo-files/actions/, specifying file and folder creation in JSON format.

Templates

Templates define the structure of components and variants. They use Go’s text/template engine along with custom template functions provided by Tempo.

πŸ“Œ Default Template Functions

Tempo provides a set of built-in helper functions:

Function Description
goPackageName Converts a string into a valid Go package name.
goExportedName Converts a string into a valid exported Go function name.
goUnexportedName Converts a string into a valid unexported Go function name.
normalizePath Normalizes a path string.
isEmpty Checks if a string is empty.
πŸ“Œ Built-in Template Variables

Tempo automatically provides a set of predefined variables that can be used inside templates. These variables come from the configuration and CLI context during execution.

Variable Description
TemplatesDir The root directory containing template files.
ActionsDir The root directory containing actions files.
GoModule The name of the Go module being worked on.
GoPackage The Go package name where components will be organized and generated.
ComponentName The name of the component being generated.
VariantName The name of the variant being generated (if applicable).
AssetsDir The directory where asset files (CSS, JS) will be generated.
WithJs Whether JavaScript is required for the component (true/false).
CssLayer The CSS layer name associated with component styles.
GuardMarker Placeholder used in templ files to mark auto-generated sections.
πŸ“Œ Extending Template Functions

Tempo supports external function providers, allowing you to integrate additional helper functions into your templates.

See the full guide in Extending Tempo.

Actions

Actions define how templates should be processed. They are stored in .tempo-files/actions/ as JSON files.

Example component action file (component.json):

[
  {
    "item": "file",
    "templateFile": "component/templ/component.templ.gotxt",
    "path": "{{ .GoPackage }}/{{ .ComponentName | goPackageName }}/{{ .ComponentName | goPackageName }}.templ"
  },
  {
    "item": "file",
    "templateFile": "component/assets/css/base.css.gotxt",
    "path": "{{ .AssetsDir }}/{{ .ComponentName | goPackageName }}/css/base.css"
  },
  {
    "item": "folder",
    "source": "component/assets/css/themes",
    "destination": "{{ .AssetsDir }}/{{ .ComponentName | goPackageName }}/css/themes"
  }
]

Each object defines a templating action:

Key Type Description
item file/folder Whether the action is creating a file or a folder.
templateFile string Path to the template file (only for file items).
path string Output path for the generated file.
source string Source folder (only for folder items).
destination string Destination folder for copied content.
skipIfExists bool Whether to skip the file if it already exists.
force bool Whether to overwrite existing files.

[!NOTE] When item is folder, all files inside the source folder will be processed and copied to the destination folder.

Variant actions (variant.json) follow the same structure but target a specific component’s variant subfolder.

πŸ”Œ Extending Tempo with Custom Functions

Tempo allows you to register external function providers, which means you can integrate additional helper functions into your templates.

πŸ“¦ Using External Function Providers

You can add external function providers in two ways:

1. Via the tempo.yaml configuration file:

templates:
  function_providers:
    - name: sprig
      type: url
      value: https://github.com/indaco/tempo-provider-sprig.git

2. Via the CLI using the tempo register functions command:

  • Register a GitHub repository provider:

    tempo register functions --name sprig --url https://github.com/indaco/tempo-provider-sprig.git
    
  • Register a local provider from a directory:

    tempo register functions --name myprovider --path /path/to/myprovider_module
    

πŸ›  Implementing a Custom Template Function Provider

To create a custom function provider, implement the TemplateFuncProvider interface from the github.com/indaco/tempo-api.

See tempo api for full details.

Example: Creating a Custom Function Provider

package myprovider

import (
    "text/template"
    "github.com/indaco/tempo-api/templatefuncs"
)

// MyProvider implements the TemplateFuncProvider interface
type MyProvider struct{}

// GetFunctions returns a map of function names to implementations
func (p *MyProvider) GetFunctions() template.FuncMap {
    return template.FuncMap{
        "myFunc": func() string { return "Hello from myFunc!" },
    }
}

// Provider instance
var Provider templatefuncs.TemplateFuncProvider = &MyProvider{}

Once your provider is implemented:

  • If published as a Git repository, register it using:

    tempo register functions --name myprovider --url https://github.com/user/myprovider_module.git
    
  • If stored locally, register it using:

    tempo register functions --name myprovider --path /path/to/myprovider_module
    

πŸ“¦ Available Function Providers

A pre-built function provider for Masterminds/sprig is available for convenience:

tempo register functions --name sprig --url https://github.com/indaco/tempo-provider-sprig.git

This allows you to access Sprig functions within Tempo templates.

🀝 Contributing

Contributions are welcome!

See the Contributing Guide for setting up the development tools.

πŸ†“ License

This project is licensed under the MIT License - see the LICENSE file for details.

Directories ΒΆ

Path Synopsis
cmd
tempo command
internal
app
generator
GoPackage generator provides functionality for processing templating actions, including adding single files or multiple files to a destination directory.
GoPackage generator provides functionality for processing templating actions, including adding single files or multiple files to a destination directory.
git
resolver
GoPackage resolver provides helper functions to resolve values by prioritizing CLI-provided values over configuration-defined values, ensuring proper validation and error handling when necessary
GoPackage resolver provides helper functions to resolve values by prioritizing CLI-provided values over configuration-defined values, ensuring proper validation and error handling when necessary
utils
GoPackage utils provides utility functions and helpers for common operations such as string manipulation and template rendering.
GoPackage utils provides utility functions and helpers for common operations such as string manipulation and template rendering.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL