Use embed package for CSS bundles instead of generated files
This commit is contained in:
parent
42edd357bc
commit
9569666259
9 changed files with 83 additions and 58 deletions
10
cli/cli.go
10
cli/cli.go
|
@ -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(),
|
||||||
|
|
29
generate.go
29
generate.go
|
@ -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
3
go.mod
|
@ -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
8
go.sum
|
@ -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=
|
||||||
|
|
1
main.go
1
main.go
|
@ -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
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue