You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

79 lines
2.0 KiB

/**
* 视图引擎中间件 - 纯粹的模板渲染职责
*
* 职责:
* 1. 提供模板渲染能力
* 2. 处理基础的渲染上下文
* 3. 错误处理和日志记录
*
* 不负责:
* - 业务数据获取
* - 复杂的上下文构建
* - 服务层调用
*/
import consolidate from 'consolidate'
import { resolve } from 'path'
import { logger } from '@/logger'
export default function viewsMiddleware(viewPath, options = {}) {
const {
extension = 'pug',
options: renderOptions = {}
} = options
return async function views(ctx, next) {
if (ctx.render) return await next()
/**
* 渲染模板
* @param {string} templatePath - 模板路径
* @param {object} locals - 本地变量
* @param {object} options - 渲染选项
*/
ctx.response.render = ctx.render = async function(templatePath, locals = {}, options = {}) {
const fullPath = resolve(viewPath, `${templatePath}.${extension}`)
// 基础上下文数据(只包含框架级别的数据)
const baseContext = {
currentPath: ctx.path,
isLogin: !!(ctx.state && ctx.state.user),
}
// 合并上下文:基础上下文 + locals + ctx.state + 渲染选项
const renderContext = Object.assign(
{},
baseContext,
locals,
renderOptions,
ctx.state || {},
options
)
// 添加 partials 支持
renderContext.partials = Object.assign({}, renderOptions.partials || {})
ctx.type = 'text/html'
const render = consolidate[extension]
if (!render) {
throw new Error(`Template engine not found for ".${extension}" files`)
}
try {
const html = await render(fullPath, renderContext)
ctx.body = html
return html
} catch (err) {
logger.error('View rendering error:', {
template: templatePath,
fullPath,
error: err.message,
stack: err.stack
})
throw err
}
}
return await next()
}
}