The @memberjunction/templates library provides a powerful templating engine built on Nunjucks with MemberJunction-specific extensions for dynamic content generation, AI-powered prompts, and recursive template embedding.
This package serves as the core templating engine for MemberJunction applications, offering:
npm install @memberjunction/templates
import { TemplateEngineServer } from '@memberjunction/templates';
import { UserInfo } from '@memberjunction/core';
// Get the template engine instance
const templateEngine = TemplateEngineServer.Instance;
// Configure the engine (usually done once at startup)
await templateEngine.Config(false, contextUser);
// Simple rendering without metadata
const result = await templateEngine.RenderTemplateSimple(
'Hello {{ name }}! Welcome to {{ company }}.',
{ name: 'John', company: 'Acme Corp' }
);
if (result.Success) {
console.log(result.Output); // "Hello John! Welcome to Acme Corp."
}
import { TemplateEngineServer } from '@memberjunction/templates';
import { TemplateContentEntity } from '@memberjunction/core-entities';
// Assume you have loaded a template entity and its content
const templateEntity = await templateEngine.GetTemplateByName('WelcomeEmail');
const templateContent = templateEntity.GetHighestPriorityContent();
// Render with validation
const result = await templateEngine.RenderTemplate(
templateEntity,
templateContent,
{
userName: 'John Doe',
accountType: 'Premium',
signupDate: new Date()
},
false // SkipValidation = false
);
if (!result.Success) {
console.error('Template rendering failed:', result.Message);
}
// In your template:
const templateText = `
Dear {{ userName }},
{% AIPrompt AIModel="gpt-4", AllowFormatting=false %}
Generate a personalized welcome message for a new {{ accountType }} customer
named {{ userName }} who just signed up for our service. Make it warm and
professional, highlighting the benefits of their account type.
{% endAIPrompt %}
Best regards,
The Team
`;
const result = await templateEngine.RenderTemplateSimple(templateText, {
userName: 'Sarah',
accountType: 'Enterprise'
});
// Main template
const mainTemplate = `
{% template "Header", type="HTML" %}
<div class="content">
<h1>Welcome {{ user.name }}</h1>
{% template "UserProfile", data={showDetails: true} %}
</div>
{% template "Footer" %}
`;
// The embedded templates will be loaded from the template metadata
// and rendered with the appropriate content type and data context
The main template engine class that handles all template operations.
Config(forceRefresh?: boolean, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<void>Configures the template engine and loads template metadata.
RenderTemplate(templateEntity: TemplateEntityExtended, templateContent: TemplateContentEntity, data: any, SkipValidation?: boolean): Promise<TemplateRenderResult>Renders a template using metadata entities with optional validation.
RenderTemplateSimple(templateText: string, data: any): Promise<TemplateRenderResult>Renders a template string without metadata integration.
GetTemplateByName(templateName: string): TemplateEntityExtended | nullRetrieves a template entity by its name.
GetTemplateByID(templateID: string): TemplateEntityExtended | nullRetrieves a template entity by its ID.
ClearTemplateCache(): voidClears the internal template cache.
interface TemplateRenderResult {
Success: boolean; // Whether rendering succeeded
Output: string; // The rendered output (null if failed)
Message?: string; // Error message (only when Success=false)
}
The template engine provides several filters for handling complex objects and JSON data:
dump (Nunjucks built-in)Converts any JavaScript object to a formatted JSON string.
{{ myObject | dump }} <!-- Pretty-printed with 2 spaces -->
{{ myObject | dump(4) }} <!-- Pretty-printed with 4 spaces -->
{{ myObject | dump(0) }} <!-- Compact single-line format -->
json (Custom filter)Similar to dump but with better error handling. Converts objects to JSON strings.
{{ userData | json }} <!-- Pretty-printed with 2 spaces (default) -->
{{ userData | json(4) }} <!-- Pretty-printed with 4 spaces -->
{{ userData | json(0) }} <!-- Compact format -->
If serialization fails, displays: [Error serializing to JSON: <error message>]
jsoninline (Custom filter)Converts objects to compact JSON strings (no formatting).
{{ userData | jsoninline }} <!-- Output: {"name":"John","age":30} -->
jsonparse (Custom filter)Parses JSON strings into JavaScript objects. Useful for processing JSON data stored as strings.
{{ '{"name":"John","age":30}' | jsonparse | json }}
<!-- First parses the string to object, then formats it -->
<!-- Access parsed object properties -->
{{ '{"name":"John","age":30}' | jsonparse | attr("name") }}
<!-- Output: John -->
Instead of getting [object Object] in your templates:
<!-- Problem: Shows [object Object] -->
<div>User Data: {{ userData }}</div>
<!-- Solutions: Use filters to display JSON -->
<div>User Data: {{ userData | dump }}</div>
<div>User Data: {{ userData | json }}</div>
<pre>{{ userData | json(2) }}</pre>
<!-- For debugging: Compact format -->
<script>
const data = {{ userData | jsoninline | safe }};
</script>
<!-- Parse a JSON string, then format it nicely -->
{{ jsonString | jsonparse | json(4) }}
<!-- Access nested properties after parsing -->
{{ responseData | jsonparse | attr("results") | json }}
<!-- Safe output without HTML escaping -->
{{ myData | json | safe }}
AIModel (optional): Specific AI model to use (e.g., "gpt-4", "claude-3")AllowFormatting (optional): Whether to allow formatted output (HTML, Markdown, etc.)type (optional): Specific content type to usedata (optional): Additional data to pass to the embedded templateTo create custom template extensions:
import { TemplateExtensionBase, RegisterClass } from '@memberjunction/templates';
@RegisterClass(TemplateExtensionBase, 'MyExtension')
export class MyExtension extends TemplateExtensionBase {
constructor(contextUser: UserInfo) {
super(contextUser);
this.tags = ['myTag'];
}
public parse(parser: Parser, nodes: Nodes, lexer: Lexer) {
const tok = parser.nextToken();
const params = parser.parseSignature(null, true);
parser.advanceAfterBlockEnd(tok.value);
const body = parser.parseUntilBlocks('endMyTag');
parser.advanceAfterBlockEnd();
return new nodes.CallExtensionAsync(this, 'run', params, [body]);
}
public run(context: Context, params: any, body: any, callBack: NunjucksCallback) {
// Your extension logic here
try {
const content = body();
// Process content...
callBack(null, processedContent);
} catch (error) {
callBack(error);
}
}
}
@memberjunction/core: Core MemberJunction functionality@memberjunction/templates-base-types: Base types and interfaces@memberjunction/ai: AI integration interfaces@memberjunction/aiengine: AI engine implementation@memberjunction/ai-groq: Groq AI provider@memberjunction/core-entities: Entity definitions@memberjunction/global: Global utilitiesnunjucks: Template engineThis package integrates seamlessly with other MemberJunction packages:
The template engine uses the MemberJunction configuration system. Key configuration options:
ClearTemplateCache() when templates are updatedAll rendering methods return a TemplateRenderResult object:
const result = await templateEngine.RenderTemplateSimple(template, data);
if (!result.Success) {
console.error('Rendering failed:', result.Message);
// Handle error appropriately
} else {
// Use result.Output
}
ISC - See LICENSE file for details.
For issues, questions, or contributions, please visit MemberJunction.com or contact the development team.