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.

85 lines
2.7 KiB

import LifecycleUnit from '../lifecycle/Unit.ts'
import {Unit} from '../lifecycle/decorators.ts'
import {Handlebars} from '../external/http.ts'
import {Logging} from '../service/logging/Logging.ts'
import {fs} from '../external/std.ts'
/**
* Lifecycle unit which sets up and provides basic view engine services.
* @extends LifecycleUnit
*/
@Unit()
export default class ViewEngine extends LifecycleUnit {
/**
* The Handlebars instance.
* @type Handlebars
*/
protected _handlebars!: Handlebars
// TODO include basic app info in view data
constructor(
protected readonly logger: Logging,
) {
super()
}
async up() {
this.logger.info(`Setting views base dir: ${this.app.app_path('http', 'views')}`)
this._handlebars = new Handlebars({
baseDir: this.app.app_path('http', 'views'),
extname: '.hbs',
layoutsDir: 'layouts',
partialsDir: 'partials',
defaultLayout: 'main',
helpers: undefined,
compilerOptions: undefined,
})
const main_layout_path = this.app.app_path('http', 'views', 'layouts', 'main.hbs')
if ( !(await fs.exists(main_layout_path)) ) {
this.logger.warn(`Unable to open main view layout file: ${main_layout_path}`)
this.logger.warn(`Unless you are using a custom layout, this could cause errors.`)
}
const partials_path = this.app.app_path('http', 'views', 'partials')
if ( !(await fs.exists(partials_path)) ) {
this.logger.warn(`Unable to open view partials directory: ${partials_path}`)
this.logger.warn(`This directory must exist for the view engine to function, even if it is empty.`)
}
}
/**
* The handlebars instance.
* @type Handlebars
*/
get handlebars(): Handlebars {
return this._handlebars
}
/**
* Render a view with the given name, using the specified arguments and layout.
* @param {string} view
* @param [args]
* @param {string} [layout]
* @return Promise<string>
*/
async render(view: string, args?: any, layout?: string): Promise<string> {
this.logger.debug(`Rendering view: ${view}`)
return this.handlebars.renderView(view, args, layout)
}
/**
* Render a partial view with the given name, using the specified arguments.
* @param {string} view
* @param [args]
*/
async partial(view: string, args?: any) {
const parts = `${view}.hbs`.split(':')
const resolved = this.app.app_path('http', 'views', ...parts)
this.logger.debug(`Rendering partial: ${view} from ${resolved}`)
return this.handlebars.render(resolved, args)
}
}