模板继承里那套 `__STATIC__` 别名,生产环境突然失效后我才摸清"资源发布"和"模板编译"是两班人马

站长杂谈 14 浏览 0 回复 返回上级

上周给老项目换 CDN,顺手把静态资源从项目目录挪到了 OSS。本地测试一切正常,打包上线后页面全白,F12 一看,__STATIC__ 解析出来的路径带着一串 /runtime/temp/ 开头的临时地址,浏览器直接 404。

折腾了两个小时才发现,问题根本不在 CDN 回源配置,而是我混淆了"模板引擎替换"和"资源实际发布位置"这两个环节。

模板编译时:别名是"指路牌"

ThinkPHP 的 {:asset('css/app.css')} 或者 __STATIC__,本质上是模板引擎在编译阶段做的字符串替换。它只管按 view_replace_str 里的配置,把别名换成你写的路径,至于这个路径后面有没有文件、文件在哪,模板引擎不关心。

我之前图省事,__STATIC__ 配的是 /static,项目里 public/static 目录确实存在,本地 Apache 直接指到 public,当然跑得通。

资源发布时:路径是"实体票"

上线后用了 Nginx,配置里做了动静分离,/static 被单独指向了一个挂载的共享存储。但那次迁 OSS,我把 public/static 里的文件清掉了,想着反正走 CDN。结果模板引擎还在按老配置输出 /static/css/app.css,Nginx 找不到本地文件,又因为没有正确回源到 OSS,直接裸奔 404。

更坑的是,我为了"兼容",在模板里混用了三种写法:

· <link rel="stylesheet" href="__STATIC__/css/app.css"> —— 走别名替换
· <link rel="stylesheet" href="/static/css/app.css"> —— 写死绝对路径
· {:url('static/css/app.css')} —— 想动态生成,但 url 助手是给路由用的,这里纯属误用

三种写法在本地都能工作,但上线后各自的表现完全不同。写死路径的那个反而最稳定,因为 Nginx 匹配规则简单;别名那个因为我还配了个 __CDN__ 别名做 AB 测试,结果某次缓存刷新不彻底,部分用户拿到了带旧域名的 HTML,新域名下的 CSS 跨域报红。

现在的做法:把"模板可见"和"资源可达"拆开管

我在 config/view.php 里只保留一套最基础的 __STATIC__ 配置,指向一个固定的入口路径,比如 /assets。然后在 Nginx 层统一处理 /assets 的映射:开发环境指到本地 public,预发环境指到内部文件服务,生产环境走 CDN 域名。

模板里不再出现任何域名拼接逻辑,所有资源调用统一用 __STATIC__ 开头。如果需要版本号,用构建工具在发布时把 app.css 打成 app.a3f2b1c.css,同时生成一份 manifest.json,PHP 端读这个映射表做最终替换。

这样模板编译只负责"相对路径正确",资源在哪、怎么加速,是部署和构建环节的事。两边解耦之后,上次换 CDN 只改了 Nginx 和 OSS 策略,一行模板代码没动,上线过程从之前的两小时缩到十分钟。

有个细节差点又踩坑:ThinkPHP 的模板缓存是文件级的,改 view_replace_str 后必须清 runtime/view,否则旧编译结果会继续用老别名。我写过一条部署脚本专门干这个,但某次手动覆盖文件忘了执行,结果又白屏了五分钟。

现在这条清缓存命令写进了 CI 的最后一步,和"重启队列"放一起,当成上线 checklist 的固定项。模板继承写深了是脑壳疼,但资源路径这种"看起来简单"的东西,坑起来更隐蔽——因为它往往在本地根本复现不了。

评论0
回复 · 0
还没有回复
微信客服 微信客服