Javascript

邮件验证码模板生产环境报错

问题现象

获取邮箱验证码时,生产环境报错:

Cannot destructure property 'templateName' of 'precompile(...)' as it is undefined

本地开发环境正常,本地执行 build 后也正常,只有上传到生产环境后触发。

后续查看 PM2 日志,看到更底层的真实错误:

Error: ENOENT: no such file or directory, open '/app/nest/dist/views/mail.hbs'

相关代码

邮件验证码发送位置:

await this.mailerService.sendMail({
  to: acount,
  subject: Mail.subject,
  template: 'mail',
  context: {
    code,
  },
})

邮件模板配置:

template: {
  dir: join(process.cwd(), '/views'),
  adapter: new HandlebarsAdapter(),
  options: {
    strict: true,
  },
}

这里的模板目录依赖 process.cwd()

根因

生产环境 PM2 配置中,Nest 服务这样启动:

{
  name: "nest",
  cwd: "/app/nest/dist/",
  script: "main.js"
}

因此生产进程里的 process.cwd() 是:

/app/nest/dist

邮件模块配置 join(process.cwd(), '/views') 后,实际模板目录变成:

/app/nest/dist/views

所以发送 template: 'mail' 时,程序会读取:

/app/nest/dist/views/mail.hbs

但原来的 Nest 构建配置没有把项目根目录的 views 目录复制到 dist/views,导致生产环境缺少这个文件。

为什么表层错误看起来不像文件缺失

@nestjs-modules/mailer 的 Handlebars 适配器内部会先调用 precompile(...) 读取模板文件。

当模板文件不存在时,底层会触发:

ENOENT: no such file or directory

但适配器里 precompile(...) 在读取失败后没有返回正常对象,后续代码继续解构:

const { templateName } = precompile(...)

于是外层看到的错误变成:

Cannot destructure property 'templateName' of 'precompile(...)' as it is undefined

这个错误是二次包装后的表现,真正根因仍然是模板文件不存在。

为什么本地正常

本地运行时通常在项目根目录启动,process.cwd() 是项目根目录:

项目根目录

所以模板目录会解析到:

项目根目录/views

本地根目录本来就有:

views/mail.hbs

因此本地不会报错。

生产环境则是在 dist 目录作为工作目录启动,模板路径变成 dist/views/mail.hbs,而构建产物里原本没有这个文件。

最终修复

nest-cli.json 中增加构建资产复制配置:

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "deleteOutDir": true,
    "assets": [
      {
        "include": "../views/**/*",
        "outDir": "dist/views"
      }
    ],
    "watchAssets": true
  }
}

这样执行 nest build 后,会把:

views/mail.hbs

复制到:

dist/views/mail.hbs

与生产环境实际读取路径保持一致。

验证方式

本地构建:

pnpm build

或直接执行:

nest build

确认构建产物存在:

ls dist/views/mail.hbs

服务器部署后确认:

ls /app/nest/dist/views/mail.hbs

如果文件存在,当前这个 ENOENT /app/nest/dist/views/mail.hbs 问题即可消除。

排查经验

遇到模板相关的 precompile(...) is undefined 时,不要只看表层错误。应优先查看 PM2 或 Node 完整日志,找到是否存在更底层的:

ENOENT

然后重点确认:

  • 生产环境 process.cwd() 是什么
  • 模板配置里的 dir 最终解析到了哪里
  • 构建产物里是否包含模板文件
  • PM2 的 cwdscript 是否改变了相对路径基准

这类问题本质上通常不是 Handlebars 模板语法错误,而是运行目录和构建产物目录结构不一致。

全部评论(0)
  • 默认
  • 回复数量
  • 与我相关
推荐文章
邮件验证码模板生产环境报错
JavaScript 对象属性枚举顺序:数字键与插入顺序
Linux安装svn服务器(yum方式)
工作中Sass常用混合器总结
微信公众号开发避坑指南之Vue篇
Javascript基础知识总结,持续更新(一)
linux安装redis完整步骤
邮件验证码模板生产环境报错
原文:https://znsay.com/article/12
更新:2026-06-30
浏览:58
评论12