用 go 写了个查看 html 文档的命令行工具

dart 和 rust 的语言都有文档生成功能,可以从注释中生成 html 格式的文档。但是很不巧的是,它们都没有提供 http 访问的工具。本地开发时只能对着 index.html 干瞪眼。虽说借助 docker 也能启动一个文档服务器,比如 docker run -it --rm -p 80:80 -v ./doc/api/:/usr/share/nginx/html nginx 。但敲这么长的命令确实有点考验记忆力。所以我写个脚本美滋滋 开发了个轮子,用于查看 html 文档(文档链接)。

其实 go 写这个超简单的,下面这行代码一行就能搞定。

go 复制代码
_ = http.ListenAndServe(":9090", http.FileServer(http.Dir("doc/api")))

但要将其写成工具的话,考虑的事情就多了。返回的 error 要处理;端口和本地目录要写成活的;要打印实际监听的端口(传入 ":0" 代表随机选择端口监听所以不能直接打印传入的参数)......最后就写成了这样。

go 复制代码
var (
	addr string // serve address
	dir  string // root path
)

func init() {
	flag.StringVar(&addr, "addr", "localhost:9090", "serve address")
	flag.StringVar(&dir, "dir", ".", "root path")
}

func main() {
	flag.Parse() // 标准库 flag 包自带 -h 和 --help 适配,不用单独写。

	l, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()

	ctx := context.Background()
	ctx, stop := signal.NotifyContext(ctx, os.Interrupt)
	defer stop()

	s := http.Server{
		Handler: http.FileServer(http.Dir(dir)),
	}

	var wg sync.WaitGroup // 虽然有点画蛇添足,但加了个 kill 适配。这种写法可以作为其他项目的参考。
	wg.Add(1)
	go func() {
		defer wg.Done()
    log.Printf("Serve at http://%s\n", l.Addr()) // 打印的是实际监听的端口,避免 ":0" 的问题
		err = s.Serve(l)
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		<-ctx.Done()
		log.Println("Closing server...")
		s.Close()
	}()

	wg.Wait()
	if !errors.Is(err, http.ErrServerClosed) {
		log.Fatal(err)
	}
}

有了这个工具后就能在本地启动工具查看文档了,以上面的 dart 工程为例:

sh 复制代码
# 克隆工程,生成文档
git clone https://github.com/kvii/kratos-plugin.git
cd kratos-plugin
dart doc

# 下载工具,启动服务
go install github.com/kvii/doc@latest
doc

# 浏览器打开 http://127.0.0.1:9090 即可访问文档

其实各个系统都能直接从命令行打开浏览器页面,比如 mac 就是 open "http://127.0.0.1:9090"。用 exec 包可以直接执行命令行命令,再适配下系统就能实现服务启动后自动打开浏览器的功能了。没加这功能的原因有二:

  1. 有的环境里可能没有浏览器,比如 linux 服务器和 devcontainer(开发容器)。
  2. 笔者开发用 vscode,它的终端对 url 有适配。ctrl + 鼠标点击就能直接浏览器里打开终端打印的 url。
相关推荐
10ms指针14 小时前
【高性能Go实践02】深水区重构:规避 sync.Pool 大对象缺陷与 Cgo 边界内存安全实践
go
鹏北海1 天前
Go 语言基础笔记 — 面向 JS/TS 前端开发者
go
鹏北海1 天前
Go 语言进阶笔记 — 面向 JS/TS 前端开发者
go
鹏北海1 天前
Go 包管理笔记 — 面向 JS/TS 前端开发者
go
百度Geek说1 天前
告别死锁和陈旧语法、告别性能瓶颈:新手Gopher 秒变 Go 语言大神
人工智能·go
用户398346161202 天前
Go-Spring 实战第 14 课 —— Bean 注册函数:Provide、Module、Group 以及 Configuration
spring·go
锋行天下2 天前
一句mysql复杂查询搞崩一个壮汉
后端·mysql·go
用户398346161203 天前
Go-Spring 实战第 13 课 —— Bean 元信息:名称、生命周期、接口导出、条件和显式依赖
spring·go
猪猪拆迁队3 天前
用 ESP32-S3 和 TinyGo,先搭个 AI 语音助手的小底座
前端·后端·go
赫媒派4 天前
炸裂!Go 1.26 三连发:go fix 现代化、pkg.go.dev API 开放、源码级内联器
go