mirror of https://gitee.com/answerdev/answer.git
optimize: the static files and handle
This commit is contained in:
parent
03c32f3fdd
commit
91478b54a2
11
Dockerfile
11
Dockerfile
|
@ -4,12 +4,7 @@ LABEL maintainer="mingcheng<mc@sf.com>"
|
|||
|
||||
COPY . /answer
|
||||
WORKDIR /answer
|
||||
|
||||
RUN make install-ui-packages ui
|
||||
RUN mv ui/build /tmp
|
||||
CMD ls -al /tmp
|
||||
RUN du -sh /tmp/build
|
||||
|
||||
RUN make install-ui-packages ui && mv ui/build /tmp
|
||||
|
||||
FROM golang:1.18 AS golang-builder
|
||||
LABEL maintainer="aichy"
|
||||
|
@ -23,7 +18,7 @@ ENV GOPRIVATE git.backyard.segmentfault.com
|
|||
# Build
|
||||
COPY . ${BUILD_DIR}
|
||||
WORKDIR ${BUILD_DIR}
|
||||
COPY --from=node-builder /tmp/build ${BUILD_DIR}/web/html
|
||||
COPY --from=node-builder /tmp/build ${BUILD_DIR}/ui/build
|
||||
RUN make clean build && \
|
||||
cp answer /usr/bin/answer && \
|
||||
mkdir -p /tmp/cache && chmod 777 /tmp/cache && \
|
||||
|
@ -31,8 +26,6 @@ RUN make clean build && \
|
|||
mkdir -p /data/upfiles && chmod 777 /data/upfiles && \
|
||||
mkdir -p /data/i18n && chmod 777 /data/i18n && cp -r i18n/*.yaml /data/i18n
|
||||
|
||||
|
||||
|
||||
FROM debian:bullseye
|
||||
ENV TZ "Asia/Shanghai"
|
||||
RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list \
|
||||
|
|
|
@ -11,7 +11,7 @@ func NewHTTPServer(debug bool,
|
|||
staticRouter *router.StaticRouter,
|
||||
answerRouter *router.AnswerAPIRouter,
|
||||
swaggerRouter *router.SwaggerRouter,
|
||||
viewRouter *router.ViewRouter,
|
||||
viewRouter *router.UIRouter,
|
||||
authUserMiddleware *middleware.AuthUserMiddleware) *gin.Engine {
|
||||
|
||||
if debug {
|
||||
|
@ -22,7 +22,7 @@ func NewHTTPServer(debug bool,
|
|||
r := gin.New()
|
||||
r.GET("/healthz", func(ctx *gin.Context) { ctx.String(200, "OK") })
|
||||
|
||||
viewRouter.RegisterViewRouter(r)
|
||||
viewRouter.Register(r)
|
||||
|
||||
rootGroup := r.Group("")
|
||||
swaggerRouter.Register(rootGroup)
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/ui"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
const UIIndexFilePath = "build/index.html"
|
||||
const UIStaticPath = "build/static"
|
||||
|
||||
// UIRouter is an interface that provides ui static file routers
|
||||
type UIRouter struct {
|
||||
}
|
||||
|
||||
// NewUIRouter creates a new UIRouter instance with the embed resources
|
||||
func NewUIRouter() *UIRouter {
|
||||
return &UIRouter{}
|
||||
}
|
||||
|
||||
// _resource is an interface that provides static file, it's a private interface
|
||||
type _resource struct {
|
||||
fs embed.FS
|
||||
}
|
||||
|
||||
// Open to implement the interface by http.FS required
|
||||
func (r *_resource) Open(name string) (fs.File, error) {
|
||||
name = fmt.Sprintf(UIStaticPath+"/%s", name)
|
||||
log.Debugf("open static path %s", name)
|
||||
return r.fs.Open(name)
|
||||
}
|
||||
|
||||
// Register a new static resource which generated by ui directory
|
||||
func (a *UIRouter) Register(r *gin.Engine) {
|
||||
staticPath := os.Getenv("ANSWER_STATIC_PATH")
|
||||
info, err := os.Stat(staticPath)
|
||||
|
||||
// if ANSWER_STATIC_PATH is set and not empty, ignore embed resource
|
||||
if staticPath != "" {
|
||||
if err != nil || !info.IsDir() {
|
||||
log.Error(err)
|
||||
} else {
|
||||
log.Debugf("registering static path %s", staticPath)
|
||||
|
||||
r.LoadHTMLGlob(staticPath + "/*.html")
|
||||
r.Static("/static", staticPath+"/static")
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", gin.H{})
|
||||
})
|
||||
|
||||
// return immediately if the static path is set
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handle the static file by default ui static files
|
||||
r.StaticFS("/static", http.FS(&_resource{
|
||||
fs: ui.Build,
|
||||
}))
|
||||
|
||||
// specify the not router for default routes and redirect
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
index, err := ui.Build.ReadFile(UIIndexFilePath)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("content-type", "text/html;charset=utf-8")
|
||||
c.String(http.StatusOK, string(index))
|
||||
})
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUIRouter_Register(t *testing.T) {
|
||||
r := gin.Default()
|
||||
|
||||
NewUIRouter().Register(r)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/", nil)
|
||||
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
func TestUIRouter_Static(t *testing.T) {
|
||||
r := gin.Default()
|
||||
|
||||
NewUIRouter().Register(r)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/static/version.txt", nil)
|
||||
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "OK", w.Body.String())
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/web"
|
||||
)
|
||||
|
||||
// RegisterViewRouter
|
||||
type ViewRouter struct {
|
||||
}
|
||||
|
||||
// NewRegisterViewRouter
|
||||
func NewViewRouter() *ViewRouter {
|
||||
return &ViewRouter{}
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
fs embed.FS
|
||||
path string
|
||||
}
|
||||
|
||||
func NewResource() *Resource {
|
||||
return &Resource{
|
||||
fs: web.Static,
|
||||
path: "html",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Resource) Open(name string) (fs.File, error) {
|
||||
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
|
||||
return nil, errors.New("http: invalid character in file path")
|
||||
}
|
||||
fullName := filepath.Join(r.path, filepath.FromSlash(path.Clean("/static/"+name)))
|
||||
file, err := r.fs.Open(fullName)
|
||||
return file, err
|
||||
}
|
||||
|
||||
func (a *ViewRouter) RegisterViewRouter(r *gin.Engine) {
|
||||
//export answer_html_static_path="../../web/static"
|
||||
//export answer_html_page_path="../../web"
|
||||
static := os.Getenv("answer_html_static_path")
|
||||
index := os.Getenv("answer_html_page_path")
|
||||
if len(static) > 0 && len(index) > 0 {
|
||||
r.LoadHTMLGlob(index + "/*.html")
|
||||
r.Static("/static", static)
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", gin.H{})
|
||||
})
|
||||
return
|
||||
} else {
|
||||
r.StaticFS("/static", http.FS(NewResource()))
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.Header("content-type", "text/html;charset=utf-8")
|
||||
c.String(200, string(web.Html))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed build
|
||||
var Build embed.FS
|
|
@ -1,9 +0,0 @@
|
|||
package web
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed html/index.html
|
||||
var Html []byte
|
||||
|
||||
//go:embed html/static
|
||||
var Static embed.FS
|
Loading…
Reference in New Issue