feat(v1.0.4): DX & Docs 改进
按报告 v1.0.4 路线图完成 5 项开发体验与文档改进: #25 模块路径文档改进: - 保留 -core 后缀(xlgo 是多产品系列:xlgo-core/xlgo-orm/xlgo-ai) - README 快速开始补完整 import 示例 + 新增「模块路径与包名」小节 - CLAUDE.md Import Path Note 措辞明确化 #27 Without* Option 定位文档化: - 调研确认 Without* 有真实用例(测试覆盖 + NewFullStack 后排除单项) - 不删不标 Deprecated,在 app.go 注释 + README 说明其定位 #28 CLI 多模板: - xlgo new --template minimal/api/fullstack - minimal 轻量HTTP无依赖,api 标准业务分层(默认),fullstack 全组件 - 三模板实测生成正确 #29 examples/ 目录: - examples/minimal(50行可跑,无外部依赖) - examples/full(mysql+redis+jwt+user CRUD) - examples/README.md #30 文档结构: - Version_*.md + report.md 移到 docs/plans/(v2.0-review.md) - 新增 docs/README.md 索引 - CHANGELOG/GUIDE 留根目录(按惯例) - .gitignore 整理 build/vet/test + examples 编译全绿。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+61
-24
@@ -19,17 +19,46 @@ func createProject(name string) {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建目录结构
|
||||
dirs := []string{
|
||||
name,
|
||||
name + "/config",
|
||||
name + "/handler",
|
||||
name + "/model",
|
||||
name + "/repository",
|
||||
name + "/service",
|
||||
name + "/middleware",
|
||||
name + "/public",
|
||||
name + "/logs",
|
||||
// 解析 --template 与 --module 参数(默认 template=api)
|
||||
tmplName := "api"
|
||||
module := name
|
||||
args := os.Args[3:]
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch args[i] {
|
||||
case "--template", "-t":
|
||||
if i+1 < len(args) {
|
||||
tmplName = args[i+1]
|
||||
i++
|
||||
}
|
||||
case "--module", "-m":
|
||||
if i+1 < len(args) {
|
||||
module = args[i+1]
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 校验模板名
|
||||
switch tmplName {
|
||||
case "minimal", "api", "fullstack":
|
||||
// ok
|
||||
default:
|
||||
fmt.Printf("未知模板: %s(可选: minimal / api / fullstack)\n", tmplName)
|
||||
return
|
||||
}
|
||||
|
||||
// minimal 模板目录结构最小化;api/fullstack 含完整分层目录
|
||||
var dirs []string
|
||||
dirs = append(dirs, name, name+"/public", name+"/logs")
|
||||
if tmplName != "minimal" {
|
||||
dirs = append(dirs,
|
||||
name+"/config",
|
||||
name+"/handler",
|
||||
name+"/model",
|
||||
name+"/repository",
|
||||
name+"/service",
|
||||
name+"/middleware",
|
||||
)
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
@@ -39,12 +68,6 @@ func createProject(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取模块路径
|
||||
module := name
|
||||
if len(os.Args) > 3 && os.Args[3] == "--module" && len(os.Args) > 4 {
|
||||
module = os.Args[4]
|
||||
}
|
||||
|
||||
caser := cases.Title(language.English)
|
||||
data := TemplateData{
|
||||
Package: caser.String(name),
|
||||
@@ -54,14 +77,28 @@ func createProject(name string) {
|
||||
Year: time.Now().Year(),
|
||||
}
|
||||
|
||||
// 按模板选择 main.go 与 config.yaml
|
||||
var mainTmpl, configTmpl string
|
||||
switch tmplName {
|
||||
case "minimal":
|
||||
mainTmpl, configTmpl = templates.MainMinimal, templates.ConfigMinimal
|
||||
case "fullstack":
|
||||
mainTmpl, configTmpl = templates.MainFull, templates.ConfigFull
|
||||
default: // api
|
||||
mainTmpl, configTmpl = templates.Main, templates.Config
|
||||
}
|
||||
|
||||
// 创建文件
|
||||
files := map[string]string{
|
||||
name + "/main.go": templates.Main,
|
||||
name + "/config.yaml": templates.Config,
|
||||
name + "/go.mod": fmt.Sprintf(templates.GoMod, module, xlgo.Version),
|
||||
name + "/Makefile": templates.Makefile,
|
||||
name + "/.gitignore": templates.Gitignore,
|
||||
name + "/handler/home.go": templates.Handler,
|
||||
name + "/main.go": mainTmpl,
|
||||
name + "/config.yaml": configTmpl,
|
||||
name + "/go.mod": fmt.Sprintf(templates.GoMod, module, xlgo.Version),
|
||||
name + "/Makefile": templates.Makefile,
|
||||
name + "/.gitignore": templates.Gitignore,
|
||||
}
|
||||
// api/fullstack 模板带示例 handler
|
||||
if tmplName != "minimal" {
|
||||
files[name+"/handler/home.go"] = templates.Handler
|
||||
}
|
||||
|
||||
for path, content := range files {
|
||||
@@ -84,7 +121,7 @@ func createProject(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("✓ 项目 %s 创建成功\n", name)
|
||||
fmt.Printf("✓ 项目 %s 创建成功(模板: %s)\n", name, tmplName)
|
||||
fmt.Println("\n下一步:")
|
||||
fmt.Printf(" cd %s\n", name)
|
||||
fmt.Println(" go mod tidy")
|
||||
|
||||
+10
-3
@@ -11,15 +11,22 @@ func printUsage() {
|
||||
fmt.Println(`xlgo - Go Web 框架脚手架工具
|
||||
|
||||
用法:
|
||||
xlgo new <项目名> 创建新项目
|
||||
xlgo make handler <名称> 创建处理器
|
||||
xlgo new <项目名> [--template <模板>] [--module <模块路径>] 创建新项目
|
||||
xlgo make handler <名称> 创建处理器
|
||||
xlgo make repository <名称> 创建仓库
|
||||
xlgo make model <名称> 创建模型
|
||||
xlgo make service <名称> 创建服务
|
||||
xlgo version 显示版本号
|
||||
xlgo version 显示版本号
|
||||
|
||||
模板 (xlgo new --template <名称>):
|
||||
minimal 轻量 HTTP 服务,不依赖 MySQL/Redis(默认入门)
|
||||
api 标准业务 API,含 MySQL/Redis/JWT 与 handler/model/repository/service 分层(默认)
|
||||
fullstack 全组件,一键启用 MySQL/Redis/Storage/Swagger/AutoMigrate
|
||||
|
||||
示例:
|
||||
xlgo new myapp
|
||||
xlgo new myapp --template minimal
|
||||
xlgo new myapp --template fullstack --module github.com/me/myapp
|
||||
xlgo make handler user
|
||||
xlgo make repository user`)
|
||||
}
|
||||
|
||||
+168
-2
@@ -2,8 +2,12 @@ package main
|
||||
|
||||
// Templates 存放所有代码生成模板
|
||||
var templates = struct {
|
||||
Main string
|
||||
Config string
|
||||
Main string // api 模板:标准业务 API(mysql+redis+jwt+分层)
|
||||
MainMinimal string // minimal 模板:轻量 HTTP,无外部依赖
|
||||
MainFull string // fullstack 模板:全组件
|
||||
Config string // api 模板配置
|
||||
ConfigMinimal string
|
||||
ConfigFull string
|
||||
GoMod string
|
||||
Makefile string
|
||||
Gitignore string
|
||||
@@ -104,6 +108,168 @@ storage:
|
||||
path: ./public
|
||||
base_url: http://localhost:8080/public
|
||||
|
||||
log:
|
||||
dir: ./logs
|
||||
max_size: 100
|
||||
max_backups: 30
|
||||
max_age: 30
|
||||
compress: true
|
||||
`,
|
||||
|
||||
// MainMinimal minimal 模板:轻量 HTTP 服务,不依赖 MySQL/Redis/Storage
|
||||
MainMinimal: `package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/middleware"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/EthanCodeCraft/xlgo-core/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var configPath string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&configPath, "config", "./config.yaml", "配置文件路径")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
app := xlgo.New(
|
||||
xlgo.WithConfigPath(configPath),
|
||||
xlgo.WithLogger(),
|
||||
xlgo.WithHealthRoutes(),
|
||||
xlgo.WithMiddlewares(middleware.Logger(), middleware.CORS()),
|
||||
xlgo.WithModules(router.ModuleFunc(registerRoutes)),
|
||||
)
|
||||
|
||||
if err := app.Run(); err != nil {
|
||||
fmt.Printf("启动失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func registerRoutes(r *gin.RouterGroup) {
|
||||
api := r.Group("/api/v1")
|
||||
api.GET("/", func(c *gin.Context) {
|
||||
response.Success(c, gin.H{"message": "Hello {{.Name}}!"})
|
||||
})
|
||||
}
|
||||
`,
|
||||
|
||||
// ConfigMinimal minimal 模板配置:仅 app + server + log,无数据库/Redis
|
||||
ConfigMinimal: `app:
|
||||
name: "{{.Name}}"
|
||||
site_name: "{{.NameLower}}"
|
||||
version: "1.0.0"
|
||||
env: "dev"
|
||||
debug: true
|
||||
base_url: "http://localhost:8080"
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
mode: development
|
||||
|
||||
log:
|
||||
dir: ./logs
|
||||
max_size: 100
|
||||
max_backups: 30
|
||||
max_age: 30
|
||||
compress: true
|
||||
`,
|
||||
|
||||
// MainFull fullstack 模板:全组件(FullStack),含 Swagger + Storage
|
||||
MainFull: `package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/middleware"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/EthanCodeCraft/xlgo-core/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var configPath string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&configPath, "config", "./config.yaml", "配置文件路径")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// NewFullStack 一键启用全部组件:Logger/MySQL/Redis/Storage/Wire/Health/Swagger/AutoMigrate
|
||||
// 如需排除个别组件,追加对应 Without* Option,例如 xlgo.WithoutSwaggerRoutes()
|
||||
app := xlgo.NewFullStack(
|
||||
xlgo.WithConfigPath(configPath),
|
||||
xlgo.WithMiddlewares(middleware.Logger(), middleware.CORS()),
|
||||
xlgo.WithModules(router.ModuleFunc(registerRoutes)),
|
||||
// xlgo.WithModels(&User{}, &Order{}), // 注册模型以启用自动迁移
|
||||
)
|
||||
|
||||
if err := app.Run(); err != nil {
|
||||
fmt.Printf("启动失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func registerRoutes(r *gin.RouterGroup) {
|
||||
api := r.Group("/api/v1")
|
||||
api.GET("/", func(c *gin.Context) {
|
||||
response.Success(c, gin.H{"message": "Welcome to {{.Name}} (fullstack)!"})
|
||||
})
|
||||
}
|
||||
`,
|
||||
|
||||
// ConfigFull fullstack 模板配置:全组件配置
|
||||
ConfigFull: `app:
|
||||
name: "{{.Name}}"
|
||||
site_name: "{{.NameLower}}"
|
||||
version: "1.0.0"
|
||||
env: "dev"
|
||||
debug: true
|
||||
base_url: "http://localhost:8080"
|
||||
token_expire: 86400
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
mode: development
|
||||
|
||||
database:
|
||||
driver: mysql # mysql(默认)或 postgres
|
||||
host: localhost
|
||||
port: 3306
|
||||
user: root
|
||||
password: your_password
|
||||
name: {{.NameLower}}
|
||||
max_idle_conns: 10
|
||||
max_open_conns: 100
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 0
|
||||
|
||||
jwt:
|
||||
secret: your_jwt_secret_key_here
|
||||
expire: 86400
|
||||
|
||||
storage:
|
||||
driver: local
|
||||
local:
|
||||
path: ./public
|
||||
base_url: http://localhost:8080/public
|
||||
|
||||
log:
|
||||
dir: ./logs
|
||||
max_size: 100
|
||||
|
||||
Reference in New Issue
Block a user