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

@liquid-js/lit-ntml

v0.4.3

Published

Inspired by lit-html but for Node.js

Downloads

6

Readme

Version Downloads MIT License Code of Conduct

Build Status Dependency Status NSP Status codecov Coverage Status

Lightweight and modern templating for SSR in Node.js, inspired by lit-html.

Table of contents

Features

  • [x] await all tasks including Promises
  • [x] cacheStore: new QuickLru() to use a custom ES6 Map compliant cache instance
  • [x] cacheExpiry: 10e3 to set TTL of a cached item. Defaults to 1 year of TTL.
  • [x] minify: true to minify rendered HTML
  • [x] Compatible for ES Modules (import ntml from 'ntml') and CommonJS (const { ntml } = require('ntml');)
  • [x] Uses parse5 to parse HTML by default
  • [x] Uses pretty to prettify HTML by default
  • [x] Support HTML syntax highlighting + autocompletion with vscode-lit-html in JavaScript's template string.

Pre-requisite

How to use

Install

# Install via NPM
$ npm install lit-ntml

Enable syntax highlighting when writing HTML with template literal

Visual Studio Code

  1. Install vscode-lit-html extension.
  2. If the extension does not provide that syntax highlighting and autocompletion, try writing your templates in .jsx file (or .tsx file if you're TypeScript user) . That should work.

Code examples

Await all tasks (Promises, Functions, strings, etc)

/** Import project dependencies */
import ntml from 'lit-ntml';

/** Setting up */
const html = ntml();
const header = text => () => new Promise(yay => setTimeout(() => yay(`<div class="header">${text}</div>`), 3e3));
const content = text => async () => `<div class="content">${text}</div>`;
const someLoremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';

const rendered = await html`
  <html lang="en">
    <body>
      <style>
        body {
          padding: 0;
          margin: 0;
          font-size: 16px;
          font-family: 'sans-serif';
          box-sizing: border-box;
        }

        .header {
          background: #0070fb;
          color: #fff;
        }

        .content {
          background: #f5f5f5;
          color: #000;
        }
      </style>

      <main>
        <div>Hello, world! ${header('Hello, world!')} ${content('lorem ipsum')}</div>
        <div>${someLoremIpsum}</div>
      </main>
    </body>
  </html>
`;

console.log('#', rendered); /** <html lang="en>...</html> */

Use custom cache store + unique cache name to cache rendered HTML

/** Import project dependencies */
import ntml from 'lit-ntml';
import QuickLru from 'quick-lru';

/** Setting up */
const cacheStore = new QuickLru({ maxSize: 1000 }); // A cache instance must be ES6 Map compliant.
// const simpleCache = new Map(); // Simple cache using ES6 Map.
const html = ntml({
  cacheStore, // cacheStore: simpleCache,
  cacheName: 'main', // Gives the rendered HTML a unique name
  cacheExpiry: 10e3, // Set TTL of the rendered HTML. Defaults to 1 year.
});

const cacheAfterRendered = await html`
  <html lang="en">
    <body>
      <style>
        body {
          padding: 0;
          margin: 0;
          font-size: 16px;
          font-family: 'sans-serif';
          box-sizing: border-box;
        }

        .header {
          background: #0070fb;
          color: #fff;
        }

        .content {
          background: #f5f5f5;
          color: #000;
        }
      </style>

      <main>
        <div>Hello, world!</div>
        <div>This content will be cached!</div>
      </main>
    </body>
  </html>
`;

console.log('#', cacheAfterRendered); /** <html lang="en">...</html> */

Minify rendered HTML

/** Import project dependencies */
import ntml from 'lit-ntml';

/** Setting up */
const html = ntml({
  minify: true,
});

const minifyAfterRendered = await html`
  <html lang="en">
    <body>
      <style>
        body {
          padding: 0;
          margin: 0;
          font-size: 16px;
          font-family: 'sans-serif';
          box-sizing: border-box;
        }

        .header {
          background: #0070fb;
          color: #fff;
        }

        .content {
          background: #f5f5f5;
          color: #000;
        }
      </style>

      <main>
        <div>Hello, world!</div>
        <div>This content will be minified!</div>
      </main>
    </body>
  </html>
`;

console.log('#', minifyAfterRendered); /** <html lang="en"><body><style>...</style><main>...</main></body></html> */

Non-TypeScript users

For non-TypeScript users, here's the snippet:

const { ntml } = require('ntml');

(async () => {
  const html = ntml();

  const rendered = await html`<div>haha</div>`;

  console.log('#', rendered);
  /**
   * <div>haha</div>
   */
})();

API Reference

ntml(options)

  • options <Object> Optional configuration for the templating.
    • cacheStore <Map> Custom ES6 Map compliant cache instance to cache rendered HTML.
    • cacheName <string> Name of the rendered HTML that needs to be cached. Use a unique name for each rendered HTML to avoid cache conflict.
    • cacheExpiry <number> How long the rendered HTML should be cached for. Defaults to 1 year (12 * 30 * 24 * 3600).
    • minify <boolean> If true, minify rendered HTML. Defaults to false.
    • parseHtml <boolean> If true, parse the HTML with parse5, a HTML compliant parser for Node.js. Defaults to true.
    • parseHtmlFragment <boolean> If true, parse the HTML as fragment, i.e. don't wrap the result in <html><body> tags. Defaults to false.
  • returns: <Promise<string>> Promise which resolves with rendered HTML.

Caveat

Writing CSS styles outside of HTMLStyleElement can lead to unexpected parsing behavior, such as:

CSS styles outside of <style>

import ntml from 'lit-ntml';

const html = ntml();
const style = () => html`
  body {}

  div {}
`;

const main = () => html`
  <style>${style()}</style>
`;

/**
 * <!DOCTYPE>
 * <html> 
 *   <head>
 *     <style>
 *       <!DOCTYPE html>
 *       <html>
 *         <head>
 *           <style>
 *             body {}
 *
 *             div {}
 *           </style>
 *         </head>
 *       </html>
 *     </style>
 *   </head>
 * </html>
 * 
 */

It's clearly that the style tag element has been wrapped inside another html tag element. This is an unexpected behavior. However, it kind of makes sense as from the above scenario each of the new content is rendered separately with lit-ntml and the lit-ntml has no knowledge about what will be rendered next and before. To avoid such behavior, do one of the following:

  1. Avoid using lit-ntml to render the content of a HTML element

    const style = () => `
    body {}
    main {}
    `;
    const main = () => html`<style>${style}</style>`;
  2. Parse style as fragment

    const { ntml } = require('lit-ntml');
    const fhtml = ntml({
      parseHtmlFragment: true,
    });
    const style = () => fhtml`
    body {}
    main {}
    `;
    const main = () => html`<style>${style}</style>`;
  3. Wrap with any valid HTML element

    const style = () => html`
    <style>
      body {}
    
      main {}
    </style>`;

License

MIT License © Rong Sen Ng