Skip to content

Extending gsx

Use gsx.toml for declarative settings. Build a project-owned gsx binary only when configuration needs to call Go code directly.

When you need a custom binary

NeedPut it in
Filters and filter packagesgsx.toml
URL rules and presetsgsx.toml
Type renderersgsx.toml
Minify levelsgsx.toml
Class mergergsx.toml
CSS or JavaScript formatter functionProject binary with gen.Main
CSS or JavaScript minifier functionProject binary with gen.Main

gen.Main still loads gsx.toml. Programmatic options take precedence over an environment override and the config file when they set the same behavior.

Create cmd/gsx/main.go

Start with a normal project-owned command, then add the formatter or minifier options described below:

go
package main

import "github.com/gsxhq/gsx/gen"

func main() {
	gen.Main()
}

The custom command has the same subcommands and flags as the standard command.

Custom CSS and JavaScript formatters

Use a custom formatter when gsx fmt should delegate embedded code to a tool such as Prettier or Biome:

go
gen.Main(
	gen.WithCSSFormatter(formatCSS),
	gen.WithJSFormatter(formatJavaScript),
)

Both callbacks have this signature:

go
func(src []byte) ([]byte, error)

They receive a self-contained <style> or executable <script> body and return formatted bytes. If a callback returns an error or panics, gsx keeps that body unchanged and continues formatting the file.

With no programmatic formatter, gsx uses token-aware CSS and JavaScript formatters. Once either custom formatter is installed, the two callbacks become an explicit pair: a nil callback leaves that language's body unchanged instead of selecting its built-in formatter. Supply both callbacks to keep formatting both languages.

The built-in formatters keep strings and comments intact, preserve meaningful line breaks and intra-line spacing, and normalize structural indentation.

Custom minifiers and minify level

Custom minifiers replace the built-in full minifier:

go
gen.Main(
	gen.WithCSSMinifier(minifyCSS),
	gen.WithJSMinifier(minifyJavaScript),
	gen.WithMinifyLevel(gen.MinifyFull, gen.MinifyFull), // CSS, JavaScript
)

The signatures are:

go
func minifyCSS(css string) (string, error)
func minifyJavaScript(js string) (string, error)

The minify level gates each callback. gen.MinifyNone skips minification; gen.MinifyFull uses the custom callback when one is present, otherwise the built-in full minifier. You can set the levels in [minify] instead of calling WithMinifyLevel; the option overrides both GSX_MINIFY and gsx.toml.

A custom CSS minifier receives only fully static <style> blocks. CSS with @{...} holes always uses gsx's built-in hole-aware path. JavaScript minifiers receive complete, holeless executable <script> bodies. A callback error stops generation and reports which minifier failed.

An executable <script> containing any @{...} hole remains wholly unminified. Neither the built-in nor a custom JavaScript minifier changes the text around its holes.

Run the project binary

Invoke the project command explicitly so its options are used:

bash
go run ./cmd/gsx generate ./...

Use the same prefix for other affected commands, for example go run ./cmd/gsx fmt -w ..

To inspect resolved declarative settings, run go run ./cmd/gsx info for the readable view or add --json for the JSON view. Function hooks are not enumerated.