npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

node-red-contrib-nunjucks-templating

v1.0.10

Published

Nunjucks is a full featured templating engine for javascript. It is heavily inspired by jinja2.

Downloads

8

Readme

node-red-contrib-nunjucks-templating

A rich and powerful templating language for JavaScript right in Node-RED. For all of the Nunjucks template features checkout the official Nunjucks documentation

Macro usage

Options

You can define any valid Nunjucks options in the Node-RED settings.js file. nunjucks.options

Loading templates

Templates can be defined with the Nunjucks template nodes or be loaded from the file system using preconfigured folders for lookup. Loading is done automatically in the following order:

  1. Defined templates as nodes within the project that matches the name
  2. Looking for files in one of the configures folders
nunjucks: {
    folders: ["./my-templates", "./templates"],
}

This means you don't have to worry about where the template is defined while including it in your templates.

Template inheritance

extends is used to specify template inheritance. The specified template is used as a base template. See Template Inheritance. Macro usage

Custom filters

You can register filters using the global function nj.addFilter

// Value will be whatever is piped to the filter
function myFilter(value) {
    return `Foo: ${value}!!`
}

global.get('nj.addFilter')('myFilter', myFilter)

Now you can use it in all of your templates like: {{ 'bar' | foo }}

Output: Foo: bar!!

Passing functions

Functions can be passed like any other variables as context.

