HoganJS - Documentation

What is Hogan.js?

Hogan.js is a lightweight, client-side JavaScript templating engine. It’s designed to be fast and efficient, focusing on compiling templates into JavaScript functions for optimal performance. This means rendering happens entirely within the browser, without requiring server-side processing of templates. Hogan.js uses a syntax similar to Mustache, making it familiar to developers already comfortable with that templating language. It’s particularly well-suited for applications that require high-performance template rendering, especially on mobile or less powerful devices.

Why use Hogan.js?

Hogan.js offers several compelling reasons for its use:

Key Features and Benefits

Comparison with other templating engines

Compared to other JavaScript templating engines like Handlebars, Mustache.js, and Underscore.js templates, Hogan.js often stands out due to its speed and small size. While Handlebars offers more advanced features (e.g., helpers and partials), it may be slower. Mustache.js shares the same syntax but might lack some performance optimizations found in Hogan.js. Underscore.js templates, while versatile, are generally not as specialized or performant for templating as Hogan.js. The choice ultimately depends on the specific needs of the project; if raw speed and minimal size are paramount, Hogan.js is a strong contender.

Setting up the Development Environment

Setting up Hogan.js is straightforward. You can include it in your project via:

  1. CDN: Include the Hogan.js library from a CDN like jsDelivr:

    <script src="https://cdn.jsdelivr.net/npm/hogan.js@latest"></script>
  2. NPM (Node Package Manager): If you’re using Node.js and npm, install it via:

    npm install hogan.js

    Then, require it in your JavaScript code using:

    const Hogan = require('hogan.js');
  3. Download: Download the Hogan.js library directly from the project repository and include it in your project.

After including Hogan.js, you’re ready to start compiling and rendering templates. Refer to the Hogan.js documentation for detailed instructions on template syntax and API usage.

Basic Usage and Syntax

Creating a Simple Template

The simplest Hogan.js template consists of plain text interspersed with Mustache tags. These tags are denoted by double curly braces { }. Anything outside these tags is rendered literally. Let’s create a template that displays a greeting:

<p>Hello, {{name}}!</p>

To render this template, you’ll first need to compile it using Hogan.js:

const Hogan = require('hogan.js'); // Or include via CDN as shown previously

const template = Hogan.compile('<p>Hello, {{name}}!</p>');
const output = template.render({ name: 'World' });
console.log(output); // Output: <p>Hello, World!</p>

This code first compiles the template string into a rendering function. Then, it renders the template with a data object containing the name variable.

Using Variables in Templates

You can access variables from your data object within the template using Mustache syntax. For example:

<h1>{{title}}</h1>
<p>{{description}}</p>
<p>Price: ${{price}}</p>

Given the data:

const data = {
  title: "My Awesome Product",
  description: "This is a great product!",
  price: 99.99
};

The rendered output would correctly incorporate these values.

Escaping HTML

Hogan.js automatically escapes HTML entities within variables to prevent cross-site scripting (XSS) vulnerabilities. If you need to render unescaped HTML, you can use the triple-mustache syntax {{ }}:

<div>
  Escaped: {{unsafeData}}
  <br>
  Unescaped: {{{unsafeData}}}
</div>

If unsafeData contains <script>alert('XSS')</script>, the first instance will be escaped, while the second will render the script, potentially causing an XSS attack. Use the triple-mustache with extreme caution and only when you are absolutely certain the data is safe.

Conditional Statements (if/else)

