Handlebars.js

repository·master·Indexed 12 days ago

https://github.com/handlebars-lang/handlebars.js

A powerful, semantic templating engine largely compatible with Mustache. It supports precompilation for performance, custom helpers, block expressions, and nested paths. Version 5.0.0-alpha.1 is designed for ECMAScript 2020 environments including Node.js and modern browsers.

Tokens
11.5K
Snippets
36
Records
51
Agent score
97%

What's inside Handlebars

  1. Traverse and mutate the AST with Handlebars.Visitor

    master

    The Handlebars.Visitor class allows you to traverse the AST. By extending it, you can override specific node handler methods to inspect or modify the tree.

    Non-mutation mode

    In the default mode, you override methods (like PartialStatement) to perform actions as the visitor traverses the tree. The visitor maintains a parents array containing the current node's ancestors, with the most recent parent listed first.

    Mutation mode

    By setting the mutating field to true, you can modify the AST during traversal. Handler methods in mutation mode return:

    • A valid AST node: Replaces the current node with the returned node.
    • false: Removes the current node from the tree.
    • undefined: Leaves the node unchanged.

    When implementing mutation mode, use the acceptKey, acceptRequired, and acceptArray helpers to manage conditional overwrites and sanity checks.

    var Visitor = Handlebars.Visitor;
    
    function ImportScanner() {
      this.partials = [];
    }
    ImportScanner.prototype = new Visitor();
    
    // Override specific node handlers
    ImportScanner.prototype.PartialStatement = function (partial) {
      this.partials.push({ request: partial.name.original });
    
      // Call the prototype to continue traversal
      Visitor.prototype.PartialStatement.call(this, partial);
    };
    
    var scanner = new ImportScanner();
    scanner.accept(ast);
  2. Understand Handlebars vs Mustache compatibility

    master

    While Handlebars is largely compatible with Mustache, there are key differences to be aware of:

    Features added by Handlebars

    • Nested Paths: Accessing deeply nested data.
    • Helpers: Explicit pieces of code for custom logic.
    • Block Expressions: Syntax for sections (like each or with).
    • Literal Values: Literal segments in templates.
    • Delimited Comments: Template comments.

    Breaking differences from Mustache

    • Recursive Lookup: Handlebars does not perform recursive lookup by default. You must set the compile-time compat flag to enable it, though this incurs a performance cost.
    • Lambdas: Mustache-style lambdas are not supported; Handlebars uses its own lambda resolution based on helpers.
    • Syntax Strictness: Handlebars does not allow spaces between the opening {{ and command characters like #, /, or >. For example, {{> partial }} is valid, but {{ > partial }} is not.
    • Delimiters: Alternative delimiters are not supported.
  3. Precompile templates for faster startup

    master
    Handlebars allows you to precompile templates into JavaScript code. This approach improves startup performance by avoiding the compilation step at runtime. For detailed implementation guides, refer to the official precompilation documentation.
  4. What are Decorators in Handlebars.js

    master

    Decorators are a mechanism used to annotate blocks with metadata or wrap them in additional functionality before execution. They are useful for communicating with a containing helper or setting up specific system states before a block runs.

    Note: Decorators are currently deprecated. The community is discussing the future of this feature in issue #1574.

  5. Include script tags inside Handlebars templates

    master

    If you are loading templates via an inlined <script type="text/x-handlebars"> tag, including a <script> tag inside the template can cause browser parser errors. To prevent this, break up the inner script tag using an empty Handlebars comment {{!}} to hide the characters from the HTML parser.

    <script type="text/x-handlebars">
      foo
      <scr{{!}}ipt src="bar"></scr{{!}}ipt>
    </script>
  6. Understand the HelperDelegate signature

    master

    A helper function receives the current context and arguments. For block helpers, the options object provides access to the block's lifecycle.

    HelperDelegate signature:

    (context?: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any, arg5?: any, options?: HelperOptions) => any

    HelperOptions contains:

    • fn: TemplateDelegate (the block content)
    • inverse: TemplateDelegate (the {{else}} block content)
    • hash: Record<string, any> (arguments passed via hash, e.g., {{helper key='val'}})
    • data: any
  7. Use the Handlebars CLI to precompile templates

    master

    The Handlebars CLI allows you to precompile Handlebars templates into JavaScript functions. You can pass individual template files or entire directories as arguments.

    Basic Usage: handlebars [template|directory]... [options]

    Common workflows include:

    • Compiling a single file to an output file using -f or --output.
    • Compiling a directory of templates.
    • Using -i or --string to pass a template string directly, or using -i - to read from stdin.
    • Using --partial (-p) when compiling a template intended to be used as a partial.
    handlebars my-template.handlebars -f my-template.js
  8. Use the Handlebars runtime-only build

    master

    The handlebars.runtime.js build is intended for environments where the template compiler is not available (e.g., client-side browsers). It provides the necessary logic to execute precompiled templates.

    When using this build, you cannot compile raw Handlebars strings into templates; you must instead provide the precompiled template specification to the hb.template() method.

    import Handlebars from 'handlebars/runtime';
    
    // Assuming 'spec' is a precompiled template object generated by the compiler
    const template = Handlebars.template(spec);
    const output = template({ key: 'value' });
  9. Avoid Content Security Policy (CSP) issues

    master

    When compiling templates at runtime, Handlebars generates dynamic JavaScript functions. This can trigger violations in environments with strict Content Security Policies. To resolve this, you should either:

    1. Precompile your templates: This is the recommended approach as it avoids dynamic function generation.
    2. Enable unsafe-eval: If you must generate templates at runtime, your CSP must allow the unsafe-eval policy.
  10. Verify Handlebars version compatibility for precompiled templates

    master

    Precompiled templates require a matching version of the Handlebars runtime on the client side. If you encounter errors like undefined is not a function, verify that the compiler version and the client runtime version are identical.

    To check the compiler version, use the CLI:

    handlebars --version

    To check the client runtime version, use:

    console.log(Handlebars.VERSION);
    handlebars --version
    console.log(Handlebars.VERSION);
  11. Register and use Decorators

    master

    Decorators are managed using registerDecorators and unregisterDecorators. Once registered, they can be invoked in templates using a special asterisk syntax.

    There are two primary syntaxes for referencing a decorator by its friendly name:

    1. {{* decorator}}: For single-line or non-block usage.
    2. {{#* decorator}}{/decorator}}: For block-based usage.

    These syntaxes follow standard Mustache argument and whitespace rules.