go build tag 实现开发环境与生产环境采用不同的 embed.FS 策略

更新日期: 2022-05-30 阅读次数: 5009 字数: 518 分类: golang

通过 go embed.FS 将 gin 模板及静态资源文件打包进二进制程序 确实非常方便在服务器上部署、更新程序,但是开发环境调试前端代码就非常麻烦了。 因为每次修改都需要重新编译。

所以,我想利用 go build tag 条件编译来实现,开发环境不启用 embed.FS,只在发布时使用。

重命名问题

xxx redeclared in this block

build tag 的互斥来解决。即

//go:build !prod
//go:build prod

省略任何一个,如果定义了同名的函数,或者变量,都会导致重复声明的问题。

文件命名来区分

绞尽脑汁起名 load.go / load_embed.go, 不如 dev.go / prod.go 直观。

实现代码

dev.go

//go:build !prod

package templates

import (
	// ...
)

// LoadTemplateAndStatic loads from disk
func LoadTemplateAndStatic(router *gin.Engine, funcMap template.FuncMap) {
	// ...
}

prod.go

//go:build prod

package templates

import (
	// ...
)

//go:embed *
var f embed.FS

// LoadTemplateAndStatic loads from embed fs
func LoadTemplateAndStatic(router *gin.Engine, funcMap template.FuncMap) {
	// ...
}

然后在 main.go 中调用这个同名函数即可。

验证

分别编译两个版本,对比一下就能发现,确实生效了。

go build
go build -tags prod

gopls 警告信息

prod.go|3 col 9-17 warning| No packages found for open file /mnt/d/work/tools2/backend/templates/prod.go: <nil>. If this file contains build tags, try adding "-tags=<build tag>" to your gopls "buildFlag" configuration (see (https://github.com/golang/tools/blob/master/gopls/doc/settings.md#buildflags-string). Otherwise, see the troubleshooting guidelines for help investigating (https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md).

翻了半天的 vim-go 代码,才找到 gopls build tags 的设置方法。

function! go#config#BuildTags() abort
  return get(g:, 'go_build_tags', '')
endfunction

let l:buildtags = go#config#BuildTags()
if buildtags isnot ''
  let l:config.buildFlags = extend(l:config.buildFlags, ['-tags', go#config#BuildTags()])
endif

let g:go_build_tags = "prod"

然而并没有作用,我怀疑是 VIM 下 ale 和 vim-go 都用了 gopls,没有都配置才导致此问题。

不想折腾了,等代码上线在回头来看看这部分的配置。

init 的使用

一些 build tags 是通过 init 来执行相关的逻辑的。

虽然最终没有用这个方案,但是尝试了一个版本实现,还是了解了这部分逻辑:

  • 一个 package 中多个 init 的使用场景: https://stackoverflow.com/questions/45278540/whats-the-purpose-of-golang-allowing-multiple-init-in-one-package
  • 多个 init 的执行顺序: https://stackoverflow.com/questions/32829538/init-order-within-a-package/32829593#32829593

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式