// context
msg.payload = {
    foo: 'bar',
    reverse: value => value.split('').reverse().join('')
}
{# template #}
{{ reverse(foo) }}

Output: rab

Global context

You can add global variables in multiple ways:

  1. Add a section to settings.js like this:
nunjucks: {
    global: {
        foo: 'bar',
        app: {
            name: 'My Awesome App'
        }
    }
}

Now you can access it anywhere like so: {{ app.name }} and {{ foo }}.

  1. Add it within a function node: global.get('nj.addGlobal')('myVar', 'Some value') Access it anywhere in any template or macro: {{ myVar }}

Snippets

Nunjucks snippets are provided for the Monaco editor only. Press ctrl+spacebar to list the available snippets.

  • asyncAll
  • asyncEach
  • block
  • call
  • elif
  • else
  • end
  • extends
  • filter
  • for
  • from
  • if
  • ife
  • ifel
  • import
  • include
  • macro
  • njk
  • or
  • pipe
  • raw
  • set
  • super
  • var
  • v{}

Macros

"macro allows you to define reusable chunks of content. It is similar to a function in a programming language."

Simple place your macros in a Nunjucks template node or in a file. The macros can be imported simply by there node name or filename. You can have one or more macros in one or more Nunjuck template nodes or files.

Defining macros

Macro definitions

Using macros

Macro usage

Other global functions

  • global.get("nj.addFilter");
  • global.get("nj.getFilter");
  • global.get("nj.addExtension");
  • global.get("nj.getExtension");
  • global.get("nj.hasExtension");
  • global.get("nj.removeExtension");
  • global.get("nj.getTemplate");
  • global.get("nj.addGlobal");
  • global.get("nj.getGlobal");
  • global.get("nj.renderString");

Examples

[{"id":"79b0f31660687179","type":"http response","z":"e78f061152fe82f8","name":"","statusCode":"","headers":{},"x":890,"y":120,"wires":[]},{"id":"f39790b7c1b32cbb","type":"nunjucks_render","z":"e78f061152fe82f8","template":"{% extends \"base.html\" %}\n\n{% import \"cards.html\" as cards %}\n\n{% block body %}\n{% call cards.card(card) %}\n  <form>\n    <div class=\"row\">\n      <div class=\"col\">\n        <input type=\"text\" class=\"form-control\" id=\"firstname\" name=\"firstName\" placeholder=\"Firstname\" value=\"{{ request.query.firstName }}\">\n      </div>\n      <div class=\"col\">\n        <input type=\"text\" class=\"form-control\" id=\"firstname\" name=\"lastName\" placeholder=\"Lastname\" value=\"{{ request.query.lastName }}\">\n      </div>\n    </div>\n\n    {# How to call your custom filters #}\n    <div class=\"my-4\">\n    {{ 'Hello' | myFilter }}\n    </div> \n\n    \n    <button type=\"submit\" class=\"btn btn-dark mt-3\">Give me a joke!</button>\n  </form>\n{% endcall %}\n{% endblock %}","x":760,"y":120,"wires":[["79b0f31660687179"]]},{"id":"45ba6e37f1581888","type":"function","z":"e78f061152fe82f8","name":"","func":"msg.payload = {\n    card: {\n        title: 'A Random Joke',\n        text: msg.payload.value.joke,\n        image: {\n            src: 'https://cdn.dribbble.com/users/1774513/screenshots/3726127/media/ef86424ae75426acfa624dfadcabda14.jpg?compress=1&resize=400x300'\n        },\n        buttons: [{\n            label: 'Another Joke',\n            href: '#',\n            className: 'btn btn-dark'\n        }]\n    }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":120,"wires":[["f39790b7c1b32cbb"]]},{"id":"fe5e86af251c9c02","type":"http request","z":"e78f061152fe82f8","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":470,"y":120,"wires":[["45ba6e37f1581888"]]},{"id":"f9cf633ec1b34528","type":"function","z":"e78f061152fe82f8","name":"payload","func":"global.get('nj.addGlobal')('request', msg.req)\n\nconst firstName = msg.req.query.firstName || 'Chuck'\nconst lastName = msg.req.query.lastName || 'Norris'\n\nmsg.method = 'GET'\nmsg.url = `http://api.icndb.com/jokes/random?firstName=${firstName}&lastName=${lastName}`\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":120,"wires":[["fe5e86af251c9c02"]]},{"id":"1fdca429c8c60b6f","type":"http in","z":"e78f061152fe82f8","name":"","url":"/example/joke","method":"get","upload":false,"swaggerDoc":"","x":150,"y":120,"wires":[["f9cf633ec1b34528"]]},{"id":"7c41b5ed52f53c40","type":"nunjucks","z":"e78f061152fe82f8","name":"cards.html","template":"{% macro card(card) %}\n<div class=\"card\">\n  {% if card.image %}\n    <img src=\"{{ card.image.src  }}\" class=\"card-img-top\" alt=\"{{ card.image.alt  }}\">\n  {% endif %}\n\n  <div class=\"card-body\">\n  {% if card.title %}\n    <h5 class=\"card-title\">{{ card.title }}</h5>\n  {% endif %}\n\n  {% if card.text %}\n    <p class=\"card-text\">{{ card.text }}</p>\n  {% endif %}\n\n  {{  caller() }}\n  </div>\n</div>\n{% endmacro %}","x":120,"y":320,"wires":[]},{"id":"3d4160d4d2e68eef","type":"nunjucks","z":"e78f061152fe82f8","name":"base.html","template":"<!doctype html>\n<html lang=\"en\">\n  <head>\n    <!-- Required meta tags -->\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n    <!-- Bootstrap CSS -->\n    <link href=\"https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3\" crossorigin=\"anonymous\">\n    \n    <title>{% block title %}Nunjucks Rocks!{% endblock %}</title>\n  </head>\n  <body>\n    {% include \"navbar.html\" %}\n    <div class=\"container\" style=\"margin-top: 80px;\">\n      {% block body %}\n        <h1>Hello, world!</h1>\n      {% endblock %}\n    </div>\n    <!-- Optional JavaScript; choose one of the two! -->\n\n    <script src=\"https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js\" integrity=\"sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p\" crossorigin=\"anonymous\"></script>\n    <script src=\"https://unpkg.com/[email protected]\" integrity=\"sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo\" crossorigin=\"anonymous\" defer></script>\n\n    {% block footer %}{% endblock %}\n  </body>\n</html>","x":120,"y":280,"wires":[]},{"id":"754c717efb65ad56","type":"nunjucks","z":"e78f061152fe82f8","name":"navbar.html","template":"<nav class=\"navbar navbar-light bg-light fixed-top\">\n  <div class=\"container-fluid\">\n    <a class=\"navbar-brand\" href=\"#\">{{ app.name }}</a>\n    <button class=\"navbar-toggler\" type=\"button\" data-bs-toggle=\"offcanvas\" data-bs-target=\"#offcanvasNavbar\" aria-controls=\"offcanvasNavbar\">\n      <span class=\"navbar-toggler-icon\"></span>\n    </button>\n    <div class=\"offcanvas offcanvas-end\" tabindex=\"-1\" id=\"offcanvasNavbar\" aria-labelledby=\"offcanvasNavbarLabel\">\n      <div class=\"offcanvas-header\">\n        <h5 class=\"offcanvas-title\" id=\"offcanvasNavbarLabel\">{{ foo.bar.baz }}</h5>\n        <button type=\"button\" class=\"btn-close text-reset\" data-bs-dismiss=\"offcanvas\" aria-label=\"Close\"></button>\n      </div>\n      <div class=\"offcanvas-body\">\n        <ul class=\"navbar-nav justify-content-end flex-grow-1 pe-3\">\n          {% for link in links %}\n            <li class=\"nav-item\">\n              <a {{ link.attributes | attr | safe }}>{{ link.label }}</a>\n            </li>\n          {% endfor %}\n        </ul>\n        <form class=\"d-flex\" action=\"/example/search\">\n          <input class=\"form-control me-2\" name=\"q\" type=\"search\" placeholder=\"Search\" aria-label=\"Search\" value=\"{{ request.query.q }}\">\n          <button class=\"btn btn-outline-success\" type=\"submit\">Search</button>\n        </form>\n      </div>\n    </div>\n  </div>\n</nav>","x":130,"y":240,"wires":[]},{"id":"b9a2ff8d07d15421","type":"http response","z":"e78f061152fe82f8","name":"","statusCode":"","headers":{},"x":610,"y":80,"wires":[]},{"id":"b3f6875fd13c8c43","type":"nunjucks_render","z":"e78f061152fe82f8","template":"{% extends \"base.html\" %}\n\n{% import \"cards.html\" as cards %}\n\n{% block body %}\n{% call cards.card(card) %}\n  \n{% endcall %}\n{% endblock %}","x":480,"y":80,"wires":[["b9a2ff8d07d15421"]]},{"id":"f9ba36f6f0a1145a","type":"function","z":"e78f061152fe82f8","name":"payload","func":"global.get('nj.addGlobal')('request', msg.req)\n\nmsg.payload = {\n    card: {\n        title: 'Search results',\n        text: `Searching for ${msg.req.query.q || ''}`,\n    }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":80,"wires":[["b3f6875fd13c8c43"]]},{"id":"599b7390c55080e2","type":"http in","z":"e78f061152fe82f8","name":"","url":"/example/search","method":"get","upload":false,"swaggerDoc":"","x":160,"y":80,"wires":[["f9ba36f6f0a1145a"]]},{"id":"4cf30c301712f9c8","type":"function","z":"e78f061152fe82f8","name":"Nunjucks Global Context","func":"const _context = {\n    app: {\n        name: 'Nunjucks for Node-RED'\n    },\n    links: [{\n        label: 'Random Joke',\n        attributes: {\n            'class': 'nav-link',\n            'href': '/example/joke'\n        }\n    }]\n}\n\nObject.entries(_context).forEach(([key, value]) => {\n    global.get('nj.addGlobal')(key, value)\n})\n\n","outputs":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":420,"wires":[]},{"id":"7f7ef0cd9623ebab","type":"inject","z":"e78f061152fe82f8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":420,"wires":[["4cf30c301712f9c8"]]},{"id":"2076215c31136a97","type":"function","z":"e78f061152fe82f8","name":"More Nunjucks Global Context","func":"const _context = {\n    foo: {\n        bar: {\n            baz: 'Hello Baz!'\n        }\n    }\n}\n\nObject.entries(_context).forEach(([key, value]) => {\n    global.get('nj.addGlobal')(key, value)\n})\n\n","outputs":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":460,"wires":[]},{"id":"ce4d3011a50a78ce","type":"inject","z":"e78f061152fe82f8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":460,"wires":[["2076215c31136a97"]]},{"id":"df10be42375fbc1e","type":"function","z":"e78f061152fe82f8","name":"Filters Example","func":"function myFilter(value) {\n    return `This is myFilter: ${value.toUpperCase()}!!!`\n}\n\nfunction attr(value) {\n    return Object.entries(value).reduce((prev, [key, value]) => {\n        prev.push(`${key}=\"${value}\"`)\n\n        return prev\n    }, []).join(' ')\n}\n\nglobal.get('nj.addFilter')('myFilter', myFilter)\nglobal.get('nj.addFilter')('attr', attr)","outputs":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":560,"wires":[]},{"id":"49bd7037b1599555","type":"inject","z":"e78f061152fe82f8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":560,"wires":[["df10be42375fbc1e"]]}]