Use embed package for CSS bundles instead of generated files

This commit is contained in:
Frédéric Guillot 2021-02-17 21:58:04 -08:00 committed by fguillot
parent 42edd357bc
commit 9569666259
9 changed files with 83 additions and 58 deletions

View file

@ -13,6 +13,7 @@ import (
"miniflux.app/locale" "miniflux.app/locale"
"miniflux.app/logger" "miniflux.app/logger"
"miniflux.app/storage" "miniflux.app/storage"
"miniflux.app/ui/static"
"miniflux.app/version" "miniflux.app/version"
) )
@ -106,6 +107,15 @@ func Parse() {
logger.Fatal("Unable to load translations: %v", err) logger.Fatal("Unable to load translations: %v", err)
} }
logger.Debug("Loading static assets...")
if err := static.CalculateBinaryFileChecksums(); err != nil {
logger.Fatal("Unable to calculate binary files checksum: %v", err)
}
if err := static.GenerateStylesheetsBundles(); err != nil {
logger.Fatal("Unable to generate stylesheet bundles: %v", err)
}
db, err := database.NewConnectionPool( db, err := database.NewConnectionPool(
config.Opts.DatabaseURL(), config.Opts.DatabaseURL(),
config.Opts.DatabaseMinConns(), config.Opts.DatabaseMinConns(),

View file

@ -16,7 +16,6 @@ import (
"text/template" "text/template"
"github.com/tdewolff/minify/v2" "github.com/tdewolff/minify/v2"
"github.com/tdewolff/minify/v2/css"
"github.com/tdewolff/minify/v2/js" "github.com/tdewolff/minify/v2/js"
) )
@ -133,25 +132,6 @@ func generateJSBundle(bundleFile string, bundleFiles map[string][]string, prefix
bundle.Write(bundleFile) bundle.Write(bundleFile)
} }
func generateCSSBundle(bundleFile string, themes map[string][]string) {
bundle := NewBundle("static", "Stylesheets", "ui/static")
m := minify.New()
m.AddFunc("text/css", css.Minify)
for theme, srcFiles := range themes {
data := concat(srcFiles)
minifiedData, err := m.String("text/css", data)
if err != nil {
panic(err)
}
bundle.Files[theme] = minifiedData
bundle.Checksums[theme] = checksum([]byte(minifiedData))
}
bundle.Write(bundleFile)
}
func generateBundle(bundleFile, pkg, mapName string, srcFiles []string) { func generateBundle(bundleFile, pkg, mapName string, srcFiles []string) {
bundle := NewBundle(pkg, mapName, pkg) bundle := NewBundle(pkg, mapName, pkg)
@ -187,15 +167,6 @@ func main() {
"app": "})();", "app": "})();",
}) })
generateCSSBundle("ui/static/css.go", map[string][]string{
"light_serif": []string{"ui/static/css/light.css", "ui/static/css/serif.css", "ui/static/css/common.css"},
"light_sans_serif": []string{"ui/static/css/light.css", "ui/static/css/sans_serif.css", "ui/static/css/common.css"},
"dark_serif": []string{"ui/static/css/dark.css", "ui/static/css/serif.css", "ui/static/css/common.css"},
"dark_sans_serif": []string{"ui/static/css/dark.css", "ui/static/css/sans_serif.css", "ui/static/css/common.css"},
"system_serif": []string{"ui/static/css/system.css", "ui/static/css/serif.css", "ui/static/css/common.css"},
"system_sans_serif": []string{"ui/static/css/system.css", "ui/static/css/sans_serif.css", "ui/static/css/common.css"},
})
generateBundle("template/views.go", "template", "templateViewsMap", glob("template/html/*.html")) generateBundle("template/views.go", "template", "templateViewsMap", glob("template/html/*.html"))
generateBundle("template/common.go", "template", "templateCommonMap", glob("template/html/common/*.html")) generateBundle("template/common.go", "template", "templateCommonMap", glob("template/html/common/*.html"))
} }

3
go.mod
View file

