chore: baseline snapshot before moderation-strictness feature
Repo .git was damaged (refs/ missing, index truncated, object store near-empty). Repaired via git init (rebuilt refs), stale index preserved as .git/index.corrupt-20260910.bak, then full worktree committed as a rollback baseline.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
// Copyright 2022 E99p1ant. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"github.com/flamego/template"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/tdewolff/minify/v2"
|
||||
"github.com/tdewolff/minify/v2/css"
|
||||
"github.com/tdewolff/minify/v2/html"
|
||||
"github.com/tdewolff/minify/v2/js"
|
||||
)
|
||||
|
||||
var _ template.FileSystem = (*FileSystem)(nil)
|
||||
|
||||
type file struct {
|
||||
name string
|
||||
data []byte
|
||||
ext string
|
||||
}
|
||||
|
||||
func (f *file) Name() string { return f.name }
|
||||
func (f *file) Data() ([]byte, error) { return f.data, nil }
|
||||
func (f *file) Ext() string { return f.ext }
|
||||
|
||||
type FileSystem struct {
|
||||
files []template.File
|
||||
}
|
||||
|
||||
func (fs *FileSystem) Files() []template.File { return fs.files }
|
||||
|
||||
// getExt returns the extension of given name, prefixed with the dot (".").
|
||||
// 必须用 filepath.Ext:取最后一个点之后的部分。
|
||||
// 旧的 strings.Index 实现会把 "foo.bar.html" 的扩展名误判为 ".bar.html",
|
||||
// 导致模板名截取错误(如 "foo" 丢失子目录结构)。
|
||||
func getExt(name string) string {
|
||||
return filepath.Ext(name)
|
||||
}
|
||||
|
||||
func Minify(embedFS embed.FS, dir string, allowedExtensions []string) (*FileSystem, error) {
|
||||
var beforeSize, afterSize int64
|
||||
|
||||
var files []template.File
|
||||
m := minify.New()
|
||||
m.AddFunc("text/html", html.Minify)
|
||||
m.AddFunc("text/css", css.Minify)
|
||||
m.AddFuncRegexp(regexp.MustCompile(`^(application|text)/(x-)?(java|ecma)script$`), js.Minify)
|
||||
|
||||
err := fs.WalkDir(embedFS, dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
relpath, err := filepath.Rel(dir, path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get relative path")
|
||||
}
|
||||
|
||||
ext := getExt(relpath)
|
||||
for _, allowed := range allowedExtensions {
|
||||
if ext != allowed {
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := embedFS.ReadFile(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read")
|
||||
}
|
||||
beforeSize += int64(len(data))
|
||||
|
||||
var buf bytes.Buffer
|
||||
switch filepath.Ext(path) {
|
||||
case ".html":
|
||||
if err := html.Minify(m, &buf, bytes.NewReader(data), nil); err != nil {
|
||||
return errors.Wrap(err, "minify html")
|
||||
}
|
||||
default:
|
||||
buf = *bytes.NewBuffer(data)
|
||||
}
|
||||
afterSize += int64(buf.Len())
|
||||
|
||||
name := filepath.ToSlash(relpath[:len(relpath)-len(ext)])
|
||||
files = append(files,
|
||||
&file{
|
||||
name: name,
|
||||
data: buf.Bytes(),
|
||||
ext: ext,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "walk")
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"before_size": beforeSize,
|
||||
"after_size": afterSize,
|
||||
"ratio": float64(afterSize) / float64(beforeSize),
|
||||
}).Info("Minify succeeded")
|
||||
|
||||
return &FileSystem{
|
||||
files: files,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user