import nunjucks, {Environment} from "nunjucks"; import config from "config"; import {Express, NextFunction, Request, Response, Router} from "express"; import ApplicationComponent from "../ApplicationComponent"; import Controller, {RouteParams} from "../Controller"; import * as querystring from "querystring"; import {ParsedUrlQueryInput} from "querystring"; import * as util from "util"; import * as path from "path"; import Middleware from "../Middleware"; export default class NunjucksComponent extends ApplicationComponent { private readonly viewsPath: string[]; private environment?: Environment; public constructor(viewsPath: string[] = ['views']) { super(); this.viewsPath = viewsPath; } public async start(app: Express): Promise { const opts = { autoescape: true, noCache: !config.get('view.cache'), throwOnUndefined: true, }; this.environment = new nunjucks.Environment([ ...this.viewsPath.map(path => new nunjucks.FileSystemLoader(path, opts)), new nunjucks.FileSystemLoader(path.join(__dirname, '../../../views'), opts), new nunjucks.FileSystemLoader(path.join(__dirname, '../views'), opts), ], opts) .addGlobal('route', ( route: string, params: RouteParams = [], query: ParsedUrlQueryInput = {}, absolute: boolean = false, ): string => { return Controller.route(route, params, query, absolute); }) .addGlobal('app_version', this.getApp().getVersion()) .addGlobal('core_version', this.getApp().getCoreVersion()) .addGlobal('querystring', querystring) .addGlobal('app', config.get('app')) .addFilter('dump', (val) => { return util.inspect(val); }) .addFilter('hex', (v: number) => { return v.toString(16); }); this.environment.express(app); app.set('view engine', 'njk'); } public async init(_router: Router): Promise { this.use(NunjucksMiddleware); } public getEnvironment(): Environment { if (!this.environment) throw new Error('Environment not initialized.'); return this.environment; } } export class NunjucksMiddleware extends Middleware { private env?: Environment; protected async handle(req: Request, res: Response, next: NextFunction): Promise { this.env = this.app.as(NunjucksComponent).getEnvironment(); res.locals.url = req.url; res.locals.params = req.params; res.locals.query = req.query; res.locals.body = req.body; next(); } public getEnvironment(): Environment { if (!this.env) throw new Error('Environment not initialized.'); return this.env; } }