@ -14,7 +14,8 @@ require (
github.com/prometheus/client_golang v1.9.0 github.com/prometheus/client_golang v1.9.0
github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d
github.com/stretchr/testify v1.6.1 // indirect github.com/stretchr/testify v1.6.1 // indirect
github.com/tdewolff/minify/v2 v2.9.11 // indirect github.com/tdewolff/minify/v2 v2.9.13
github.com/tdewolff/parse v2.3.4+incompatible // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d

8
go.sum
View file

@ -378,10 +378,18 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tdewolff/minify v1.1.0 h1:nxHQi1ML+g3ZbZHffiZ6eC7vMqNvSRfX3KB5Y5y/kfw= github.com/tdewolff/minify v1.1.0 h1:nxHQi1ML+g3ZbZHffiZ6eC7vMqNvSRfX3KB5Y5y/kfw=
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo= 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/minify/v2 v2.9.11 h1:8o6hclGwxm6MNwTPHabvdND5SghhHs0bn+3/+uAf0yQ= github.com/tdewolff/minify/v2 v2.9.11 h1:8o6hclGwxm6MNwTPHabvdND5SghhHs0bn+3/+uAf0yQ=
github.com/tdewolff/minify/v2 v2.9.11/go.mod h1:YZk0lGOc6CvQrqvm5f7V3ihaq3QUd9acS4HESdVDOaM= github.com/tdewolff/minify/v2 v2.9.11/go.mod h1:YZk0lGOc6CvQrqvm5f7V3ihaq3QUd9acS4HESdVDOaM=
github.com/tdewolff/minify/v2 v2.9.13 h1:RrwQhgGoYBhKN/ezStGB+crU64wPK1ZE5Jmkl63lif0=
github.com/tdewolff/minify/v2 v2.9.13/go.mod h1:faNOp+awAoo+fhFHD+NAkBOaXBAvJI2X2SDERGKnARo=
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/parse/v2 v2.5.8 h1:vutkOO9Xi3DehIzCLHqvMM2hFXo54S0iDvIG/hYznnE= github.com/tdewolff/parse/v2 v2.5.8 h1:vutkOO9Xi3DehIzCLHqvMM2hFXo54S0iDvIG/hYznnE=
github.com/tdewolff/parse/v2 v2.5.8/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= github.com/tdewolff/parse/v2 v2.5.8/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/parse/v2 v2.5.10 h1:vj35n+ljq8LuYUx436s4qB18wuwP7thrLv+t1syE39M=
github.com/tdewolff/parse/v2 v2.5.10/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=

View file

@ -5,7 +5,6 @@
package main // import "miniflux.app" package main // import "miniflux.app"
//go:generate go run generate.go //go:generate go run generate.go
//go:generate gofmt -s -w ui/static/css.go
//go:generate gofmt -s -w ui/static/js.go //go:generate gofmt -s -w ui/static/js.go
//go:generate gofmt -s -w template/views.go //go:generate gofmt -s -w template/views.go
//go:generate gofmt -s -w template/common.go //go:generate gofmt -s -w template/common.go

File diff suppressed because one or more lines are too long

View file

@ -5,32 +5,48 @@
package static // import "miniflux.app/ui/static" package static // import "miniflux.app/ui/static"
import ( import (
"bytes"
"crypto/sha256" "crypto/sha256"
"embed" "embed"
"fmt" "fmt"
"github.com/tdewolff/minify/v2"
"github.com/tdewolff/minify/v2/css"
)
// Static assets.
var (
StylesheetBundleChecksums map[string]string
StylesheetBundles map[string][]byte
) )
//go:embed bin/* //go:embed bin/*
var binaryFiles embed.FS var binaryFiles embed.FS
//go:embed css/*.css
var stylesheetFiles embed.FS
var binaryFileChecksums map[string]string var binaryFileChecksums map[string]string
func init() { // CalculateBinaryFileChecksums generates hash of embed binary files.
func CalculateBinaryFileChecksums() error {
binaryFileChecksums = make(map[string]string) binaryFileChecksums = make(map[string]string)
dirEntries, err := binaryFiles.ReadDir("bin") dirEntries, err := binaryFiles.ReadDir("bin")
if err != nil { if err != nil {
panic(err) return err
} }
for _, dirEntry := range dirEntries { for _, dirEntry := range dirEntries {
data, err := LoadBinaryFile(dirEntry.Name()) data, err := LoadBinaryFile(dirEntry.Name())
if err != nil { if err != nil {
panic(err) return err
} }
binaryFileChecksums[dirEntry.Name()] = fmt.Sprintf("%x", sha256.Sum256(data)) binaryFileChecksums[dirEntry.Name()] = fmt.Sprintf("%x", sha256.Sum256(data))
} }
return nil
} }
// LoadBinaryFile loads an embed binary file. // LoadBinaryFile loads an embed binary file.
@ -45,3 +61,44 @@ func GetBinaryFileChecksum(filename string) (string, error) {
} }
return binaryFileChecksums[filename], nil return binaryFileChecksums[filename], nil
} }
// GenerateStylesheetsBundles creates CSS bundles.
func GenerateStylesheetsBundles() error {
var bundles = map[string][]string{
"light_serif": {"css/light.css", "css/serif.css", "css/common.css"},
"light_sans_serif": {"css/light.css", "css/sans_serif.css", "css/common.css"},
"dark_serif": {"css/dark.css", "css/serif.css", "css/common.css"},
"dark_sans_serif": {"css/dark.css", "css/sans_serif.css", "css/common.css"},
"system_serif": {"css/system.css", "css/serif.css", "css/common.css"},
"system_sans_serif": {"css/system.css", "css/sans_serif.css", "css/common.css"},
}
StylesheetBundles = make(map[string][]byte)
StylesheetBundleChecksums = make(map[string]string)
minifier := minify.New()
minifier.AddFunc("text/css", css.Minify)
for bundle, srcFiles := range bundles {
var buffer bytes.Buffer
for _, srcFile := range srcFiles {
fileData, err := stylesheetFiles.ReadFile(srcFile)
if err != nil {
return err
}
buffer.Write(fileData)
}
minifiedData, err := minifier.Bytes("text/css", buffer.Bytes())
if err != nil {
return err
}
StylesheetBundles[bundle] = minifiedData
StylesheetBundleChecksums[bundle] = fmt.Sprintf("%x", sha256.Sum256(minifiedData))
}
return nil
}

