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

small-tpl

v3.0.2

Published

A small lightweight but powerful template engine.

Downloads

15

Readme

small-tpl

A small lightweight but powerful template engine.

Install:npm install small-tpl or yarn add small-tpl

模板语法

<? 开始标签

?> 结束标签

each 遍历数组

endeach 结束遍历

echo 在JS脚本里输出数据

$data 模板内嵌变量,渲染模板的数据对象

$fn 模板内嵌变量,渲染模板的helper对象

$encodeChars 模板内嵌变量,输出内容时需要编码的字符,默认包含4个字符<>"'

$encode 模板内嵌函数,输出内容时对内容进行编码

$indent 模板内嵌函数,输出内容时对内容保持当前缩进量

$item 模板内嵌变量,遍历数组时指向当前数组元素

$i 模板内嵌变量,遍历数组时指向当前数组元素的下标

$count 模板内嵌变量,遍历数组时指向当前数组的长度

= 在“each”外时输出$data对象的属性,在“each”里时输出$item对象的属性;属性值为null或undefined时输出空字符串

=: 与“=”相似,区别在于会用$encode编码内容

=] 与“=”相似,区别在于会用$indent保持当前缩进量

+ 直接字符串连接整个语句块,不做任何处理

API

  • compile(template, [options])

    编译模板字符串为渲染函数。

    options有3个选项:openTag自定义开始标签;closeTag自定义结束标签;uglify是否去除HTML里无用的空白字符,默认true去除。

  • setTag(openTag, closeTag)

    全局设置开始标签和结束标签。

Demo

Hello world

const { compile } = require('small-tpl')

// for pure Object
const render = compile('<?= hello ?>, <?= name ?>!')
render({hello: 'Hello', name: 'girl'})
// => Hello, girl!

// for Array
const render = compile('<?+ $data[0] ?>, <?+ $data[1] ?>!')
render(['Hello', 'girl'])
// => Hello, girl!

标签内可以使用原生JS语法:

<div>
<? if ($data.someProp) { ?>
  <h1>哈哈哈</h1>
<? } else { ?>
  <i>嘿嘿嘿</i>
<? } ?>
</div>

JS代码内可以使用echo语句,上面的代码等同于:

<div>
<?
  if ($data.someProp) {
    echo '<h1>哈哈哈</h1>' // 也可以写成 echo('<h1>哈哈哈</h1>')
  } else {
    echo '<i>嘿嘿嘿</i>'
  }
?>
</div>

三目运算:

<h1><?+ ($data.someProp ? '哈哈哈' : '嘿嘿嘿') ?></h1>

遍历数组:

<h1><?= title ?></h1> <!-- 输出 $data.title -->
<ul>
<? each $data.someList ?>
  <li>
    <?= title ?> <!-- 输出 someList 里每一项的 title,即 $item.title -->
  <? if ($item.subTitle) { ?> <!-- $item 指向 someList 的元素 -->
    <span class="sub-title">
      <?+ $fn.encodeXssChar($item.subTitle) ?>
    </span>
  <? } ?>
  </li>
<? endeach ?>
</ul>

特别注意eachendeach只能放在独立的<? ?>标签内,不能跟其他语句同处一个标签内。除了下面这种情况。

在上面的模板中,如果不确定someList这个属性是否存在,可以像下面这样:

<? each $data.someList || [] ?>
  TODO
<? endeach ?>

对输出内容进行编码,预防XSS攻击:

const render = compile('<?=: content ?>')
render({content: '<script>alert("1")</script>'})
// => &lt;script&gt;alert(&quot;1&quot;)&lt;/script&gt;
// 即可在页面上正常显示:<script>alert("1")</script>

扩充默认的$encodeChars,扩充只影响当前模板:

const render = compile(`<? $encodeChars['b'] = 'B' ?><?=: content ?>`)
render({content: 'abc'})
// => aBc

手动调用$encode函数:

const render = compile(`<?+ $encode('Encode: ' + $data.content) ?>`)
render({content: '<b>abc</b>'})
// => Encode: &lt;b&gt;abc&lt;/b&gt;
// 页面上正常显示:Encode: <b>abc</b>

Deep

compile('<p><?= hello ?>, <?= name ?>!</p>')

// 模板将被编译为如下函数
function anonymous($data, $fn) {
  'use strict';
  var $_get = function (data, key) {
    return data[key] || (data[key] == null ? '' : data[key]);
  };
  var echo = '<p>'+ $_get($data, 'hello')+ ', '+ $_get($data, 'name')+ '!</p>';
  return echo
}

compile(`
  <h1><?= title ?></h1>
  <ul>
  <? each $data.someList ?>
    <li>
      <?= title ?>
    </li>
  <? endeach ?>
  </ul>
`)

// 模板将被编译为如下函数
function anonymous($data, $fn) {
  'use strict';
  var $_get = function (data, key) {
    return data[key] || (data[key] == null ? '' : data[key]);
  };
  var echo = '<h1>'+ $_get($data, 'title')+ '</h1><ul>';
  ~function () {
    var $_list = $data.someList, $count = $_list.length, $i = 0, $item;
    for (; $i < $count; $i++) {
      $item = $_list[$i];
      echo += '<li>'+ $_get($item, 'title')+ '</li>'
    }
  }();
  echo += '</ul>';
  return echo
}

compile('<p><?=: content ?></p>')

// 模板将被编译为如下函数
function anonymous($data, $fn) {
  'use strict';
  var $_get = function (data, key) {
    return data[key] || (data[key] == null ? '' : data[key]);
  };
  var $encodeChars = {
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;'
  };
  var $encode = function (s) {
    if (typeof s === 'string') {
      var res = '', i = 0, l = s.length;
      for (; i < l; i++) {
        res += $encodeChars[s[i]] || s[i];
      }
      return res;
    }
    return s == null ? '' : s;
  };
  var echo = '<p>'+ $encode($_get($data, 'content'))+ '</p>';
  return echo
}