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  }