fix(dev): load runtime metadata without frontend build artifacts

This commit is contained in:
eezd committed 2026-10-25 13:59:54 +08:00
1 parent c705d1ab33
commit 11f5e4fcf4
6 files changed
+96 -16

No files matched your search

+18
View File
@@ -5,7 +5,9 @@
package web
import (
"bytes"
"embed"
"fmt"
"io/fs"
)
@@ -19,3 +21,19 @@ func Dist() fs.FS {
}
return sub
}
// BuildVersion 与页面入口使用同一构建标识,生产产物缺失时明确失败。
func BuildVersion() (string, error) {
html, err := fs.ReadFile(Dist(), "index.html")
if err != nil {
return "", err
}
marker := []byte(`<meta name="rawmark-version" content="`)
if start := bytes.Index(html, marker); start >= 0 {
rest := html[start+len(marker):]
if end := bytes.IndexByte(rest, '"'); end > 0 {
return string(rest[:end]), nil
}
}
return "", fmt.Errorf("缺少构建版本")
}
+30
View File
@@ -5,6 +5,8 @@ package web
import (
"io/fs"
"os"
"path/filepath"
"regexp"
)
// Dist 在开发模式下直接读取磁盘上的 web/dist(未构建时为空,页面由 Vite 开发服务器提供),
@@ -12,3 +14,31 @@ import (
func Dist() fs.FS {
return os.DirFS("web/dist")
}
// 开发环境由 Vite 提供页面,不依赖 web/dist 中可能过期的构建产物。
func BuildVersion() (string, error) { return "dev", nil }
// FontStorage 按 Vite 构建使用的 fonts.css 统计可选字体,不包含 Maple 与 KaTeX。
func FontStorage() (int64, error) {
root := filepath.Join("web", "src", "themes")
css, err := os.ReadFile(filepath.Join(root, "fonts.css"))
if err != nil {
return 0, err
}
paths := regexp.MustCompile(`url\(['"]?(\.?/?fonts/[^)'"]+)`).FindAllSubmatch(css, -1)
seen := map[string]bool{}
var size int64
for _, match := range paths {
name := string(match[1])
if seen[name] {
continue
}
seen[name] = true
info, err := os.Stat(filepath.Join(root, name))
if err != nil {
return 0, err
}
size += info.Size()
}
return size, nil
}
+43
View File
@@ -0,0 +1,43 @@
//go:build dev
package web
import (
"os"
"path/filepath"
"testing"
)
func TestDevelopmentMetadataDoesNotRequireBuild(t *testing.T) {
root := t.TempDir()
t.Chdir(root)
themes := filepath.Join("web", "src", "themes")
if err := os.MkdirAll(filepath.Join(themes, "fonts"), 0700); err != nil {
t.Fatal(err)
}
css := `@font-face { src: url(./fonts/a.woff2); }
@font-face { src: url('./fonts/a.woff2'); }
@font-face { src: url("./fonts/b.woff2"); }`
if err := os.WriteFile(filepath.Join(themes, "fonts.css"), []byte(css), 0600); err != nil {
t.Fatal(err)
}
for name, data := range map[string]string{"a.woff2": "abc", "b.woff2": "defgh"} {
if err := os.WriteFile(filepath.Join(themes, "fonts", name), []byte(data), 0600); err != nil {
t.Fatal(err)
}
}
version, err := BuildVersion()
if err != nil || version != "dev" {
t.Fatalf("开发版本不应依赖构建产物:%q,%v", version, err)
}
size, err := FontStorage()
if err != nil || size != 8 {
t.Fatalf("开发字体统计应按源文件去重:%d,%v", size, err)
}
if err = os.Remove(filepath.Join(themes, "fonts", "b.woff2")); err != nil {
t.Fatal(err)
}
if _, err = FontStorage(); err == nil {
t.Fatal("字体源文件缺失时不得返回零值伪装成功")
}
}
+2
View File
@@ -1,3 +1,5 @@
//go:build !dev
package web
import (