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 (