diff --git a/go.mod b/go.mod index 271a643..2ab4b0e 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,9 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/julienschmidt/httprouter v1.3.0 github.com/pkg/errors v0.9.1 + github.com/pquerna/otp v1.4.0 github.com/rs/zerolog v1.28.0 + github.com/tdewolff/minify v2.3.6+incompatible github.com/tkw1536/goprogram v0.2.4 golang.org/x/crypto v0.3.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db @@ -35,7 +37,8 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect - github.com/pquerna/otp v1.4.0 // indirect + github.com/tdewolff/parse v2.3.4+incompatible // indirect + github.com/tdewolff/test v1.0.7 // indirect golang.org/x/sys v0.3.0 // indirect golang.org/x/tools v0.4.0 // indirect ) diff --git a/go.sum b/go.sum index 5ad7869..bb7a398 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,7 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/feiin/sqlstring v0.3.0 h1:iyPEFijI2BxpY2M+AuhIvdNManzXa2OwGzuPaEMLUgo= github.com/feiin/sqlstring v0.3.0/go.mod h1:xpZTjVUw1nD3hMgF9SMRdPiooKSikLf4PS5j2NTn3RI= @@ -46,6 +47,7 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= @@ -53,7 +55,14 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo= +github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= +github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38= +github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= +github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM= +github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tkw1536/goprogram v0.2.4 h1:1l3+j8xjY3E3uf+ba3QRGWm09ucFCKrnNLq6g1Gq8YA= github.com/tkw1536/goprogram v0.2.4/go.mod h1:3Ngcwy7jtsZ+pINc+JfLdf8TWbvthdSS2T6Vbg44Fy8= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= diff --git a/internal/dis/component/control/home/cron.go b/internal/dis/component/control/home/cron.go index 85028aa..e371f7a 100644 --- a/internal/dis/component/control/home/cron.go +++ b/internal/dis/component/control/home/cron.go @@ -4,6 +4,7 @@ import ( "context" "github.com/FAU-CDI/wisski-distillery/internal/dis/component" + "github.com/FAU-CDI/wisski-distillery/pkg/httpx" ) type UpdateInstanceList struct { @@ -77,6 +78,6 @@ func (ur *UpdateHome) Cron(ctx context.Context) error { return err } - ur.Dependencies.Home.homeBytes.Set(bytes) + ur.Dependencies.Home.homeBytes.Set(httpx.MinifyHTML(bytes)) return nil } diff --git a/pkg/httpx/errors.go b/pkg/httpx/errors.go index ebd32df..9c3e33c 100644 --- a/pkg/httpx/errors.go +++ b/pkg/httpx/errors.go @@ -72,6 +72,6 @@ var ( return json.Marshal(map[string]any{"status": text, "code": code}) }) HTMLInterceptor = StatusInterceptor("text/html", func(code int, text string) ([]byte, error) { - return []byte(`` + text + `` + text), nil + return MinifyHTML([]byte(`` + text + `` + text)), nil }) ) diff --git a/pkg/httpx/html.go b/pkg/httpx/html.go index 0148232..5729175 100644 --- a/pkg/httpx/html.go +++ b/pkg/httpx/html.go @@ -17,10 +17,15 @@ func WriteHTML[T any](result T, err error, template *template.Template, template w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusOK) + // minify html! + minifier := MinifyHTMLWriter(w) + defer minifier.Close() + + // and return the template if templateName != "" { - template.ExecuteTemplate(w, templateName, result) + template.ExecuteTemplate(minifier, templateName, result) } else { - template.Execute(w, result) + template.Execute(minifier, result) } } diff --git a/pkg/httpx/html_minify.go b/pkg/httpx/html_minify.go new file mode 100644 index 0000000..6990923 --- /dev/null +++ b/pkg/httpx/html_minify.go @@ -0,0 +1,42 @@ +package httpx + +import ( + "io" + "regexp" + + "github.com/tdewolff/minify" + "github.com/tdewolff/minify/css" + "github.com/tdewolff/minify/html" + "github.com/tdewolff/minify/js" + "github.com/tdewolff/minify/svg" +) + +// minifier holds the minfier used for all html minification +// +// NOTE(twiesing): We can't use an init function for this, because otherwise initialization order is incorrect. +var minifier = (func() *minify.M { + m := minify.New() + m.AddFunc("text/html", html.Minify) + m.AddFunc("text/css", css.Minify) + m.AddFunc("image/svg+xml", svg.Minify) + m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) + return m +})() + +// MinifyHTMLWriter wraps the given io.Writer to minify the given html instead. +// The writer must be closed explicitly. +// +// Specific environments may chose to disable http minification, in which case MinifyHTMLWriter becomes the identity function. +func MinifyHTMLWriter(dest io.Writer) io.WriteCloser { + return minifier.Writer("text/html", dest) +} + +// MinifyHTML minifies the html source. +// If an error occurs, returns the unmodified source instead. +func MinifyHTML(source []byte) []byte { + result, err := minifier.Bytes("text/html", source) + if err != nil { + return source + } + return result +} diff --git a/pkg/lazy/lazy.go b/pkg/lazy/lazy.go index bc4406d..563c922 100644 --- a/pkg/lazy/lazy.go +++ b/pkg/lazy/lazy.go @@ -5,7 +5,7 @@ import ( ) // Lazy holds a lazily initialized value of T. -// Lazy non-zero lazy must not be copied after first use. +// A non-zero lazy must not be copied after first use. type Lazy[T any] struct { once sync.Once