refac: rethought the complete workflow and deployement flow ; docs etc.
This commit is contained in:
1 parent
4a6209a8db
commit
09bd5afa4a
26 files changed
+800
-334
No files matched your search
@@ -86,8 +86,18 @@ func getUseCases(repos *Repositories) *UseCases {
|
||||
}
|
||||
}
|
||||
|
||||
func InitContainer() *UseCases {
|
||||
func InitContainer() (*UseCases, func() error) {
|
||||
db := getDb()
|
||||
repos := getRepositories(db)
|
||||
return getUseCases(repos)
|
||||
return getUseCases(repos), closeDb(db)
|
||||
}
|
||||
|
||||
func closeDb(db *gorm.DB) func() error {
|
||||
return func() error {
|
||||
sqlDb, err := db.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sqlDb.Close()
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,23 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
const hashedAssetsPrefix = "assets/"
|
||||
|
||||
const (
|
||||
hashedAssetCacheControl = "public, max-age=31536000, immutable"
|
||||
staticFileCacheControl = "public, max-age=3600"
|
||||
indexCacheControl = "no-store, no-cache, must-revalidate"
|
||||
)
|
||||
|
||||
const devNotice = "RenewCMS was built with -tags nofrontend: the SPA is served by the Vite dev server (http://localhost:5173)."
|
||||
|
||||
type spaHandler struct {
|
||||
staticFS fs.FS
|
||||
modTime time.Time
|
||||
@@ -20,9 +30,13 @@ type spaHandler struct {
|
||||
func NewFrontendRouter() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
|
||||
distFS, _ := fs.Sub(assets.DistEmbed, "dist")
|
||||
if assets.Dist == nil {
|
||||
r.Get("/*", serveDevNotice)
|
||||
return r
|
||||
}
|
||||
|
||||
handler := &spaHandler{
|
||||
staticFS: distFS,
|
||||
staticFS: assets.Dist,
|
||||
modTime: time.Now(),
|
||||
}
|
||||
|
||||
@@ -30,6 +44,12 @@ func NewFrontendRouter() http.Handler {
|
||||
return r
|
||||
}
|
||||
|
||||
func serveDevNotice(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = io.WriteString(w, devNotice)
|
||||
}
|
||||
|
||||
func (h *spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
path := h.cleanPath(r.URL.Path)
|
||||
if h.fileExists(path) {
|
||||
@@ -39,8 +59,8 @@ func (h *spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
h.serveIndex(w, r)
|
||||
}
|
||||
|
||||
func (h *spaHandler) cleanPath(path string) string {
|
||||
return strings.TrimPrefix(filepath.Clean(path), "/")
|
||||
func (h *spaHandler) cleanPath(p string) string {
|
||||
return strings.TrimPrefix(path.Clean("/"+p), "/")
|
||||
}
|
||||
|
||||
func (h *spaHandler) fileExists(path string) bool {
|
||||
@@ -52,11 +72,16 @@ func (h *spaHandler) fileExists(path string) bool {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
return true
|
||||
stat, err := f.Stat()
|
||||
return err == nil && !stat.IsDir()
|
||||
}
|
||||
|
||||
func (h *spaHandler) serveAsset(w http.ResponseWriter, r *http.Request, path string) {
|
||||
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
|
||||
if strings.HasPrefix(path, hashedAssetsPrefix) {
|
||||
w.Header().Set("Cache-Control", hashedAssetCacheControl)
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", staticFileCacheControl)
|
||||
}
|
||||
http.FileServer(http.FS(h.staticFS)).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
@@ -74,6 +99,6 @@ func (h *spaHandler) serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate")
|
||||
w.Header().Set("Cache-Control", indexCacheControl)
|
||||
http.ServeContent(w, r, "index.html", h.modTime, content)
|
||||
}
|
||||
+23
-6
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/MadAppGang/httplog"
|
||||
"github.com/go-chi/chi/v5"
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
"github.com/go-chi/jwtauth/v5"
|
||||
)
|
||||
@@ -55,6 +56,7 @@ func InitBackendRoutes(container *UseCases) *chi.Mux {
|
||||
|
||||
enableLoggingIfDev(r, "backend")
|
||||
|
||||
r.Use(chimiddleware.GetHead)
|
||||
r.Use(middleware.JsonContentTypeMiddleware)
|
||||
r.Get("/", GetHelloWorld)
|
||||
r.Group(func(r chi.Router) {
|
||||
@@ -77,19 +79,34 @@ func InitFrontendRoutes() *chi.Mux {
|
||||
return r
|
||||
}
|
||||
|
||||
func InitRoutes(container *UseCases) *chi.Mux {
|
||||
backend := InitBackendRoutes(container)
|
||||
frontend := InitFrontendRoutes()
|
||||
func GetHealth(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
_, _ = w.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
apiRouter := chi.NewRouter()
|
||||
apiRouter.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: strings.Split(os.Getenv("CORS_ALLOWED_ORIGINS"), ";"),
|
||||
func enableCorsIfConfigured(r *chi.Mux) {
|
||||
origins := os.Getenv("CORS_ALLOWED_ORIGINS")
|
||||
if origins == "" {
|
||||
return
|
||||
}
|
||||
r.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: strings.Split(origins, ";"),
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
|
||||
ExposedHeaders: []string{"Link"},
|
||||
AllowCredentials: false,
|
||||
MaxAge: 300,
|
||||
}))
|
||||
}
|
||||
|
||||
func InitRoutes(container *UseCases) *chi.Mux {
|
||||
backend := InitBackendRoutes(container)
|
||||
frontend := InitFrontendRoutes()
|
||||
|
||||
apiRouter := chi.NewRouter()
|
||||
enableCorsIfConfigured(apiRouter)
|
||||
apiRouter.Use(chimiddleware.GetHead)
|
||||
apiRouter.Get("/healthz", GetHealth)
|
||||
apiRouter.Mount("/v1", backend)
|
||||
apiRouter.Mount("/", frontend)
|
||||
|
||||
|
||||
Reference in new issue
Block a user