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

talismanjs

v0.9.1

Published

A streaming promise-aware templating engine for Node.js.

Downloads

44

Readme

Travis CI Coverage Status npm version

Talisman

Talisman is a logicless streaming templating system and language for Node.js, created by Digital Design Labs.

Installing

npm install talismanjs --save

Streams FTW

Streams are awesome, and so Talisman is built to be used as a streaming template system. This means Talisman renders templates to a stream, which you can then pipe to a writable stream, like process.stdout or http.ServerResponse.

Why Streaming?

Templating systems will often wait to compute last byte of a page before sending the first one. This manifests for users as a blank white screen, while they wait for our application to query the database and perform other required IO, before generating HTML for the page.

By contrast, Talisman sends as much data as it can as soon as it can; so the user gets something up on their screen quickly. This improves the perceived performance of your application, and also means their browser can start fetching external resources sooner. This reduces overall page load time, as JavaScript, CSS, and images can be downloaded on the client in parallel with the database work being done on the server.

Syntax

Talisman uses a simple syntax, based around two concepts: blocks and variables.

Variables

Talisman allows you to define variable placeholders which will be later populated with data. They are enclosed by {{double}} {{curly}} {{braces}}. Variables can be strings, streams, Buffers, or Promises for any of these.

// This will output:
// Hello World!
talisman.createFromString("Hello {{name}}!").then(view => {
    view.set({name: "World"})
        .toStream()
        .pipe(process.stdout);
});

Variables are automatically HTML escaped before they are displayed. You can request a variable be displayed raw by using a triple-brace instead of a double-brace, e.g. {{{varName}}}.

// This will output:
// Your name is <strong>World</strong>.
// The markup was &lt;strong>World&lt;/strong>.
talisman.createFromString("Your name is {{{name}}}.\nThe markup was {{name}}.").then(view => {
    view.set({name: "<strong>World</strong>"})
        .toStream()
        .pipe(process.stdout);
});

Blocks

A block defines a section of template text. Blocks can used as loops (by assigning iterators to them); as condtionals (by removing them when some condition is met) or simply as a way of defining a scope. A block is inherently none of these; its behaviour depends on how you treat it. Like HTML, blocks may nest, but may not overlap.

// This will output:
// <h1>Shopping List<h1>
// <ul>
// <li>Celery</li>
// <li>Apples</li>
// <li>Walnuts</li>
// <li>Grapes</li>
// </ul>
const template = "<h1>Shopping List</h1>\n<ul>\n"
    + "{#row}<li>{{item}}</li>\n{/row}"
    + "{#norows}<li>I'm afraid we're fresh out of waldorfs...</li>\n{/norows}"
    + "</ul>";

const data = [
    {item: "Celery"},
    {item: "Apples"},
    {item: "Walnuts"},
    {item: "Grapes"}
];

talisman.createFromString(template).then(view => {

    if (data.length > 0) {
        view.remove("norows").setIterator(data, "row");
    } else {
        view.remove("row");
    }

    view.toStream().pipe(process.stdout);
});

Other Markers

There are two other markers supported, though you are unlikely to need to use them.

  • {/* */} defines a comment. Anything placed between these markers will be removed by Talisman during rendering.
  • {{CDATA[ ]}} defines a block of non-template text. Anything between the square brackets will be ignored by Talisman, and rendered as-is.

Masks

Variables can have masks applied to them. Masks are small synchronous functions which transform the content in some way during rendering.

// This will output:
// <h1>Price List<h1>
// <ul>
// <li>Celery: $1.00</li>
// <li>Apples: $1.50</li>
// <li>Walnuts: $1.25</li>
// <li>Grapes: $0.75</li>
// </ul>
const template = "<h1>Price List</h1>\n<ul>\n"
    + "{#row}<li>{{item}}: {{price|format}}</li>\n{/row}"
    + "</ul>";

const data = [
    {item: "Celery", price: 1},
    {item: "Apples", price: 1.5},
    {item: "Walnuts", price: 1.25},
    {item: "Grapes", price: .75}
];

talisman.createFromString(template).then(view => {
    view.addMask("format", n => "$" + n.toFixed(2))
        .setIterator(data, "row")
        .toStream()
        .pipe(process.stdout);
});

Masks may also be chained, e.g. {{name|parseAsMarkdown|lowercase}}

Loading templates from files

In the examples so far, we have used createFromString(), but usually you would load templates files from disk.

talisman.create("template.html").then(view => {
   view.toStream().pipe(process.stdout);
});

You can also load templates into variables on another templates.

<!doctype html>
<html>
<!-- main.html -->
<title>{{pageTitle}}</title>
{{content}}
</html>
<!-- article.html -->
<h1>{{pageTitle}}</h1>
<h2>Posted: {{date|dateFormat}}</h2>
{{bodyContent|makeParagraphs}}
talisman.create("main.html").then(view => {
    // Second argument tells talisman which variable this content replaces
    return view.load("article.html", "content");
}).then(view => {
    view.set({pageTitle: "Talisman is awesome!"})
        .set({date: article.date, bodyContent: article.body}, "content")
        .addMask("dateFormat", dt => new Date(dt).toISOString())
        .addMask("makeParagraphs", text => "<p>" + text.replace(/\n/g, "</p>\n<p>") + "</p>\n")
        .toStream()
        .pipe(process.stdout);
});

This would render:

<!doctype html>
<html>
<!-- main.html -->
<title>Talisman is awesome!</title>
<!-- article.html -->
<h1>Talisman is awesome!</h1>
<h2>Posted: 2016-06-20T10:23:00.000Z</h2>
<p>My article body</p>
<p>Has multiple lines</p>


</html>

Minification

Minification is awesome. You can minify content from Talisman by piping the content through a transform stream.

const talisman = require("talismanjs");
const Minifier = require("minify-html-stream");

talisman.create("main.html").then(view => {
    view.toStream().pipe(new Minifier()).pipe(process.stdout);
});

The minify-html-stream project currently is basic and very cautious. You can make it better.

Simple Demos

git clone https://github.com/digitaldesignlabs/talisman.git
cd talisman
npm i
npm run-script demo console

There is also a browser-based demo

npm run-script demo browser

License

Published under the MIT License.