import {Express, Router} from "express"; import path from "path"; import config from "config"; import ApplicationComponent from "../ApplicationComponent"; import {logger} from "../Logger"; import "svelte/register"; import ViewEngine from "../frontend/ViewEngine"; import {readdirRecursively} from "../Utils"; import FileCache from "../utils/FileCache"; import Controller, {RouteParams} from "../Controller"; import * as querystring from "querystring"; import {ParsedUrlQueryInput} from "querystring"; import util from "util"; export default class FrontendToolsComponent extends ApplicationComponent { private readonly publicAssetsCache: FileCache = new FileCache(); private readonly viewEngines: ViewEngine[]; public constructor( private readonly publicAssetsDir: string, ...viewEngines: ViewEngine[] ) { super(); this.viewEngines = viewEngines; } public async start(app: Express): Promise { // Cache public assets if (config.get('asset_cache')) { logger.info('Caching assets from', this.publicAssetsDir, '...'); await readdirRecursively( this.publicAssetsDir, async file => await this.publicAssetsCache.load(file), ); } else { logger.info('Asset cache disabled.'); } // Setup express view engine let main = true; for (const viewEngine of this.viewEngines) { viewEngine.setup(app, main); main = false; } // Add util globals this.setupGlobals(); } public async stop(): Promise { for (const viewEngine of this.viewEngines) { await viewEngine.stop(); } } public async handle(router: Router): Promise { router.use((req, res, next) => { res.locals.inlineAsset = (urlPath: string) => { return this.publicAssetsCache.getOrFail(path.join(this.publicAssetsDir, urlPath)); }; next(); }); // Add request context locals router.use((req, res, next) => { res.locals.url = req.url; res.locals.params = req.params; res.locals.query = req.query; res.locals.body = req.body; next(); }); } public async preCompileViews(watch: boolean): Promise { for (const viewEngine of this.viewEngines) { await viewEngine.preCompileAll(watch); } } public setupGlobals(): void { ViewEngine.setGlobal('route', ( route: string, params: RouteParams = [], query: ParsedUrlQueryInput = {}, absolute: boolean = false, ) => Controller.route(route, params, query, absolute)); ViewEngine.setGlobal('app_version', this.getApp().getVersion()); ViewEngine.setGlobal('core_version', this.getApp().getCoreVersion()); ViewEngine.setGlobal('querystring', querystring); ViewEngine.setGlobal('app', config.get('app')); ViewEngine.setGlobal('dump', (val: unknown) => { return util.inspect(val); }); ViewEngine.setGlobal('hex', (v: number) => { return v.toString(16); }); } }