This project provides an implementation of Tailwind CSS functionality in pure Go. It includes the ability to embed an HTTP handler which processes Tailwind directives on the fly, facilities to purge unneeded styles, and a command line tool.
Godoc can be found in the usual place: https://pkg.go.dev/github.com/gotailwindcss/tailwind?tab=doc
For development, the typical use is to integrate the handler found in twhandler
so Tailwind CSS processing is done as your CSS file is served. Example:
main.go
// ...
import "github.com/gotailwindcss/tailwind/twembed"
import "github.com/gotailwindcss/tailwind/twhandler"
func main() {
mux := http.NewServeMux()
mux.Handle("/", http.FileServer(http.Dir("static")))
mux.Handle("/css/", twhandler.New(http.Dir("css"), "/css", twembed.New()))
s := &http.Server{Addr: ":8182", Handler: mux}
log.Fatal(s.ListenAndServe())
}
static/index.html
<html>
<head><link rel="stylesheet" href="https://github.com/gotailwindcss/tailwind/blob/master/css/main.css"/></head>
<body><a href="#" class="button">Test Button</a></body>
</html>
css/main.css
@tailwind base;
@tailwind components;
.button { @apply inline-block m-2 p-2 rounded-md bg-green-400; }
@tailwind utilities;
In production we recommend you use a simple static file server whever possible, e.g. http.FileServer(distDir)
.
See Procesing CSS Files below for more info on how to create output from the command line, or Library Usage for how to perform Tailwind CSS conversion from Go.
The following Tailwind directives are supported:
@tailwind
@apply
These are intended to work with the same behavior as the Tailwind project. If differences are encountered/necessary this section will be updated as applicable.
To install the gotailwindcss command, do:
go get github.com/gotailwindcss/tailwind/cmd/gotailwindcss
Once installed, for help:
gotailwindcss --help
Use the build
subcommand to perform processing on one or more CSS files.
gotailwindcss build -o out.css in1.css in2.css
This project is organized into the following packages:
To process "convert" files, a "Dist" (distribution) of Tailwind CSS is required. The twembed
package provides this. Importing it embeds this data into your application, which is usually file for server applications.
Calling twembed.New()
will return a new Dist
corresponding to this embedded CSS. It is intentionally inexpensive to call and there is no need to retain an instance as opposed ot calling twembed.New()
again.
A tailwind.Convert
is used to perform processing of directives like @tailwind
and @apply
. Example:
var w bytes.Buffer
conv := tailwind.New(&w, twembed.New())
conv.AddReader("base.css", strings.NewReader(`@tailwind base;`), false)
err := conv.Run()
// w now has the processed CSS output
The twhandler
package has an HTTP handler intended to be useful during development by performing CSS processing on the fly as the file is requested. Creating a handler is simple:
h := twhandler.New(
http.Dir("/path/to/css"), // directory from which to read input CSS files
"/css", // HTTP path prefix to expect
twembed.New(), // Tailwind distribution
)
From there it is used like any other http.Handler
.
The SetWriteCloserFunc can be used in conjunction with brotli.HTTPCompressor in order to enable brotli and gzip compression. Example:
h := twhandler.New(http.Dir("/path/to/css"), "/css", twembed.New())
h.SetWriteCloserFunc(brotli.HTTPCompressor)
// ...
By default, caching is enabled on handlers created. Meaning the same output will be served without re-processing as long as the underlying input CSS file's timestamp is not modified.
And by default, responses do not have a browser caching max-age, so each load results in a new request back to the server to check for a modified file. This can be adjusted with SetMaxAge if needed.
TODO: write doc and example
This project was created as part of research while developing Vugu (doc).