feat: 完成前后端打包

This commit is contained in:
2026-03-27 18:39:53 +08:00
parent b0db64bd7b
commit 21251c6e07
8 changed files with 201 additions and 8 deletions

2
.gitignore vendored
View File

@@ -1 +1 @@
Taskfile.yml
bin

139
Taskfile.yml Normal file
View File

@@ -0,0 +1,139 @@
version: "3"
vars:
FRONTEND_DIR: web/frontend
BIN_DIR: bin
SERVER_NAME: server
# --- 全局 Git 信息 (关键修复:放这里才能被所有子任务读取) ---
GIT_AUTHOR: zhilv666
GIT_EMAIL: zhilv666@qq.com
VERSION:
sh: git describe --tags --always --dirty 2>/dev/null || echo "dev"
BUILD_TIME:
sh: date '+%Y-%m-%d %H:%M:%S'
GIT_COMMIT:
sh: git rev-parse --short HEAD 2>/dev/null || echo "unknown"
# --- 全局注入参数 (关键修复) ---
LDFLAGS: >-
-s -w
-X "ckwk/internal/conf.Version={{.VERSION}}"
-X "ckwk/internal/conf.BuildAt={{.BUILD_TIME}}"
-X "ckwk/internal/conf.GitAuthor={{.GIT_AUTHOR}}"
-X "ckwk/internal/conf.GitEmail={{.GIT_EMAIL}}"
-X "ckwk/internal/conf.GitCommit={{.GIT_COMMIT}}"
tasks:
# ======================
# 🎨 前端
# ======================
fe:install:
desc: 安装前端依赖 📦
dir: "{{.FRONTEND_DIR}}"
cmds:
- pnpm install
fe:dev:
desc: 启动前端开发服务器 🚀
dir: "{{.FRONTEND_DIR}}"
cmds:
- pnpm dev
fe:build:
desc: 构建前端 🏗️
dir: "{{.FRONTEND_DIR}}"
cmds:
- pnpm build
fe:clean:
desc: 清理前端构建产物 🧹
dir: "{{.FRONTEND_DIR}}"
cmds:
- rm -rf dist
# ======================
# ⚙️ 后端
# ======================
be:run:
desc: 启动后端服务 🧠
cmds:
- go run ./cmd
be:build:
desc: 构建后端二进制 🔨
cmds:
- mkdir -p {{.BIN_DIR}}
- go build -o {{.BIN_DIR}}/{{.SERVER_NAME}} ./cmd
# ======================
# 🔄 开发 / 构建流程
# ======================
dev:
desc: 同时启动前后端(开发模式)🔥
cmds:
- task fe:dev &
- task be:run
dev:be:
desc: 只启动后端(配合前端 dev
cmds:
- go run ./cmd
build:
desc: 构建前端 + 后端 📦
cmds:
- task fe:build
- task be:build
rebuild:
desc: 清理并重建 🔁
cmds:
- task fe:clean
- task build
# ======================
# 🚀 生产构建
# ======================
release:
desc: 构建多平台二进制 🌍
vars:
MODE: -X "ckwk/internal/conf.Mode=release"
cmds:
- task fe:build
- mkdir -p {{.BIN_DIR}}
# 🐧 Linux
- CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags '{{.LDFLAGS}} {{.MODE}}' -o {{.BIN_DIR}}/{{.SERVER_NAME}}-linux-amd64 ./cmd
# 🪟 Windows
- CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags '{{.LDFLAGS}} {{.MODE}}' -o {{.BIN_DIR}}/{{.SERVER_NAME}}-windows-amd64.exe ./cmd
# --- 压缩任务 (优化版) ---
upx:
desc: "压缩二进制文件 (智能跳过 macOS 和 Windows ARM)"
cmds:
- echo "* 开始压缩处理..."
- |
if ! command -v upx > /dev/null 2>&1; then
echo "⚠️ 未找到 UPX跳过压缩。"
exit 0
fi
for file in {{.BIN_DIR}}/*; do
[ -f "$file" ] || continue
if [[ "$file" == *"darwin"* ]]; then
echo "* [SKIP] 跳过 macOS: $(basename $file)"
elif [[ "$file" == *"windows_arm"* ]]; then
echo "* [SKIP] 跳过 Win ARM: $(basename $file)"
else
echo "* [UPX] 压缩: $(basename $file)"
upx --best --lzma "$file" >/dev/null 2>&1 || echo " ⚠️ 失败: $file"
fi
done
silent: true

View File

@@ -1,5 +0,0 @@
package main
func main() {
}

12
internal/conf/var.go Normal file
View File

@@ -0,0 +1,12 @@
package conf
// 构建信息
var (
Mode string = "debug"
Version string = "unknown"
BuildAt string = "unknown"
GitAuthor string = "unknown"
GitEmail string = "unknown"
GitCommit string = "unknown"
)

View File

@@ -1,16 +1,27 @@
package router
import (
"ckwk/internal/conf"
"ckwk/internal/handler"
"ckwk/internal/middleware"
"ckwk/internal/schedule"
"ckwk/pkg/log"
"ckwk/web"
"io/fs"
"net/http"
"strings"
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
func SetupRouter() *gin.Engine {
if conf.Mode != gin.ReleaseMode {
gin.SetMode(gin.DebugMode)
} else {
gin.SetMode(gin.ReleaseMode)
}
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"*://*", "http://localhost:5173"},
@@ -22,7 +33,16 @@ func SetupRouter() *gin.Engine {
}))
wkHandler := handler.NewWKHandler()
sessionMiddleware := middleware.SessionMiddleware(wkHandler.Session)
schedule.StartCron(wkHandler.Session)
// schedule.StartCron(wkHandler.Session)
dist, err := fs.Sub(web.Public, web.DistDir)
if err != nil {
log.Fatal("failed to read dist dir", zap.Error(err))
}
distHTTP := http.FS(dist)
r.StaticFS("/js", http.FS(mustSub(dist, "js")))
r.StaticFS("/assets", http.FS(mustSub(dist, "assets")))
r.StaticFileFS("/favicon.ico", "favicon.ico", distHTTP)
api := r.Group("/api")
{
@@ -40,5 +60,23 @@ func SetupRouter() *gin.Engine {
}
}
r.NoRoute(func(ctx *gin.Context) {
if strings.HasPrefix(ctx.Request.URL.Path, "/api") {
ctx.JSON(404, gin.H{"code": 404, "msg": "API not found"})
return
}
ctx.Header("Content-Type", "text/html; charset=utf-8")
http.ServeFileFS(ctx.Writer, ctx.Request, dist, "index.html")
})
return r
}
// 辅助函数:简化 fs.Sub 的错误处理
func mustSub(f fs.FS, dir string) fs.FS {
sub, err := fs.Sub(f, dir)
if err != nil {
panic("failed to find static dir: " + dir)
}
return sub
}

1
web/.gitignore vendored
View File

@@ -1 +1,2 @@
frontend
dist

8
web/web.go Normal file
View File

@@ -0,0 +1,8 @@
package web
import "embed"
const DistDir = "frontend/dist"
//go:embed all:frontend/dist
var Public embed.FS