Hogan.js supports conditional rendering using sections. A section starts with {#condition} and ends with {/condition}. An {^condition} section is rendered only if the condition is falsy.

{{#showName}}
  <p>My name is {{name}}.</p>
{{/showName}}
{{^showName}}
  <p>Name is hidden.</p>
{{/showName}}

This will show “My name is…” only if showName is truthy in the data object.

Iteration (loops)

To iterate over arrays or objects, use sections with the array or object as the context.

{{#items}}
  <li>{{name}}</li>
{{/items}}

Where items is an array of objects, each with a name property. This will render a list item for each item in the array.

Partials

Partials allow you to reuse sections of your templates. While Hogan.js doesn’t have built-in partial support in the same way as Handlebars, you can achieve a similar effect by creating functions or using a pre-processing step to include external templates before compiling.

Including External Templates

To include external templates, you’ll need to load the template content (e.g., using AJAX) and then compile it using Hogan.js. You can then combine it with your main template or render it separately. There’s no direct “include” directive in Hogan.js’s core syntax; it’s a matter of handling the external template loading and integration in your application’s logic. For example:

fetch('my-external-template.html')
  .then(response => response.text())
  .then(templateText => {
    const externalTemplate = Hogan.compile(templateText);
    const externalData = { ... };
    const renderedExternal = externalTemplate.render(externalData);
    // ... integrate renderedExternal into your main template ...
  });

Remember to adjust this example to your specific fetching method and error handling.

Advanced Techniques

Working with Data Structures

Hogan.js handles various data structures effectively. You can seamlessly access properties from objects, iterate over arrays, and even traverse nested objects using dot notation. For instance:

const data = {
  user: {
    name: "John Doe",
    address: {
      street: "123 Main St",
      city: "Anytown"
    }
  }
};

const template = Hogan.compile("User: {{user.name}}, City: {{user.address.city}}");
const output = template.render(data);
console.log(output); // Output: User: John Doe, City: Anytown

Handling complex data structures requires understanding how Hogan.js resolves context. Remember that nested objects require proper dot notation within the template.

Custom Helpers and Functions

While Hogan.js doesn’t have a built-in helper system like Handlebars, you can create custom functions to extend its capabilities. These functions can be passed into the render function as part of the data context:

function formatDate(dateString) {
  // Your date formatting logic here
  return new Date(dateString).toLocaleDateString();
}

const data = {
  date: "2024-03-08",
  formatDate: formatDate
};

const template = Hogan.compile("Today's date: {{formatDate(date)}}");
const output = template.render(data);
console.log(output); // Output will be the formatted date

This example demonstrates how to define a formatDate helper and call it from within the template. The helper function itself is included in the data object.

Context Management

Understanding context is crucial for complex templates. The context refers to the current data object being used for rendering. Sections ({#section}...{{/section}}) create new contexts. When rendering nested sections, the inner section inherits the context from the outer section unless overridden. Careful structuring of your data and mindful use of sections are key to managing context effectively. If you need to explicitly change context, you may consider restructuring your data object or employing custom helpers.

Nested Partials

Hogan.js doesn’t directly support nested partials in the same way as other templating engines. To simulate nested partials, you need to load and render separate templates and integrate their output within your main template. This typically involves managing context carefully to pass data to the nested “partials.” A pre-processing step to assemble larger templates from smaller components can also streamline the process.

Template Inheritance

Template inheritance, in the sense of extending one template from another, isn’t a built-in feature of Hogan.js. Techniques like partial inclusion (as discussed earlier) combined with careful data management can approximate this behavior to some extent but will require more manual effort.

Error Handling and Debugging

Hogan.js provides some basic error handling. If there are issues with the template syntax or accessing data, you’ll usually see JavaScript errors in the browser console. Use your browser’s developer tools to inspect these errors. Carefully review your template syntax, data structure, and the calls to Hogan.compile and .render to diagnose the root cause. Using a linter can help catch potential template errors early in the development process.

Performance Optimization

Hogan.js is already known for its performance. However, you can further optimize your templates for speed:

Integration with Frameworks

Hogan.js with React

Integrating Hogan.js with React involves using it to render HTML strings within React components. Because React manages its own rendering process, you’ll typically use Hogan.js to generate the HTML that React then inserts into the DOM.

import React, { useState } from 'react';
import Hogan from 'hogan.js';

const MyComponent = () => {
  const [data, setData] = useState({ name: 'World' });
  const template = Hogan.compile('<p>Hello, {{name}}!</p>');

  return (
    <div>
      <p>Using Hogan.js within React</p>
      <div dangerouslySetInnerHTML={{ __html: template.render(data) }} />
      {/* Use dangerouslySetInnerHTML with caution! */}
      <button onClick={() => setData({ name: 'React' })}>
        Change Name
      </button>
    </div>
  );
};

export default MyComponent;

Important Note: The dangerouslySetInnerHTML prop should be used with extreme caution. Always ensure the data used to render the Hogan.js template is properly sanitized to prevent XSS vulnerabilities. Consider alternative approaches if possible that avoid direct innerHTML manipulation.

Hogan.js with Angular

In Angular, you can integrate Hogan.js within components by compiling the templates and injecting the rendered HTML. This often involves creating a custom pipe or service to encapsulate the Hogan.js functionality.

import { Component } from '@angular/core';
import * as Hogan from 'hogan.js';

@Component({
  selector: 'app-my-component',
  template: `
    <p>Using Hogan.js within Angular</p>
    <div [innerHTML]="renderedHtml"></div>
  `
})
export class MyComponent {
  renderedHtml: string = '';

  constructor() {
    const template = Hogan.compile('<p>Hello, {{name}}!</p>');
    this.renderedHtml = template.render({ name: 'Angular' });
  }
}

Similar to React, be mindful of security implications when using innerHTML. Sanitize your data thoroughly. A more robust approach might involve creating a custom Angular pipe to handle the template rendering and data sanitization in a cleaner, more Angular-idiomatic way.

Hogan.js with Vue.js

In Vue.js, you can leverage Hogan.js within a component’s template or by creating a custom directive. The approach using a custom directive offers better encapsulation and maintainability. This example uses the template option:

<template>
  <div>
    <p>Using Hogan.js within Vue.js</p>
    <div v-html="renderedHtml"></div>
  </div>
</template>

<script>
import Hogan from 'hogan.js';
export default {
  data() {
    return {
      renderedHtml: ''
    }
  },
  mounted() {
    const template = Hogan.compile('<p>Hello, {{name}}!</p>');
    this.renderedHtml = template.render({ name: 'Vue.js' });
  }
};
</script>

Again, v-html requires careful attention to data sanitization to prevent XSS. A custom directive could provide a more structured way to manage this process and improve code organization.

Hogan.js with other frameworks

The integration patterns illustrated above for React, Angular, and Vue.js generally apply to other JavaScript frameworks. The core idea is to use Hogan.js to pre-render the HTML and then inject it into the framework’s DOM using appropriate mechanisms (e.g., innerHTML, dedicated methods for updating content within the framework’s virtual DOM). Always prioritize security and use data sanitization techniques to prevent XSS vulnerabilities. Consider creating custom functions or components to encapsulate Hogan.js usage and improve code organization and maintainability within your chosen framework.

API Reference

Hogan.compile()

The Hogan.compile() method compiles a Hogan.js template string into a reusable template function. This function can then be used repeatedly to render the template with different data.

Syntax:

const templateFunction = Hogan.compile(templateString, [options]);

Return Value:

A template function that accepts a data object as an argument and returns the rendered HTML string.

Example:

const template = Hogan.compile('Hello, {{name}}!');
const output = template.render({ name: 'World' });
console.log(output); // Output: Hello, World!

Hogan.template()

The Hogan.template() method is a less frequently used alternative to Hogan.compile(). It’s primarily a convenience method and mostly used internally. It’s generally recommended to use Hogan.compile() for most scenarios. The functionality is very similar to Hogan.compile().

Hogan.render()

This method is deprecated in newer versions of Hogan.js. Instead of using Hogan.render(), you should compile the template using Hogan.compile() first and then call the .render() method on the resulting template function.

Template Methods

Once you’ve compiled a template using Hogan.compile(), the resulting function has the following key method:

Example:

const template = Hogan.compile('My name is {{name}} and I am {{age}} years old.');
const output = template.render({ name: 'Alice', age: 30 });
console.log(output); // Output: My name is Alice and I am 30 years old.

Helper Functions

Hogan.js doesn’t have built-in helper functions in the same way as some other templating engines. However, you can effectively create custom helper functions and pass them to the .render() method within the data object (as shown in the “Advanced Techniques” section). These helper functions extend the template’s capabilities by providing reusable logic for tasks like formatting dates, numbers or performing conditional logic within the template.

Error Objects

When errors occur during template compilation or rendering (e.g., syntax errors in the template or issues accessing data), Hogan.js will typically throw JavaScript errors. The specific error message will provide information about the nature of the problem. These errors will generally appear in your browser’s developer console (or through standard Node.js error handling if you’re using Hogan.js in a server-side context). There isn’t a specific, distinct “Hogan.js Error Object” class; standard JavaScript Error objects are used.

Best Practices and Common Pitfalls

Security Considerations

The most critical security concern when using Hogan.js (or any templating engine) is cross-site scripting (XSS). Never directly insert unsanitized user-provided data into your templates using the double-mustache syntax {...}. This can lead to vulnerabilities where malicious scripts are injected into your application.

Template Design Best Practices

Avoiding Common Mistakes

Troubleshooting Tips

Contributing to Hogan.js

Setting up the Development Environment

Contributing to Hogan.js typically involves working with its source code. To set up your development environment:

  1. Clone the repository: Start by forking the Hogan.js repository on GitHub and cloning your fork to your local machine:

    git clone <your-fork-url>
  2. Install dependencies: Navigate to the cloned directory and install the necessary dependencies using npm:

    npm install
  3. Run tests: Before making any changes, ensure the existing tests pass. This provides a baseline and helps to prevent regressions. The test command will vary depending on the project’s setup. Check the project’s README for specific instructions on running tests. It might involve commands like:

    npm test

Writing Tests

Hogan.js uses a testing framework (check the project’s README or package.json for details, likely something like Mocha or Jest). When contributing new features or fixing bugs, you should write comprehensive tests to ensure your changes work correctly and don’t introduce regressions. Tests should cover various scenarios, edge cases, and potential error conditions. The project will have established a style for how tests are written; follow that style and add tests in the appropriate location within the test suite.

Submitting Pull Requests

  1. Create a branch: Create a new branch for your changes:

    git checkout -b <your-branch-name>
  2. Make your changes: Implement your changes, ensuring that your code adheres to the project’s coding style guide (see below).

  3. Run tests: Run the tests again to ensure your changes haven’t broken anything.

  4. Commit your changes: Commit your changes with clear and concise messages:

    git add .
    git commit -m "Your descriptive commit message"
  5. Push your branch: Push your branch to your forked repository on GitHub:

    git push origin <your-branch-name>
  6. Create a pull request: On GitHub, create a pull request from your branch to the main branch of the original Hogan.js repository. Provide a detailed description of your changes, including the context, rationale, and any relevant information. Address any feedback from reviewers.

Coding Style Guide

Adhere to the coding style used consistently within the Hogan.js project. This typically involves:

The specific style guide details might be documented within the project (e.g., in a .editorconfig file, a contributing.md file, or within the project’s README). Carefully review these style guides before submitting your pull request. Consistency is key to maintainability and readability of the project’s codebase.