feat: integrate React frontend with Go backend and containerize with Docker
Some checks failed
Continuous Integration / Lint Frontend (push) Failing after 7m48s
Continuous Integration / Lint Backend (push) Failing after 24m58s
Continuous Integration / Test (push) Failing after 12m32s
Continuous Integration / Build (push) Failing after 7m26s
Docs / Build Docs (push) Has been skipped
Docs / Build and Release Docs (push) Failing after 5m42s
Continuous Integration / Release (push) Has been skipped

- Rewrite Dockerfile with 4-stage build process:
  - Stage 1: Build React SPA with Bun (oven/bun:latest)
  - Stage 2: Build Go binary with embedded frontend (golang:1.25-alpine)
  - Stage 3: Fetch runtime dependencies (alpine:3.23)
  - Stage 4: Minimal runtime container (busybox:1.37.0-musl)
- Add comprehensive comments explaining each build stage
- Add build verification checks to ensure frontend embeds correctly
- Update compose.yaml with environment variables (FB_PORT=80, FB_ADDRESS=0.0.0.0)
- Add docker-compose.dev.yaml for development with hot reload support
- Modify http/static.go to serve 'index.html' instead of 'public/index.html'
- Final production image: ~50MB with non-root user and health checks
- Enable both production and development Docker workflows
This commit is contained in:
2026-03-16 16:13:22 +01:00
parent 49553233fe
commit 65ffa1785c
4 changed files with 216 additions and 24 deletions

View File

@@ -1,12 +1,12 @@
package fbhttp
import (
"compress/gzip"
"encoding/json"
"errors"
"fmt"
"io/fs"
"io"
"compress/gzip"
"io/fs"
"log"
"net/http"
"os"
@@ -110,7 +110,7 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
}
w.Header().Set("x-xss-protection", "1; mode=block")
return handleWithStaticData(w, r, d, assetsFs, "public/index.html", "text/html; charset=utf-8")
return handleWithStaticData(w, r, d, assetsFs, "index.html", "text/html; charset=utf-8")
}, "", store, server)
static = handle(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
@@ -153,7 +153,7 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
defer f.Close()
acceptEncoding := r.Header.Get("Accept-Encoding")
if strings.Contains(acceptEncoding, "gzip") {
if strings.Contains(acceptEncoding, "gzip") {
w.Header().Set("Content-Encoding", "gzip")
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
@@ -168,7 +168,7 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
defer gzReader.Close()
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
if _, err := io.Copy(w, gzReader); err != nil {
return http.StatusInternalServerError, err
}