From aa89777dda8ec656aab9fe8f09aefa5225172b43 Mon Sep 17 00:00:00 2001 From: Forest Date: Sat, 20 Dec 2025 16:44:25 +0800 Subject: [PATCH] =?UTF-8?q?ci(backend):=20=E8=B0=83=E6=95=B4=20embed=20ser?= =?UTF-8?q?ver?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 ++++++- backend/.github/workflows/ci.yml | 10 ++++++---- backend/Makefile | 14 +++++++++++-- backend/internal/web/embed_off.go | 20 +++++++++++++++++++ .../internal/web/{embed.go => embed_on.go} | 8 ++------ 5 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 backend/internal/web/embed_off.go rename backend/internal/web/{embed.go => embed_on.go} (80%) diff --git a/.gitignore b/.gitignore index d9345a80..41078f14 100644 --- a/.gitignore +++ b/.gitignore @@ -81,7 +81,12 @@ build/ release/ # 后端嵌入的前端构建产物 +# Keep a placeholder file so `//go:embed all:dist` always has a match in CI/lint, +# while still ignoring generated frontend build outputs. backend/internal/web/dist/ +!backend/internal/web/dist/ +backend/internal/web/dist/* +!backend/internal/web/dist/.keep # 后端运行时缓存数据 backend/data/ @@ -92,4 +97,4 @@ backend/data/ tests CLAUDE.md .claude -scripts \ No newline at end of file +scripts diff --git a/backend/.github/workflows/ci.yml b/backend/.github/workflows/ci.yml index 7efeea15..bee7db76 100644 --- a/backend/.github/workflows/ci.yml +++ b/backend/.github/workflows/ci.yml @@ -14,10 +14,11 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version-file: go.mod + go-version-file: backend/go.mod check-latest: true cache: true - name: Run tests + working-directory: backend run: go test ./... golangci-lint: @@ -26,11 +27,12 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version-file: go.mod + go-version-file: backend/go.mod check-latest: true cache: true - name: golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v9 with: - version: latest + version: v2.7 args: --timeout=5m + working-directory: backend diff --git a/backend/Makefile b/backend/Makefile index 9aa0c965..e59acc78 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -1,6 +1,16 @@ -.PHONY: wire +.PHONY: wire build build-embed wire: @echo "生成 Wire 代码..." @cd cmd/server && go generate - @echo "Wire 代码生成完成" \ No newline at end of file + @echo "Wire 代码生成完成" + +build: + @echo "构建后端(不嵌入前端)..." + @go build -o bin/server ./cmd/server + @echo "构建完成: bin/server" + +build-embed: + @echo "构建后端(嵌入前端)..." + @go build -tags embed -o bin/server ./cmd/server + @echo "构建完成: bin/server (with embedded frontend)" \ No newline at end of file diff --git a/backend/internal/web/embed_off.go b/backend/internal/web/embed_off.go new file mode 100644 index 00000000..ac57fb5c --- /dev/null +++ b/backend/internal/web/embed_off.go @@ -0,0 +1,20 @@ +//go:build !embed + +package web + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func ServeEmbeddedFrontend() gin.HandlerFunc { + return func(c *gin.Context) { + c.String(http.StatusNotFound, "Frontend not embedded. Build with -tags embed to include frontend.") + c.Abort() + } +} + +func HasEmbeddedFrontend() bool { + return false +} diff --git a/backend/internal/web/embed.go b/backend/internal/web/embed_on.go similarity index 80% rename from backend/internal/web/embed.go rename to backend/internal/web/embed_on.go index f05ae8df..287de3e3 100644 --- a/backend/internal/web/embed.go +++ b/backend/internal/web/embed_on.go @@ -1,3 +1,5 @@ +//go:build embed + package web import ( @@ -13,8 +15,6 @@ import ( //go:embed all:dist var frontendFS embed.FS -// ServeEmbeddedFrontend returns a Gin handler that serves embedded frontend assets -// and handles SPA routing by falling back to index.html for non-API routes. func ServeEmbeddedFrontend() gin.HandlerFunc { distFS, err := fs.Sub(frontendFS, "dist") if err != nil { @@ -25,7 +25,6 @@ func ServeEmbeddedFrontend() gin.HandlerFunc { return func(c *gin.Context) { path := c.Request.URL.Path - // Skip API and gateway routes if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "/v1/") || strings.HasPrefix(path, "/setup/") || @@ -34,7 +33,6 @@ func ServeEmbeddedFrontend() gin.HandlerFunc { return } - // Try to serve static file cleanPath := strings.TrimPrefix(path, "/") if cleanPath == "" { cleanPath = "index.html" @@ -47,7 +45,6 @@ func ServeEmbeddedFrontend() gin.HandlerFunc { return } - // SPA fallback: serve index.html for all other routes serveIndexHTML(c, distFS) } } @@ -72,7 +69,6 @@ func serveIndexHTML(c *gin.Context, fsys fs.FS) { c.Abort() } -// HasEmbeddedFrontend checks if frontend assets are embedded func HasEmbeddedFrontend() bool { _, err := frontendFS.ReadFile("dist/index.html") return err == nil