A fast, friendly css compiler in go.
This repo is the start of a css compiler (parser, ast, and printer) and set of transforms to support new CSS syntax in current browsers. To start with, it aims to be able to replace projects like postcss-preset-env and cssnext.
It's approach is inspired from experimenting with esbuild (see here).
The package can currently parse and print most standard CSS. There are likely bugs in both.
Some transforms are supported:
Transform | Support | Notes |
---|---|---|
@import rules |
Partial | Only non-conditional imports can be inlined. Import conditions will be ignored. |
Custom Properties | Partial | Only variables defined on :root will be substituted. The compiler will ignore any non-:root variables. See #3. |
Custom Media Queries | Complete | |
Media Feature Ranges | Complete | |
:any-link |
Complete |
For now, there is only a go API.
package main
import (
"log"
"github.com/stephen/cssc"
)
func main() {
result := cssc.Compile(cssc.Options{
Entry: []string{"css/index.css"},
})
// result.Files is a map of all output files.
for path, content := range result.Files {
log.Println(path, content)
}
}
Transforms can be specified via options:
package main
import (
"github.com/stephen/cssc"
"github.com/stephen/cssc/transforms"
)
func main() {
result := cssc.Compile(cssc.Options{
Entry: []string{"css/index.css"},
Transforms: transforms.Options{
// Transform :any-link into :link and :visited equivalents.
AnyLink: transforms.AnyLinkTransform,
// Keep @import rules without transforming them or inlining their content.
ImportRules: transforms.ImportRulesPassthrough,
},
})
// result.Files...
}
By default, all features are in passthrough mode and will not get transformed.
By default, errors and warnings are printed to stderr. You can control this behavior by providing a Reporter:
package main
import (
"log"
"github.com/stephen/cssc"
)
type TestReporter []error
func (r *TestReporter) AddError(err error) {
*r = append(*r, err)
}
func main() {
var errors TestReporter
result := cssc.Compile(cssc.Options{
Entry: []string{"css/index.css"},
Reporter: &errors,
})
for _, err := range errors {
log.Println(err)
}
}
To keep track of performance, I've been benchmarking performance on (partially) parsing bootstrap.css.
$ go test -bench=. internal/parser/*.go
goos: darwin
goarch: amd64
BenchmarkParser-12 296 3934884 ns/op 1548281 B/op 45916 allocs/op
PASS
I expect this to be a moving target as I complete the parser implementation.