diff --git a/README.md b/README.md index 8074a65..8f123a9 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ scripts/dev.sh --host # 前端监听所有网卡,手机访问 http://<电脑 ``` 浏览器打开 http://localhost:5173 ,首次使用直接设置登录密码。端口与数据目录可用 `API_PORT`、`WEB_PORT`、`RAWMARK_DATA` 覆盖,详见 `scripts/dev.sh --help`。 +开发模式从源码统计可选字体,日志导出的版本标为 `dev`,不读取已有 `web/dist`;生产模式使用前端构建清单与页面构建版本。 检查: diff --git a/cmd/rawmark/main.go b/cmd/rawmark/main.go index e44a23d..59d8eb5 100644 --- a/cmd/rawmark/main.go +++ b/cmd/rawmark/main.go @@ -6,7 +6,6 @@ package main import ( - "bytes" "context" "errors" "fmt" @@ -18,13 +17,13 @@ import ( "os" "os/signal" "path/filepath" - "rawmark/internal/backup" "sync" "syscall" "time" "rawmark/internal/api" "rawmark/internal/auth" + "rawmark/internal/backup" "rawmark/internal/events" "rawmark/internal/search" "rawmark/internal/store" @@ -84,23 +83,10 @@ func run(addr string) error { if err != nil { return fmt.Errorf("读取内置字体统计失败: %w", err) } - // 构建标识与前端入口一致,不另建版本来源。 - static := web.Dist() - html, err := fs.ReadFile(static, "index.html") + buildVersion, err := web.BuildVersion() if err != nil { return err } - buildVersion := "" - marker := []byte(`= 0 { - buildVersion = string(rest[:end]) - } - } - if buildVersion == "" { - return fmt.Errorf("缺少构建版本") - } ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() for { diff --git a/web/embed.go b/web/embed.go index ca11a34..8f7c8a6 100644 --- a/web/embed.go +++ b/web/embed.go @@ -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(` 0 { + return string(rest[:end]), nil + } + } + return "", fmt.Errorf("缺少构建版本") +} diff --git a/web/embed_dev.go b/web/embed_dev.go index 8908ee4..8bec9c8 100644 --- a/web/embed_dev.go +++ b/web/embed_dev.go @@ -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 +} diff --git a/web/embed_dev_test.go b/web/embed_dev_test.go new file mode 100644 index 0000000..6626887 --- /dev/null +++ b/web/embed_dev_test.go @@ -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("字体源文件缺失时不得返回零值伪装成功") + } +} diff --git a/web/font_storage.go b/web/font_storage.go index 3aa6965..db4d341 100644 --- a/web/font_storage.go +++ b/web/font_storage.go @@ -1,3 +1,5 @@ +//go:build !dev + package web import (