Express需同时配置app.set('view engine','ext')与app.engine('ext',handler)才能渲染对应后缀文件;多引擎共存须用不同扩展名或手动调用引擎,避免app.engine覆盖。
Express 本身不内置 HTML 模板引擎,必须显式配置 app.engine() 才能支持 .html 后缀文件渲染;多个 HTML 引擎共存是可行的,但不能靠简单叠加 app.set('view engine', ...) 实现——它只接受单个字符串值,无法“切换”引擎。
app.set('view engine', 'html') 不等于“用了 HTML 引擎”这个设置只是告诉 Express:当调用 res.render('index') 时,默认去找 index.html(而不是 index.ejs 或 index.pug)。但它不负责解析该文件——解析逻辑由 app.engine('html', ...) 绑定的回调决定。如果没配 app.engine('html', ...),直接访问会报错 Error: Failed to lookup view "index" in views directory 或更隐晦的 TypeError: callback is not a function。
app.set('view engine', 'html') 是“找文件名”的约定app.engine('html', require('ejs').__express) 才是“怎么读这个文件”的实现app.engine 的第一个参数(扩展名)必须和 view engine 值一致,否则匹配失效.html 文件不能直接注册两个 app.engine('html', ...)——后注册的会覆盖前一个。正确做法是用文件扩展名区分,比如让 EJS 处理 .ejs.html,art-template 处理 .art.html:
npm install ejs art-template express-art-template
app.engine('ejs.html', require('ejs').__express);app.engine('art.html', require('express-art-template'));
app.set('view engine', 'ejs.html')),或渲染时显式传扩展名:res.render('page.ejs.html', data)、res.render('page.art.html', data)
views 目录下对应文件存在,例如 views/page.ejs.html 和 views/page.art.html
consolidate 统一接入多个引擎的坑consolidate 能简化多引擎接入,但它对 .html 后缀的支持有陷阱:
立即学习“前端免费学习笔记(深入)”;
consolidate.ejs 当作函数调用,但 EJS 的 __express 方法依赖 filename 参数,而 consolidate 在某些版本中可能未透传该参数,导致 include 或 partial 失效consolidate.ejs 和 consolidate.handlebars 到同一扩展名(如 html),仍会发生覆盖consolidate 接入非主流引擎(如 swig、dot),主流引擎(EJS/Pug/Handlebars)优先走原生 app.engine 绑定最可控的方式不是靠扩展名,而是绕过 res.render() 自动查找机制,在路由里手动调用引擎函数:
const ejs = require('ejs')、const template = require('art-template')
const html1 = fs.readFileSync('./views/page1.html', 'utf8')
const result1 = ejs.render(html1, data);const result2 = template.render('./views/page2.html', data);
res.send(result1) 或 res.type('html').send(...) 输出layout、partials 等框架级功能多引擎共存不是配置开关,而是路径、扩展名、调用时机三者的组合决策;最容易被忽略的是 app.engine 的覆盖行为——它不报错,只静默替换,出问题时往往以为是模板语法错,其实根本没走到你期望的那个引擎。