build: use ghcr.io/hanzoai/spa instead of custom Go server

This commit is contained in:
2026-04-18 22:29:25 -07:00
parent e029ef8dfd
commit aee31c87bb
4 changed files with 2 additions and 134 deletions
+2 -16
View File
@@ -7,19 +7,5 @@ RUN pnpm install --frozen-lockfile
COPY apps/docs apps/docs
RUN pnpm --filter lux-docs build
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS server
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY serve.go .
ARG TARGETOS=linux
ARG TARGETARCH=amd64
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags="-w -s" -o /serve .
FROM alpine:3.23
RUN apk add --no-cache ca-certificates
COPY --from=server /serve /serve
COPY --from=build /app/apps/docs/out /app
EXPOSE 3000
HEALTHCHECK --interval=10s --timeout=3s CMD wget -q --spider http://localhost:3000/health || exit 1
CMD ["/serve"]
FROM ghcr.io/hanzoai/spa
COPY --from=build /app/apps/docs/out /public
-5
View File
@@ -1,5 +0,0 @@
module github.com/luxfi/docs
go 1.26.1
require github.com/hanzoai/static v0.1.0
-2
View File
@@ -1,2 +0,0 @@
github.com/hanzoai/static v0.1.0 h1:X12eRv7z0HKomdFNRj8jHJKuQb4nSel+Hm/oboIb64I=
github.com/hanzoai/static v0.1.0/go.mod h1:nI9SvT9wqrO7gheNYnKT5hQAfTTpVLRP6UxtVrqeU+0=
-111
View File
@@ -1,111 +0,0 @@
// Static file server for Lux docs using hanzoai/static.
// Handles Next.js static export clean URLs: tries path, path.html, path/index.html, then 404.
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"path/filepath"
"syscall"
static "github.com/hanzoai/static"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "3000"
}
root := os.Getenv("ROOT")
if root == "" {
root = "/app"
}
cfg := static.CreateConfig()
cfg.Root = root
cfg.ErrorPage404 = "404.html"
cfg.CacheControl = map[string]string{
".html": "no-cache",
".json": "no-cache",
".js": "public, max-age=31536000, immutable",
".css": "public, max-age=31536000, immutable",
".png": "public, max-age=86400",
".jpg": "public, max-age=86400",
".svg": "public, max-age=86400",
".ico": "public, max-age=86400",
".woff": "public, max-age=31536000, immutable",
".woff2": "public, max-age=31536000, immutable",
"*": "public, max-age=3600",
}
handler, err := static.New(context.Background(), http.NotFoundHandler(), cfg, "docs")
if err != nil {
log.Fatalf("failed to create static handler: %v", err)
}
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "ok")
})
// Wrap static handler to try .html extension for clean URLs.
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
urlPath := r.URL.Path
// Root: serve index.html directly (avoid redirect).
if urlPath == "/" {
r.URL.Path = "/index.html"
handler.ServeHTTP(w, r)
return
}
// Has file extension: serve directly.
if filepath.Ext(urlPath) != "" {
handler.ServeHTTP(w, r)
return
}
// Try path.html (Next.js static export generates these).
htmlPath := filepath.Join(root, urlPath+".html")
if _, err := os.Stat(htmlPath); err == nil {
r.URL.Path = urlPath + ".html"
handler.ServeHTTP(w, r)
return
}
// Try path/index.html.
indexPath := filepath.Join(root, urlPath, "index.html")
if _, err := os.Stat(indexPath); err == nil {
r.URL.Path = urlPath + "/index.html"
handler.ServeHTTP(w, r)
return
}
// Fall through to static handler (will serve 404.html).
handler.ServeHTTP(w, r)
})
addr := ":" + port
srv := &http.Server{Addr: addr, Handler: mux}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
go func() {
<-ctx.Done()
log.Println("shutting down...")
srv.Shutdown(context.Background())
}()
log.Printf("serving %s on %s", root, addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("server error: %v", err)
}
}