直接结论:别用 go generate 做脚手架,它专为代码生成设计,缺乏参数解析、模板渲染和交互能力;应使用独立 CLI 工具(如 Cobra + text/template),配合 embed 打包模板,显式校验目录、模块路径并自动执行 go mod init。

脚手架工具该用 go generate 还是独立二进制?
直接结论:别用 go generate 做脚手架。它设计初衷是代码生成(比如从 protobuf 生成 Go 结构体),不是交互式项目初始化工具;没有参数解析、模板渲染、目录交互能力,强行塞功能容易失控。
真正靠谱的方式是写一个独立的 CLI 工具,用 github.com/spf13/cobra 管命令,text/template 渲染模板,打包成单文件二进制分发。
模板文件怎么组织才不踩坑?
常见错误是把模板硬编码进 Go 源码里——改个 README 就得 recompile,协作成本高。正确做法是把模板放在 templates/ 目录下,用 embed(Go 1.16+)打包进二进制:
- 模板路径保持相对一致,比如
templates/go.mod.tmpl、templates/main.go.tmpl - 模板里用
{{.ProjectName}}这类字段,结构体字段名必须首字母大写(否则text/template访问不到) - 避免在模板里写复杂逻辑,只做变量替换和简单
{{if}}判断;分支逻辑放到 Go 代码里控制 - 注意换行和缩进:Go 模板默认保留所有空白,用
{{- if}}和{{- end}}去掉左侧空格,防止生成文件开头多出空行
如何安全创建目录并避免覆盖已有文件?
用户执行 mycli new myproject 时,如果 myproject 目录已存在,直接 os.MkdirAll 会静默成功,但后续写文件可能覆盖关键内容。必须显式检查:
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
- 先用
os.Stat检查目标路径是否存在且是目录 - 若存在,提示用户确认(用
fmt.Print+bufio.NewReader(os.Stdin).ReadString('\n')读一行) - 若用户输入
y或yes再继续,否则return - 写文件前用
ioutil.WriteFile(Go 1.16+ 推荐os.WriteFile)而非os.Create+Write,减少中间状态残留
模块初始化和依赖管理怎么自动处理?
脚手架生成完项目后,不能只丢个空 go.mod 就完事。用户期望的是“生成即可用”,所以得自动 go mod init 并可选添加常用依赖:
立即学习“go语言免费学习笔记(深入)”;
- 调用
exec.Command("go", "mod", "init", moduleName),捕获stderr判断是否失败(比如路径含空格或非法字符) - 如果用户指定了 SDK 版本(如
--sdk v1.2.0),用exec.Command("go", "get", "github.com/xxx/sdk@v1.2.0")安装,而不是写死在模板里 - 不要自动
go mod tidy—— 它会拉取所有间接依赖,网络差时卡住;改成提示用户自行运行,并附上命令示例
最麻烦的其实是模块路径校验:用户输入的项目名可能含大写字母、短横线或点号,而 Go 模块路径要求合法导入标识符。得提前用正则 ^[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*$ 过滤,否则 go mod init 直接报错。

















