README-zh_cn.md
Air 是为 Go 应用开发设计的实时重载命令行工具。只需在你的项目根目录下输入 air,然后把它放在一边,专注于你的代码即可。注意:该工具与生产环境的热部署无关。
go install(推荐)使用 go 1.25 或更高版本:
go install github.com/air-verse/air@latest
请确保你的 Go bin 目录已加入 PATH:
export PATH="$PATH:$(go env GOPATH)/bin"
go get -tool(安装到项目中)使用 go 1.25 或更高版本:
go get -tool github.com/air-verse/air@latest
# 然后像这样使用:
go tool air -v
# 二进制文件会安装到 $(go env GOPATH)/bin/air
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# 或者把它安装在 ./bin/ 路径下
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s
air -v
参见 goblin.run。
# 二进制文件将会安装到 /usr/local/bin/air
curl -sSfL https://goblin.run/github.com/air-verse/air | sh
# 自定义路径安装
curl -sSfL https://goblin.run/github.com/air-verse/air | PREFIX=/tmp sh
brew install go-air
scoop install air
mise use -g air
拉取 cosmtrek/air 镜像,用法见 Docker。
# 进入你的项目目录
cd /path/to/your_project
# 先尝试读取当前目录中的 `.air.toml`;如果不存在,则使用默认配置
air
如果想生成一份可以自行修改的配置文件,先执行一次 air init,之后直接执行 air 即可:
# 生成带有默认配置的 .air.toml
air init
# 会自动读取 .air.toml
air
如果要显式指定配置文件,可以使用 -c:
air -c .air.toml
全部可用配置项请参考 air_example.toml 文件。
.env 文件加载你可以把参数添加在 air 命令之后,传递给构建出来的二进制文件。
# 会执行 ./tmp/main bench
air bench
# 会执行 ./tmp/main server --port 8080
air server --port 8080
你可以使用 -- 参数来分隔传递给 air 命令和传递给二进制文件的参数。
# 会运行 ./tmp/main -h
air -- -h
# 会使用个性化配置来运行 air,并把 -h 传给构建出的二进制文件
air -c .air.toml -- -h
air -d 命令能打印所有日志。
air 的配置字段都支持以命令行参数的形式传入。可以通过下面的命令查看全部可用参数:
air -h
# 或者
air --help
如果你只是想配置构建命令和运行命令,可以直接使用以下命令,而无需配置文件:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api"
对于以列表形式输入的参数,使用逗号来分隔各项:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api" --build.exclude_dir "templates,build"
列表类参数也可以重复传入,取值会按出现顺序依次追加。当命令行由脚本或 Makefile 生成时,这种写法很方便:
# 等价于 --env_files ".env,.env.local,.env.secret"
air --env_files ".env,.env.local" --env_files ".env.secret"
使用 misc.startup_banner 控制 Air 启动时打印的内容。
[misc]
# 不设置(默认):显示内置的 ASCII 横幅和版本号。
# 设置为空字符串:什么都不打印。
startup_banner = ""
# 设置为自定义文本:打印这段文本,替代内置横幅。
# startup_banner = "API watcher"
使用 build.entrypoint 指定 build.cmd 构建出的二进制文件,以及它的执行方式。该值可以是字符串(只指定可执行文件),也可以是字符串数组。使用数组时,第一个元素是可执行文件(相对于 root 解析;如果其中不含路径分隔符,则从 $PATH 中查找),其余元素都会作为默认参数。build.args_bin 和命令行传入的参数会追加在这些内联参数之后。旧的 build.bin 字段已弃用,将在未来的版本中移除,请优先使用 entrypoint 的写法。
[build]
entrypoint = ["./tmp/main"]
args_bin = ["server", ":8080"]
# 也可以把默认参数直接内联写在二进制文件后面。
entrypoint = ["./tmp/main", "server", ":8080"]
# 不带路径分隔符时会从 PATH 中查找,例如 dlv。
entrypoint = [
"dlv", "exec", "--accept-multiclient", "--log", "--headless", "--continue",
"--listen=:8999", "--api-version", "2", "./tmp/main",
]
配置 env_files 后,Air 会在构建和运行之前自动从 .env 文件中加载环境变量。
# 依次加载 .env.development 和 .env。
# 靠后文件中的值会覆盖前面的值。
# 不会覆盖运行 air 之前就已存在的变量。
env_files = [".env.development", ".env"]
你可以用 [build.windows]、[build.darwin] 和 [build.linux] 按操作系统覆盖构建配置。在对应平台上运行时,这些配置块会覆盖 [build] 中的值。平台配置块中只支持以下字段:pre_cmd、cmd、post_cmd、bin、entrypoint、full_bin、args_bin。
[build]
cmd = "go build -o ./tmp/main ."
bin = "./tmp/main"
[build.windows]
cmd = "go build -o ./tmp/main.exe ."
bin = "tmp\\main.exe"
entrypoint = ["tmp\\main.exe"]
当当前系统的默认配置与基础配置不同时,air init 会自动为当前系统生成对应的平台配置块。
有时候文件变更需要的是执行某个命令,而不是重新构建应用——比如直接从磁盘提供的前端资源,或者 templ/sqlc/go generate 这类流程。可以为它们各自声明一个 [[build.rules]] 配置块:
[build]
cmd = "go build -o ./tmp/main ."
# 主构建流程忽略前端目录……
exclude_dir = ["web"]
# ……但这条规则会监听它,并在变更时重新构建前端资源
[[build.rules]]
name = "assets"
include_dir = ["web"]
include_ext = ["js", "ts", "css"]
cmd = "npm run build"
[[build.rules]]
name = "templ"
include_ext = ["templ"]
cmd = "templ generate"
被规则匹配到的文件只会执行该规则的 cmd,绝不会触发重新构建,即使它同时也符合主构建的监听条件。规则涉及的目录即使写在 exclude_dir 里也依然会被监听。如果规则的命令生成了主构建正在监听的文件(例如 templ generate 生成 .go 文件),重新构建自然会随之触发。
每条规则支持 include_dir、include_ext、include_file、exclude_regex 以及 delay(防抖时间,单位毫秒,默认 1000)。include_* 匹配条件至少要填一项。规则会等待命令执行完毕;执行期间到达的变更会排队,结束后再跑一次。
Air 可以在你的 Web 应用前面挂一个小型代理,每次构建成功后自动刷新浏览器,这样就不用再手动按刷新了。
[proxy]
enabled = true
# 你在浏览器中访问的端口
proxy_port = 8090
# 你的应用实际监听的端口
app_port = 8080
照常启动 air,然后在浏览器中访问 http://localhost:8090,而不是应用自己的端口。请求会被转发到 app_port,同时 Air 会在每个 HTML 响应的 </body> 标签前注入一小段脚本;构建完成后,这段脚本就会刷新页面。
要让它生效,有两个前提:
</body> 标签——否则没有地方注入脚本,页面会原样返回;include_dir、include_ext 或 include_file 覆盖到。如果你的应用启动较慢(连接数据库、加载配置等),并出现 "unable to reach app" 错误,可以把等待时间调长:
[proxy]
# 构建完成后重试连接应用的时长,单位毫秒(默认 5000)
app_start_timeout = 10000
请拉取这个 Docker 镜像:cosmtrek/air。
docker/podman run -it --rm \
-w "<PROJECT>" \
-e "air_wd=<PROJECT>" \
-v $(pwd):<PROJECT> \
-p <PORT>:<APP SERVER PORT> \
cosmtrek/air \
-c <CONF>
<PROJECT> 是容器中的项目路径,例如 /go/example。如果你想进入容器,请添加 --entrypoint=bash。
我的一个项目运行在 Docker 中:
docker run -it --rm \
-w "/go/src/github.com/cosmtrek/hub" \
-v $(pwd):/go/src/github.com/cosmtrek/hub \
-p 9090:9090 \
cosmtrek/air
如果你想像使用普通应用程序那样持续使用 air,可以在你的 ${SHELL}rc(Bash、Zsh 等)中创建一个函数:
air() {
podman/docker run -it --rm \
-w "$PWD" -v "$PWD":"$PWD" \
-p "$AIR_PORT":"$AIR_PORT" \
docker.io/cosmtrek/air "$@"
}
其中 $PWD 会被替换为当前目录,$AIR_PORT 是要发布的端口,而 $@ 用于接收应用程序本身的参数,例如 -c:
cd /go/src/github.com/cosmtrek/hub
AIR_PORT=8080 air -c "config.toml"
services:
my-project-with-air:
image: cosmtrek/air
# working_dir 的值必须和挂载的卷保持一致
working_dir: /project-package
ports:
- <any>:<any>
environment:
- ENV_A=${ENV_A}
- ENV_B=${ENV_B}
- ENV_C=${ENV_C}
volumes:
- ./project-relative-path/:/project-package/
Dockerfile
# 选择你想要的版本,>= 1.25
FROM golang:1.25-alpine
WORKDIR /app
RUN go install github.com/air-verse/air@latest
COPY go.mod go.sum ./
RUN go mod download
CMD ["air", "-c", ".air.toml"]
docker-compose.yaml
version: "3.8"
services:
web:
build:
context: .
# 修改为你的 Dockerfile 路径
dockerfile: Dockerfile
ports:
- 8080:3000
# 为了实时重载,将代码目录绑定到 /app 目录是很重要的
volumes:
- ./:/app
有时也表现为 "No such file or directory"。请确认 Go bin 目录已加入 PATH:
export GOPATH=$HOME/xxxxx
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
export PATH=$PATH:$(go env GOPATH)/bin <---- 请确认这行在您的配置信息中!!!
应该使用 \ 来转义 bin 中的 '。相关 issue:#305
参见 #365。
[build]
cmd = "/usr/bin/true"
开启代理即可,详见代理:自动刷新浏览器。请确认你的静态文件被 include_dir、include_ext 或 include_file 覆盖到,否则修改它们不会触发刷新。更多细节请参考 #512。
请注意:当前需要 Go 1.25+(见 go.mod)。
# 1. 首先复刻(fork)这个项目
# 2. 其次克隆(clone)它
mkdir -p $GOPATH/src/github.com/cosmtrek
cd $GOPATH/src/github.com/cosmtrek
git clone [email protected]:<YOUR USERNAME>/air.git
# 3. 安装依赖
cd air
make ci
# 4. 这样就可以快乐地探索和玩耍啦!
make install
顺便说一句:欢迎 PR~
# 1. checkout 到 master 分支
git checkout master
# 2. 添加需要发布的版本号
git tag v1.xx.x
# 3. 推送到远程
git push origin v1.xx.x
# CI 将处理并发布新版本。等待大约 5 分钟,你就可以获取最新版本了
当我用 Go 和 gin 框架开发网站时,gin 缺乏实时重载的功能是令人遗憾的。我曾经尝试过 fresh,但是它用起来不太灵活,所以我试着用更好的方式来重写它。Air 就这样诞生了。
此外,非常感谢 pilu。没有 fresh 就不会有 air :)
非常感谢众多支持者。我一直铭记你们的善意。