Alice Gaudon
a3ebf46b54
This renames ApplicationComponent (previous) init to initRoutes and handle to handleRoutes
135 lines
4.4 KiB
TypeScript
135 lines
4.4 KiB
TypeScript
import config from "config";
|
|
import {Express, Router} from "express";
|
|
import path from "path";
|
|
import {ParsedUrlQueryInput} from "querystring";
|
|
import util from "util";
|
|
|
|
import ApplicationComponent from "../ApplicationComponent.js";
|
|
import Controller, {RouteParams} from "../Controller.js";
|
|
import AssetCompiler from "../frontend/AssetCompiler.js";
|
|
import AssetPreCompiler from "../frontend/AssetPreCompiler.js";
|
|
import Globals from "../frontend/Globals.js";
|
|
import ViewEngine from "../frontend/ViewEngine.js";
|
|
import {logger} from "../Logger.js";
|
|
import {listFilesRecursively} from "../Utils.js";
|
|
import FileCache from "../utils/FileCache.js";
|
|
|
|
export default class FrontendToolsComponent extends ApplicationComponent {
|
|
private readonly publicDir: string;
|
|
private readonly publicAssetsCache: FileCache = new FileCache();
|
|
private readonly assetPreCompilers: AssetPreCompiler[];
|
|
private readonly globals: Globals = new Globals();
|
|
|
|
public constructor(
|
|
private readonly assetCompiler: AssetCompiler,
|
|
...assetPreCompilers: AssetPreCompiler[]
|
|
) {
|
|
super();
|
|
this.assetPreCompilers = assetPreCompilers;
|
|
this.publicDir = this.assetCompiler.targetDir;
|
|
|
|
for (const assetPreCompiler of this.assetPreCompilers) {
|
|
if (assetPreCompiler.isPublic()) {
|
|
this.assetCompiler.addExtension(assetPreCompiler.getExtension());
|
|
}
|
|
|
|
assetPreCompiler.setGlobals(this.globals);
|
|
}
|
|
}
|
|
|
|
|
|
public async init(): Promise<void> {
|
|
this.globals.set('route', (
|
|
route: string,
|
|
params: RouteParams = [],
|
|
query: ParsedUrlQueryInput = {},
|
|
absolute: boolean = false,
|
|
) => Controller.route(route, params, query, absolute));
|
|
this.globals.set('app_version', this.getApp().getVersion());
|
|
this.globals.set('core_version', this.getApp().getCoreVersion());
|
|
this.globals.set('app', config.get('app'));
|
|
this.globals.set('dump', (val: unknown) => {
|
|
return util.inspect(val);
|
|
});
|
|
this.globals.set('hex', (v: number) => {
|
|
return v.toString(16);
|
|
});
|
|
}
|
|
|
|
public async start(app: Express): Promise<void> {
|
|
// Cache public assets
|
|
if (config.get<boolean>('asset_cache')) {
|
|
logger.info('Caching assets from', this.publicDir, '...');
|
|
for (const file of await listFilesRecursively(this.publicDir)) {
|
|
await this.publicAssetsCache.load(file);
|
|
}
|
|
} else {
|
|
logger.info('Asset cache disabled.');
|
|
}
|
|
|
|
this.hookPreCompilers();
|
|
|
|
// Setup express view engine
|
|
let main = true;
|
|
for (const assetPreCompiler of this.assetPreCompilers) {
|
|
if (assetPreCompiler instanceof ViewEngine) {
|
|
assetPreCompiler.setup(app, main);
|
|
main = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public async stop(): Promise<void> {
|
|
for (const assetPreCompiler of this.assetPreCompilers) {
|
|
await assetPreCompiler.stop();
|
|
}
|
|
}
|
|
|
|
public async handleRoutes(router: Router): Promise<void> {
|
|
router.use((req, res, next) => {
|
|
res.locals.inlineAsset = (urlPath: string) => {
|
|
return this.publicAssetsCache.getOrFail(path.join(this.publicDir, 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 hookPreCompilers(): void {
|
|
for (const assetPreCompiler of this.assetPreCompilers) {
|
|
assetPreCompiler.onPreCompile(async watch => {
|
|
await this.assetCompiler.compile(watch);
|
|
});
|
|
assetPreCompiler.onInputChange(async restart => {
|
|
await this.assetCompiler.stopWatching(restart);
|
|
});
|
|
}
|
|
}
|
|
|
|
public async preCompileViews(watch: boolean): Promise<void> {
|
|
for (const viewEngine of this.assetPreCompilers) {
|
|
await viewEngine.preCompileAll(watch);
|
|
}
|
|
|
|
await this.assetCompiler.compile(watch);
|
|
|
|
if (watch) {
|
|
this.hookPreCompilers();
|
|
}
|
|
}
|
|
|
|
public getGlobals(): Globals {
|
|
return this.globals;
|
|
}
|
|
}
|