github.com/gohugoio/hugo@v0.88.1/minifiers/minifiers.go (about) 1 // Copyright 2018 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 // Package minifiers contains minifiers mapped to MIME types. This package is used 15 // in both the resource transformation, i.e. resources.Minify, and in the publishing 16 // chain. 17 package minifiers 18 19 import ( 20 "io" 21 "regexp" 22 23 "github.com/gohugoio/hugo/config" 24 "github.com/gohugoio/hugo/output" 25 "github.com/gohugoio/hugo/transform" 26 27 "github.com/gohugoio/hugo/media" 28 "github.com/tdewolff/minify/v2" 29 ) 30 31 // Client wraps a minifier. 32 type Client struct { 33 // Whether output minification is enabled (HTML in /public) 34 MinifyOutput bool 35 36 m *minify.M 37 } 38 39 // Transformer returns a func that can be used in the transformer publishing chain. 40 // TODO(bep) minify config etc 41 func (m Client) Transformer(mediatype media.Type) transform.Transformer { 42 _, params, min := m.m.Match(mediatype.Type()) 43 if min == nil { 44 // No minifier for this MIME type 45 return nil 46 } 47 48 return func(ft transform.FromTo) error { 49 // Note that the source io.Reader will already be buffered, but it implements 50 // the Bytes() method, which is recognized by the Minify library. 51 return min.Minify(m.m, ft.To(), ft.From(), params) 52 } 53 } 54 55 // Minify tries to minify the src into dst given a MIME type. 56 func (m Client) Minify(mediatype media.Type, dst io.Writer, src io.Reader) error { 57 return m.m.Minify(mediatype.Type(), dst, src) 58 } 59 60 // New creates a new Client with the provided MIME types as the mapping foundation. 61 // The HTML minifier is also registered for additional HTML types (AMP etc.) in the 62 // provided list of output formats. 63 func New(mediaTypes media.Types, outputFormats output.Formats, cfg config.Provider) (Client, error) { 64 conf, err := decodeConfig(cfg) 65 66 m := minify.New() 67 if err != nil { 68 return Client{}, err 69 } 70 71 // We use the Type definition of the media types defined in the site if found. 72 if !conf.DisableCSS { 73 addMinifier(m, mediaTypes, "css", &conf.Tdewolff.CSS) 74 } 75 if !conf.DisableJS { 76 addMinifier(m, mediaTypes, "js", &conf.Tdewolff.JS) 77 m.AddRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), &conf.Tdewolff.JS) 78 } 79 if !conf.DisableJSON { 80 addMinifier(m, mediaTypes, "json", &conf.Tdewolff.JSON) 81 m.AddRegexp(regexp.MustCompile(`^(application|text)/(x-|(ld|manifest)\+)?json$`), &conf.Tdewolff.JSON) 82 } 83 if !conf.DisableSVG { 84 addMinifier(m, mediaTypes, "svg", &conf.Tdewolff.SVG) 85 } 86 if !conf.DisableXML { 87 addMinifier(m, mediaTypes, "xml", &conf.Tdewolff.XML) 88 } 89 90 // HTML 91 if !conf.DisableHTML { 92 addMinifier(m, mediaTypes, "html", &conf.Tdewolff.HTML) 93 for _, of := range outputFormats { 94 if of.IsHTML { 95 m.Add(of.MediaType.Type(), &conf.Tdewolff.HTML) 96 } 97 } 98 } 99 100 return Client{m: m, MinifyOutput: conf.MinifyOutput}, nil 101 } 102 103 func addMinifier(m *minify.M, mt media.Types, suffix string, min minify.Minifier) { 104 types := mt.BySuffix(suffix) 105 for _, t := range types { 106 m.Add(t.Type(), min) 107 } 108 } 109 110 func addMinifierFunc(m *minify.M, mt media.Types, suffix string, min minify.MinifierFunc) { 111 types := mt.BySuffix(suffix) 112 for _, t := range types { 113 m.AddFunc(t.Type(), min) 114 } 115 }