Template
Contract
@modularityjs/template defines the abstract TemplateEngine:
abstract class TemplateEngine {
abstract render(
name: string,
data?: Record<string, unknown>,
): Promise<string>;
}The name parameter identifies the template (e.g. 'welcome-email'). The data parameter provides variables available inside the template.
@Module({
name: 'template',
contracts: [TemplateEngine, TemplateHelpersPool],
})
class TemplateModule {}TemplateHelpersPool is a cross-engine helper registry — see Helpers below.
Drivers
Handlebars (@modularityjs/template-handlebars)
File-based Handlebars templates with compiled template caching. Templates are .hbs files loaded from a configured directory.
import { TemplateModule } from '@modularityjs/template';
import { TemplateHandlebarsModule } from '@modularityjs/template-handlebars';
const modules = [
TemplateModule,
TemplateHandlebarsModule.forRoot({
directory: './templates',
}),
];Given directory: './templates', calling render('welcome-email', data) reads ./templates/welcome-email.hbs, compiles it with Handlebars, caches the compiled template, and returns the rendered string. Subsequent calls to the same template name skip the filesystem read and compilation.
Configuration
| Option | Default | Description |
|---|---|---|
directory | (required) | Path to the directory of .hbs files |
cacheCapacity | 200 | Maximum number of compiled templates to keep in the LRU cache |
EJS (@modularityjs/template-ejs)
File-based EJS templates with LRU compiled template caching. Templates are .ejs files loaded from a configured directory.
import { TemplateModule } from '@modularityjs/template';
import { TemplateEjsModule } from '@modularityjs/template-ejs';
const modules = [
TemplateModule,
TemplateEjsModule.forRoot({
directory: './templates',
}),
];Given directory: './templates', calling render('welcome-email', data) reads ./templates/welcome-email.ejs, compiles it with EJS, caches the compiled function, and returns the rendered string.
Configuration
| Option | Default | Description |
|---|---|---|
directory | (required) | Path to the directory of .ejs files |
cacheCapacity | 200 | Maximum number of compiled templates to keep in the LRU cache |
Usage
Rendering an email
import { Inject, Injectable } from '@modularityjs/di';
import { TemplateEngine } from '@modularityjs/template';
@Injectable()
class EmailService {
constructor(
@Inject(TemplateEngine) private readonly templates: TemplateEngine,
) {}
async sendWelcome(user: { name: string; email: string }): Promise<void> {
const html = await this.templates.render('welcome-email', {
name: user.name,
});
await this.sendMail(user.email, 'Welcome!', html);
}
private async sendMail(
to: string,
subject: string,
html: string,
): Promise<void> {
// ...
}
}With templates/welcome-email.hbs:
Rendering an HTML page in a controller
import { Inject } from '@modularityjs/di';
import { Controller, Get, SetHeader } from '@modularityjs/http';
import { TemplateEngine } from '@modularityjs/template';
@Controller('/pages')
class PagesController {
constructor(
@Inject(TemplateEngine) private readonly templates: TemplateEngine,
) {}
@Get('/about')
@SetHeader('Content-Type', 'text/html')
async about() {
return this.templates.render('about', {
title: 'About Us',
year: new Date().getFullYear(),
});
}
}Helpers
Packages contribute reusable template helpers via TemplateHelpersPool. Each entry is an @Injectable() subclass of TemplateHelper with a name and an apply(...args) method:
import { Injectable } from '@modularityjs/di';
import { Module } from '@modularityjs/modularity';
import { TemplateHelper, TemplateHelpersPool } from '@modularityjs/template';
@Injectable()
class FormatDateHelper extends TemplateHelper {
readonly name = 'formatDate';
apply(input: unknown): string {
return new Date(String(input)).toLocaleDateString();
}
}
@Module({
name: 'my-helpers',
providers: [FormatDateHelper],
pools: [
{
pool: TemplateHelpersPool,
key: 'format-date',
useClass: FormatDateHelper,
},
],
})
class MyHelpersModule {}Templates then call the helper by name:
The Handlebars driver reads the pool in afterLoad and registers each entry via Handlebars.registerHelper. Drivers without first-class helper registration may ignore the pool — register helpers as render-data context values instead.
The asset URL helper () is provided by @modularityjs/template-assets — wire TemplateAssetsModule to enable it.