View file

@ -29,7 +29,7 @@ func (h *handler) showStylesheet(w http.ResponseWriter, r *http.Request) {
return return
} }
etag, found := static.StylesheetsChecksums[filename] etag, found := static.StylesheetBundleChecksums[filename]
if !found { if !found {
html.NotFound(w, r) html.NotFound(w, r)
return return
@ -37,7 +37,7 @@ func (h *handler) showStylesheet(w http.ResponseWriter, r *http.Request) {
response.New(w, r).WithCaching(etag, 48*time.Hour, func(b *response.Builder) { response.New(w, r).WithCaching(etag, 48*time.Hour, func(b *response.Builder) {
b.WithHeader("Content-Type", "text/css; charset=utf-8") b.WithHeader("Content-Type", "text/css; charset=utf-8")
b.WithBody(static.Stylesheets[filename]) b.WithBody(static.StylesheetBundles[filename])
b.Write() b.Write()
}) })
} }

View file

@ -40,7 +40,7 @@ func New(tpl *template.Engine, r *http.Request, sess *session.Session) *View {
b.params["flashMessage"] = sess.FlashMessage(request.FlashMessage(r)) b.params["flashMessage"] = sess.FlashMessage(request.FlashMessage(r))
b.params["flashErrorMessage"] = sess.FlashErrorMessage(request.FlashErrorMessage(r)) b.params["flashErrorMessage"] = sess.FlashErrorMessage(request.FlashErrorMessage(r))
b.params["theme"] = theme b.params["theme"] = theme
b.params["theme_checksum"] = static.StylesheetsChecksums[theme] b.params["theme_checksum"] = static.StylesheetBundleChecksums[theme]
b.params["app_js_checksum"] = static.JavascriptsChecksums["app"] b.params["app_js_checksum"] = static.JavascriptsChecksums["app"]
b.params["sw_js_checksum"] = static.JavascriptsChecksums["service-worker"] b.params["sw_js_checksum"] = static.JavascriptsChecksums["service-worker"]
return b return b