Janja is designed for high performance template rendering. This guide provides best practices and techniques to optimize your template rendering performance.
- Compilation: One-time cost to parse and compile the template into executable code
- Rendering: Repeated cost of executing the compiled template with data
Best Practice: Enable caching to avoid re-compiling the same template multiple times.
import { render } from 'janja';
const result = await render(template, data, {
cache: {
enabled: true,
maxSize: 1000,
ttl: 3600,
},
});For production deployments, pre-compile your templates to avoid compilation overhead at runtime.
# Pre-compile templates
janja compile ./templates ./dist/templates --recursiveEnable caching in production to store compiled templates:
const options = {
cache: {
enabled: true,
maxSize: 1000, // Maximum number of cached templates
ttl: 3600, // Time-to-live in seconds
},
};Complex expressions in templates can slow down rendering. Pre-compute values in your data:
Bad:
{{= (a + b) * (c - d) / e }}
Good:
const data = { result: (a + b) * (c - d) / e };{{= result }}
Filter chains add overhead. Use them efficiently:
Bad:
{{= text | upper | lower | upper | truncate(100) }}
Good:
{{= text | truncate(100) | upper }}
Large loops can impact performance. Consider pagination or limiting data:
{{ for item of items | slice(0, 50) }}
{{= item.name }}
{{ endfor }}
Deeply nested templates are harder to optimize:
Bad:
{{ for user of users }}
{{ for post of user.posts }}
{{ for comment of post.comments }}
{{= comment.text }}
{{ endfor }}
{{ endfor }}
{{ endfor }}
Good: Pre-process data or use component-based approach.
Avoid template duplication with block inheritance:
<!-- base.janja -->
{{ block content }}{{ endblock }}
<!-- page.janja -->
{{ include "base.janja" }}
{{ block content }}Page content{{ endblock }}
- Template:
Hello {{ name }}! - Data:
{ name: 'World' } - Performance: < 1ms per render
- Template with loops, filters, conditionals
- Data: Array of 100 items
- Performance: < 10ms per render
- Simple string: < 0.01ms per escape
- String with special chars: < 0.02ms per escape
- Long string (2000+ chars): < 0.05ms per escape
Run the benchmark suite to measure performance:
pnpm --filter janja test benchmarksThe CI workflow automatically runs benchmarks on every PR and alerts if performance degrades by more than 200%.
- Simple template render: < 1ms
- Complex template render: < 10ms
- Template compilation: < 5ms (first time)
- Cached template render: < 0.5ms
- Escape operation: < 0.02ms
- Filter application: < 0.05ms
Cause: Template compilation overhead
Solution: Enable caching or use pre-compilation
Cause: Large cache size or large data objects
Solution: Reduce cache size or implement data pagination
Cause: Cache not configured properly or memory leak
Solution: Check cache configuration and TTL settings
Cause: Complex template with many operations
Solution: Split into smaller components or pre-process data
For maximum performance, create custom compilers for specific use cases:
const options = {
compilers: {
CUSTOM: async (node, compiler) => {
// Optimized compilation for custom nodes
},
},
};For very large templates, consider streaming the output:
import { Renderer } from 'janja';
const renderer = new Renderer(options);
const stream = await renderer.renderStream(template, data);Use browser dev tools or Node.js profiler to identify bottlenecks:
node --prof your-app.js
node --prof-process isolate-*.log > profile.txtBy following these optimization techniques and best practices, you can achieve excellent performance with Janja template rendering. Always measure performance in your specific use case and optimize based on actual bottlenecks.