2023-06-19 23:42:47 +02:00
|
|
|
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2021-02-17 08:36:17 +01:00
|
|
|
|
2023-08-11 04:46:45 +02:00
|
|
|
package static // import "miniflux.app/v2/internal/ui/static"
|
2021-02-17 08:36:17 +01:00
|
|
|
|
|
|
|
import (
|
2021-02-18 06:58:04 +01:00
|
|
|
"bytes"
|
2021-02-17 08:36:17 +01:00
|
|
|
"embed"
|
|
|
|
"fmt"
|
2021-02-18 06:58:04 +01:00
|
|
|
|
2024-03-11 23:03:23 +01:00
|
|
|
"miniflux.app/v2/internal/crypto"
|
|
|
|
|
2021-02-18 06:58:04 +01:00
|
|
|
"github.com/tdewolff/minify/v2"
|
|
|
|
"github.com/tdewolff/minify/v2/css"
|
2021-02-19 05:34:58 +01:00
|
|
|
"github.com/tdewolff/minify/v2/js"
|
2021-02-18 06:58:04 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// Static assets.
|
|
|
|
var (
|
|
|
|
StylesheetBundleChecksums map[string]string
|
|
|
|
StylesheetBundles map[string][]byte
|
2021-02-19 05:34:58 +01:00
|
|
|
JavascriptBundleChecksums map[string]string
|
|
|
|
JavascriptBundles map[string][]byte
|
2021-02-17 08:36:17 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
//go:embed bin/*
|
|
|
|
var binaryFiles embed.FS
|
|
|
|
|
2021-02-18 06:58:04 +01:00
|
|
|
//go:embed css/*.css
|
|
|
|
var stylesheetFiles embed.FS
|
|
|
|
|
2021-02-19 05:34:58 +01:00
|
|
|
//go:embed js/*.js
|
|
|
|
var javascriptFiles embed.FS
|
|
|
|
|
2021-02-17 08:36:17 +01:00
|
|
|
var binaryFileChecksums map[string]string
|
|
|
|
|
2021-02-18 06:58:04 +01:00
|
|
|
// CalculateBinaryFileChecksums generates hash of embed binary files.
|
|
|
|
func CalculateBinaryFileChecksums() error {
|
2021-02-17 08:36:17 +01:00
|
|
|
binaryFileChecksums = make(map[string]string)
|
|
|
|
|
|
|
|
dirEntries, err := binaryFiles.ReadDir("bin")
|
|
|
|
if err != nil {
|
2021-02-18 06:58:04 +01:00
|
|
|
return err
|
2021-02-17 08:36:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, dirEntry := range dirEntries {
|
|
|
|
data, err := LoadBinaryFile(dirEntry.Name())
|
|
|
|
if err != nil {
|
2021-02-18 06:58:04 +01:00
|
|
|
return err
|
2021-02-17 08:36:17 +01:00
|
|
|
}
|
|
|
|
|
2024-03-11 23:03:23 +01:00
|
|
|
binaryFileChecksums[dirEntry.Name()] = crypto.HashFromBytes(data)
|
2021-02-17 08:36:17 +01:00
|
|
|
}
|
2021-02-18 06:58:04 +01:00
|
|
|
|
|
|
|
return nil
|
2021-02-17 08:36:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoadBinaryFile loads an embed binary file.
|
|
|
|
func LoadBinaryFile(filename string) ([]byte, error) {
|
|
|
|
return binaryFiles.ReadFile(fmt.Sprintf(`bin/%s`, filename))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBinaryFileChecksum returns a binary file checksum.
|
|
|
|
func GetBinaryFileChecksum(filename string) (string, error) {
|
|
|
|
if _, found := binaryFileChecksums[filename]; !found {
|
|
|
|
return "", fmt.Errorf(`static: unable to find checksum for %q`, filename)
|
|
|
|
}
|
|
|
|
return binaryFileChecksums[filename], nil
|
|
|
|
}
|
2021-02-18 06:58:04 +01:00
|
|
|
|
|
|
|
// 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
|
2024-03-11 23:03:23 +01:00
|
|
|
StylesheetBundleChecksums[bundle] = crypto.HashFromBytes(minifiedData)
|
2021-02-18 06:58:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2021-02-19 05:34:58 +01:00
|
|
|
|
|
|
|
// GenerateJavascriptBundles creates JS bundles.
|
|
|
|
func GenerateJavascriptBundles() error {
|
|
|
|
var bundles = map[string][]string{
|
|
|
|
"app": {
|
2024-03-18 00:45:41 +01:00
|
|
|
"js/tt.js", // has to be first
|
2021-02-19 05:34:58 +01:00
|
|
|
"js/dom_helper.js",
|
|
|
|
"js/touch_handler.js",
|
|
|
|
"js/keyboard_handler.js",
|
|
|
|
"js/request_builder.js",
|
|
|
|
"js/modal_handler.js",
|
|
|
|
"js/app.js",
|
2023-11-06 18:28:25 +01:00
|
|
|
"js/webauthn_handler.js",
|
2021-02-19 05:34:58 +01:00
|
|
|
"js/bootstrap.js",
|
|
|
|
},
|
|
|
|
"service-worker": {
|
|
|
|
"js/service_worker.js",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var prefixes = map[string]string{
|
2021-03-08 00:25:34 +01:00
|
|
|
"app": "(function(){'use strict';",
|
2021-02-19 05:34:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var suffixes = map[string]string{
|
|
|
|
"app": "})();",
|
|
|
|
}
|
|
|
|
|
|
|
|
JavascriptBundles = make(map[string][]byte)
|
|
|
|
JavascriptBundleChecksums = make(map[string]string)
|
|
|
|
|
2024-03-12 01:23:14 +01:00
|
|
|
jsMinifier := js.Minifier{Version: 2017}
|
|
|
|
|
2021-02-19 05:34:58 +01:00
|
|
|
minifier := minify.New()
|
2024-03-12 01:23:14 +01:00
|
|
|
minifier.AddFunc("text/javascript", jsMinifier.Minify)
|
2021-02-19 05:34:58 +01:00
|
|
|
|
|
|
|
for bundle, srcFiles := range bundles {
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
|
|
|
|
if prefix, found := prefixes[bundle]; found {
|
|
|
|
buffer.WriteString(prefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, srcFile := range srcFiles {
|
|
|
|
fileData, err := javascriptFiles.ReadFile(srcFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.Write(fileData)
|
|
|
|
}
|
|
|
|
|
|
|
|
if suffix, found := suffixes[bundle]; found {
|
|
|
|
buffer.WriteString(suffix)
|
|
|
|
}
|
|
|
|
|
|
|
|
minifiedData, err := minifier.Bytes("text/javascript", buffer.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
JavascriptBundles[bundle] = minifiedData
|
2024-03-11 23:03:23 +01:00
|
|
|
JavascriptBundleChecksums[bundle] = crypto.HashFromBytes(minifiedData)
|
2021-02-19 05:34:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|