fsnotify仅通知文件变化,不自动执行发布逻辑;需将事件映射到具体动作(如git pull、scp推送、oss上传),并按目录结构路由、处理原子写入、递归监听子目录、验证nfs/inotify兼容性。

为什么直接用 fsnotify 监听目录改不了生产发布逻辑
因为 fsnotify 只负责“通知文件变了”,它不关心你该拉代码、该清缓存、还是该上传 OSS。很多项目卡在这一步:监听到 public/js/app.js 被写入,但后续没做任何事,或者只打印了一行日志就结束了。
真正要支撑发布流程,得把事件映射到具体动作——比如检测到 .git/ 变化才触发 git pull;发现 dist/ 下有新 .html 文件,才调用 scp 推送到 Nginx 根目录;看到 images/ 里多了 PNG/JPEG,才走阿里云 OSS SDK 上传。
- 监听路径必须是实际构建输出目录(如
./dist),不是源码目录(./src) -
fsnotify.Create和fsnotify.Write都要响应,编辑器保存常先写临时文件再原子替换,只监听Write会漏事件 - Linux 容器中若挂载的是 NFS 卷,
fsnotify可能静默降级为轮询,需提前验证inotify是否可用
fsnotify 递归监听子目录的正确写法
调用 watcher.Add("dist") 只监听 dist 目录自身(比如被重命名或删除),不会捕获其内部文件变动。必须手动遍历并逐个添加子目录,否则新增 dist/css/ 或 dist/fonts/ 时完全收不到事件。
推荐用 filepath.WalkDir(Go 1.16+)而非旧版 filepath.Walk,避免符号链接循环问题:
err := filepath.WalkDir("dist", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
return watcher.Add(path)
}
return nil
})
- 每次新增子目录(如 CI 构建生成
dist/admin/)后,需重新执行上述遍历 +Add,不能只靠初始一次 - macOS 上若监听失败,检查是否被 Spotlight 索引干扰,可临时关闭:
sudo mdutil -a -i off - 监听路径权限不足会导致
watcher.Add静默失败,务必在Add后检查返回的err
如何区分静态资源和图库并路由到不同发布目标
不能靠文件扩展名硬判断(比如 .png 既可能是图标也可能是文章配图),而应按目录结构约定。例如统一要求前端构建输出遵循:dist/static/ 存 CSS/JS,dist/images/ 存图库,dist/uploads/ 存用户上传——工具只认路径前缀,不解析内容。
事件处理时提取相对路径再匹配:
if strings.HasPrefix(event.Name, "images/") {
uploadToOSS(event.Name)
} else if strings.HasPrefix(event.Name, "static/") {
syncToNginx(event.Name)
}
-
event.Name是相对监听根目录的路径,不是绝对路径,别直接拼/var/www - GitLab Webhook 触发的构建可能生成带哈希的文件名(如
app.a1b2c3.js),需配合正则识别,避免因文件名变化导致规则失效 - 上传 OSS 前建议加 MIME 类型探测(用
http.DetectContentType读前 512 字节),防止.jpg实际是 HTML 导致 CDN 渲染异常
热加载 vs 发布:嵌入式资源(embed)不能用于此场景
有人想用 //go:embed dist/* 把构建产物打进去,再靠 fsnotify 监听磁盘变化去“热重载”——这完全行不通。embed.FS 是编译期快照,运行时跟文件系统彻底脱钩,fsnotify 再怎么监听,对它毫无影响。
这个工具本质是“发布管道”,不是“开发服务器”。所有动作都基于真实磁盘文件状态,所以必须用 http.Dir 或 os.Open 读取,而不是 embed.FS。
- 如果真需要热加载能力,得换思路:用
http.Dir("./dist")提供服务,配合fsnotify检测到变更后,调用http.ServeMux.Handle重新注册 handler(注意并发安全) - 容器部署时,确保监听路径挂载为
rw权限,只读挂载下fsnotify无法监听写入事件 - 生产环境务必限制监听深度,避免误监听
/tmp或/var/log导致事件风暴
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











