first commit
Some checks failed
Backend Tests / Static Checks (push) Has been cancelled
Backend Tests / Tests (other) (push) Has been cancelled
Backend Tests / Tests (plugin) (push) Has been cancelled
Backend Tests / Tests (server) (push) Has been cancelled
Backend Tests / Tests (store) (push) Has been cancelled
Build Canary Image / build-frontend (push) Has been cancelled
Build Canary Image / build-push (linux/amd64) (push) Has been cancelled
Build Canary Image / build-push (linux/arm64) (push) Has been cancelled
Build Canary Image / merge (push) Has been cancelled
Frontend Tests / Lint (push) Has been cancelled
Frontend Tests / Build (push) Has been cancelled
Proto Linter / Lint Protos (push) Has been cancelled
Some checks failed
Backend Tests / Static Checks (push) Has been cancelled
Backend Tests / Tests (other) (push) Has been cancelled
Backend Tests / Tests (plugin) (push) Has been cancelled
Backend Tests / Tests (server) (push) Has been cancelled
Backend Tests / Tests (store) (push) Has been cancelled
Build Canary Image / build-frontend (push) Has been cancelled
Build Canary Image / build-push (linux/amd64) (push) Has been cancelled
Build Canary Image / build-push (linux/arm64) (push) Has been cancelled
Build Canary Image / merge (push) Has been cancelled
Frontend Tests / Lint (push) Has been cancelled
Frontend Tests / Build (push) Has been cancelled
Proto Linter / Lint Protos (push) Has been cancelled
This commit is contained in:
68
server/router/frontend/frontend.go
Normal file
68
server/router/frontend/frontend.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"io/fs"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/labstack/echo/v5/middleware"
|
||||
|
||||
"github.com/usememos/memos/internal/profile"
|
||||
"github.com/usememos/memos/internal/util"
|
||||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
//go:embed dist/*
|
||||
var embeddedFiles embed.FS
|
||||
|
||||
type FrontendService struct {
|
||||
Profile *profile.Profile
|
||||
Store *store.Store
|
||||
}
|
||||
|
||||
func NewFrontendService(profile *profile.Profile, store *store.Store) *FrontendService {
|
||||
return &FrontendService{
|
||||
Profile: profile,
|
||||
Store: store,
|
||||
}
|
||||
}
|
||||
|
||||
func (*FrontendService) Serve(_ context.Context, e *echo.Echo) {
|
||||
skipper := func(c *echo.Context) bool {
|
||||
// Skip API routes.
|
||||
if util.HasPrefixes(c.Path(), "/api", "/memos.api.v1") {
|
||||
return true
|
||||
}
|
||||
// For index.html and root path, set no-cache headers to prevent browser caching
|
||||
// This prevents sensitive data from being accessible via browser back button after logout
|
||||
if c.Path() == "/" || c.Path() == "/index.html" {
|
||||
c.Response().Header().Set(echo.HeaderCacheControl, "no-cache, no-store, must-revalidate")
|
||||
c.Response().Header().Set("Pragma", "no-cache")
|
||||
c.Response().Header().Set("Expires", "0")
|
||||
return false
|
||||
}
|
||||
// Set Cache-Control header for static assets.
|
||||
// Since Vite generates content-hashed filenames (e.g., index-BtVjejZf.js),
|
||||
// we can cache aggressively but use immutable to prevent revalidation checks.
|
||||
// For frequently redeployed instances, use shorter max-age (1 hour) to avoid
|
||||
// serving stale assets after redeployment.
|
||||
c.Response().Header().Set(echo.HeaderCacheControl, "public, max-age=3600, immutable") // 1 hour
|
||||
return false
|
||||
}
|
||||
|
||||
// Route to serve the main app with HTML5 fallback for SPA behavior.
|
||||
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
|
||||
Filesystem: getFileSystem("dist"),
|
||||
HTML5: true, // Enable fallback to index.html
|
||||
Skipper: skipper,
|
||||
}))
|
||||
}
|
||||
|
||||
func getFileSystem(path string) fs.FS {
|
||||
sub, err := fs.Sub(embeddedFiles, path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sub
|
||||
}
|
||||
Reference in New Issue
Block a user