Revel主应用通过路径注入识别模块模板:启用模块后,其app/views目录自动加入模板搜索路径,引用时直接使用相对路径如"partials/_alert.html",无需命名空间前缀;模板优先级为主应用>后加载模块,需确保模块正确安装且文件名符合小写+html规范。

Revel 中模块模板如何被主应用识别
Revel 的模块(module)本身不直接“导出”模板,而是靠路径注入:只要模块的 app/views 目录存在,Revel 启动时会自动将其加入模板搜索路径。这意味着你无需在主应用里 import 模板,只要模块启用且路径正确,{{template "partials/_alert.html" .}} 就能命中模块里的同名文件。
关键前提是模块必须在 conf/app.conf 中显式启用:module.alerts = github.com/yourname/revel-alerts
路径必须是 Go module 导入路径,不能是本地相对路径或文件系统路径。如果写成 module.alerts = ./modules/alerts,Revel 会静默忽略该模块,模板查找不到也不会报错——这是最常踩的坑。
跨模块复用 partial 模板的路径规则
模块内模板路径以 app/views/ 为根,和主应用完全对齐。比如模块项目结构如下:
revel-alerts/ ├── app/ │ └── views/ │ └── partials/ │ └── _alert.html
那么主应用中引用方式就是:{{template "partials/_alert.html" .}},不是 "alerts/partials/_alert.html",也不是 "modules/alerts/partials/_alert.html"。Revel 不支持命名空间前缀,所有模块的 app/views 内容扁平合并进同一个模板命名空间。
冲突处理规则:
- 主应用的模板优先级最高,会覆盖同名模块模板
- 多个模块含同名模板时,最后加载的模块胜出(加载顺序由
app.conf中 module 配置的先后决定) - 若两个模块都提供
partials/_nav.html,而你没改过主应用的同名文件,那结果取决于哪个 module 行写在app.conf更下面
为什么 {{template}} 找不到模块里的模板
常见失败原因不是路径写错,而是以下三点之一:
-
app/views目录不在模块仓库的根下——Revel 只扫描模块导入路径下的app/views,不会递归查找子目录 - 模块未真正安装到
$GOPATH/pkg/mod或 Go Modules 缓存中,导致 Revel 启动时读不到文件(可运行go list -m all | grep alerts确认) - 模板文件名含大写字母或特殊符号,如
_Alert.html,Go 模板引擎默认只加载小写开头 +.html结尾的文件
调试建议:启动 Revel 时加 -v 参数(revel run -v my-app),它会在日志里打印所有已加载的模板路径,一眼就能看出模块模板是否被扫描到。
在模块中安全传值给 partial 模板
模块的 partial 模板和主应用一样,接收的是当前上下文 .。但要注意:模块模板无法直接访问主应用控制器里通过 c.Render(...) 传入的顶层字段(如 .Title),因为 Revel 不做上下文扁平化——如果你在模块中写 {{.Title}},它取的是当前 . 的 Title 字段,而这个 . 很可能只是你传进去的一个 map 或 struct。
可靠做法是显式传递所需字段:
- 主应用调用:
{{template "partials/_alert.html" (dict "Message" .Flash.Message "Type" "error")}} - 模块 partial 中用:
<div class="alert alert-{{$Type}}">{{$Message}}</div> - 别忘了在
app/init.go注册dict函数,否则dict调用会报function "dict" not defined
模块不应假设调用方一定设置了 .CurrentRole 或 .User 这类字段;把依赖项作为参数传入,才是跨模块可复用的底线。


















