Add view engine unit - handlebars - and response helpers
This commit is contained in:
1
lib/src/external/http.ts
vendored
1
lib/src/external/http.ts
vendored
@@ -1,2 +1,3 @@
|
||||
export * from 'https://deno.land/std@0.53.0/http/server.ts'
|
||||
export * from 'https://deno.land/std@0.53.0/http/cookie.ts'
|
||||
export { Handlebars } from 'https://deno.land/x/handlebars/mod.ts'
|
||||
18
lib/src/http/response/PartialViewResponseFactory.ts
Normal file
18
lib/src/http/response/PartialViewResponseFactory.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import ResponseFactory from './ResponseFactory.ts'
|
||||
import ViewEngine from '../../unit/ViewEngine.ts'
|
||||
import {Request} from '../Request.ts'
|
||||
|
||||
export default class PartialViewResponseFactory extends ResponseFactory {
|
||||
constructor(
|
||||
public readonly view: string,
|
||||
public readonly context?: any,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
public async write(request: Request) {
|
||||
const views: ViewEngine = this.make(ViewEngine)
|
||||
request.response.body = await views.partial(this.view, this.context)
|
||||
return request
|
||||
}
|
||||
}
|
||||
19
lib/src/http/response/ViewResponseFactory.ts
Normal file
19
lib/src/http/response/ViewResponseFactory.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import ResponseFactory from './ResponseFactory.ts'
|
||||
import ViewEngine from '../../unit/ViewEngine.ts'
|
||||
import {Request} from '../Request.ts'
|
||||
|
||||
export default class ViewResponseFactory extends ResponseFactory {
|
||||
constructor(
|
||||
public readonly view: string,
|
||||
public readonly context?: any,
|
||||
public readonly layout?: string,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
public async write(request: Request) {
|
||||
const views: ViewEngine = this.make(ViewEngine)
|
||||
request.response.body = await views.render(this.view, this.context, this.layout)
|
||||
return request
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import TemporaryRedirectResponseFactory from './TemporaryRedirectResponseFactory
|
||||
import {HTTPStatus} from '../../const/http.ts'
|
||||
import HTTPErrorResponseFactory from './HTTPErrorResponseFactory.ts'
|
||||
import HTTPError from '../../error/HTTPError.ts'
|
||||
import ViewResponseFactory from './ViewResponseFactory.ts'
|
||||
import PartialViewResponseFactory from './PartialViewResponseFactory.ts'
|
||||
|
||||
export function json(value: any): JSONResponseFactory {
|
||||
return make(JSONResponseFactory, value)
|
||||
@@ -33,3 +35,11 @@ export function redirect(destination: string): TemporaryRedirectResponseFactory
|
||||
export function http(status: HTTPStatus, message?: string): HTTPErrorResponseFactory {
|
||||
return make(HTTPErrorResponseFactory, new HTTPError(status, message))
|
||||
}
|
||||
|
||||
export function view(view: string, context?: any, layout?: string): ViewResponseFactory {
|
||||
return make(ViewResponseFactory, view, context, layout)
|
||||
}
|
||||
|
||||
export function partial(view: string, context?: any): PartialViewResponseFactory {
|
||||
return make(PartialViewResponseFactory, view, context)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@ import {container, make} from '../../../di/src/global.ts'
|
||||
import {DependencyKey} from '../../../di/src/type/DependencyKey.ts'
|
||||
import RunLevelErrorHandler from '../error/RunLevelErrorHandler.ts'
|
||||
import {Status} from '../const/status.ts'
|
||||
import Instantiable from "../../../di/src/type/Instantiable.ts";
|
||||
import {Collection} from "../collection/Collection.ts";
|
||||
import Instantiable from '../../../di/src/type/Instantiable.ts'
|
||||
import {Collection} from '../collection/Collection.ts'
|
||||
import {path} from '../external/std.ts'
|
||||
|
||||
@Service()
|
||||
export default class Application {
|
||||
@@ -66,4 +67,20 @@ export default class Application {
|
||||
this.logger.verbose(e)
|
||||
}
|
||||
}
|
||||
|
||||
get root() {
|
||||
return path.resolve('.')
|
||||
}
|
||||
|
||||
get app_root() {
|
||||
return path.resolve('./app')
|
||||
}
|
||||
|
||||
path(...parts: string[]) {
|
||||
return path.resolve(this.root, ...parts)
|
||||
}
|
||||
|
||||
app_path(...parts: string[]) {
|
||||
return path.resolve(this.app_root, ...parts)
|
||||
}
|
||||
}
|
||||
|
||||
60
lib/src/unit/ViewEngine.ts
Normal file
60
lib/src/unit/ViewEngine.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
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'
|
||||
|
||||
@Unit()
|
||||
export default class ViewEngine extends LifecycleUnit {
|
||||
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.`)
|
||||
}
|
||||
}
|
||||
|
||||
get handlebars(): Handlebars {
|
||||
return this._handlebars
|
||||
}
|
||||
|
||||
async render(view: string, args?: any, layout?: string): Promise<string> {
|
||||
this.logger.debug(`Rendering view: ${view}`)
|
||||
return this.handlebars.renderView(view, args, layout)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user