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

masquerade-html-lib

v0.3.12

Published

Server-rendered front-end template based on html extension tags

Downloads

9

Readme

渲染动态 html 页面

masquerade version: 0.3.8 edit: 2017.3.17

  • 通过插件扩展功能
  • 全程使用 Buffer 且尽量减少内存复制
  • 静态文件最后修改日期缓存策略
  • 自定义文件获取器, 可以挂到自定义的网络文件系统

Install

npm install masquerade-html-lib --save

Demo

快速启动服务

var mas = require('masquerade-html-lib');
var ret = mas.listen(80);

使用原生 http api:

var http = require('http');
var mas = require('masquerade-html-lib');
var mid = mas.mid('/www');
http.createServer(mid).listen(80);

与 mixer-lib 结合使用的方法:

var mixer = require('mixer-lib');
var mas = require('masquerade-html-lib');

mixer.create_http_mix_server({
    whenLoad: function(app_pool) {
        mas(app_pool, '/');
    }
});

HTTP 代理

当请求一个路径为目录时, 将尝试搜索默认主页文件 (在配置文件 default_page 配置中), 如果 中间有代理层, 将跳转到错误的地址, 此时设置 http 头域 proxy-original-url 为代理的原 始地址可以解决这个跳转错误.

Html 模板说明

  • 配置文件中 masquerade.extname 指定的的扩展名称的文件作为模板进行解析
  • 模板中 ### A ### 的部分是 bird 表达式, 见下文
  • 标签分为三种:
      1. 普通 html 标签, 不做特殊处理, 可以在标签体或属性中嵌入 bird 表达式
      1. 系统标签, 这些标签有特殊的功能, 渲染结果也不是直观的, 具体见 [Html 模板特殊标签] 一节
      1. 用户自定义标签, 这些标签使用 HTML 语法写成, 放在 [/private/tag] 目录中, 见下文

bird 表达式

###A.b###

  • 表达式以 ### 作为开始, 以 ### 作为结束
  • 表达式中只支持从 '.' 运算符, 变量之间允许有空格
  • 表达式只在普通文本中生效, 特殊标签的属性, 有不同的行为, 具体查看特殊标签的定义
  • 上下文即 context 对象, 这个对象不需要在表达式中写出, 上下文参考 [上下文中的对象] 一节.
  • 在一些特殊标签中, ### 这个符号是不需要写出的, 具体查看特殊标签的定义

用户自定义 HTML 标签库

允许利用 HTML 语法定义程序库, 使定义和使用更符合前端开发者的习惯; 这些标签库都是由服务端渲染的.

自定义标签在 /private/tag 目录, 文件名(不含扩展名, 比如 user.htm 即 user 标签) 即为标签的名称; 这些标签直接在模板中使用, 引用的方式: <user v='100'/>; 引用标签的的时候, 参数都会作为上下文变量传递给此标签定义部分; 上例中, 在 user.htm 文件里可以使用变量 v.

当调用自定义 HTML 标签且含有标签体时, 标签体中的内容并不会自动渲染, 必须使用 <pit/> 这个标签来渲染调用时的标签体, 标签体中也是模板语法.

如果有子目录则使用 html 名字空间来 : 引用子目录中的标签, 子目录的子目录使用 '-' 分割, 所以目录名称不要有 :- 符号.

引用自定义标签的例子, 在文件中定义的位置 ==> 模板中引用的语法

  • 例: [/private/tag]/tag1.html ==> <tag1 />
  • 例: [/private/tag]/dir1/tag2.html ==> <dir1:tag2 />
  • 例: [/private/tag]/dir1/dir2/tag3.html ==> <dir1-dir2:tag3 />

Html 模板系统标签

  • 系统标签是系统定义的, 或通过安装插件得到的功能.
  • 没有标签体的标签, 即使声明了标签体也不会被渲染.
  • 标签属性中不能有表达式, 表达式的使用要遵从标签的说明.
  • 属性的解析方法, 不同的标签定义不同, 下文中的变量意思是从上下文对象中取一个属性作为当前值
  • 可选的属性使用 [] 符号标注, 实际使用时不要有 [] 符号
  • 每个系统标签的属性功能不同, 特别注意一些标签的属性默认支持表达式.

slice 切片

<slice ref='name' attr1='' attr2='' noerror='1' [exp='true'] />
<slice define='name' noerror='1' [exp='true']>BODY</slice>

  • 创建一个切片, 如果有 ref 属性, 则不能有标签体, 用于引用一个切片到当前位置 并且 扩展属性都会传入上下文供给 的 body 中使用 如果有 define 属性, 则必须有标签体, 切片只有在被引用的时候才会渲染 如果定义 noerror 则不会因为错误抛出异常 (如无效的引用), 否则不要定义!

include 包含

<include src="/page/a.html" [private="false"] [exp='false']/>

  • 包含一个静态文件, 如果以 '/' 开始文件层级默认相对于 public 目录, 如果以 './' 或非 '/' 开始则相对于当前文件目录. 如果 private="true" 则相对于 /private/include 目录, 忽略相对路径,

for 循环

<for from="array" save='b' index='i'> ###b### ###i###</for>
<for from="object" save='c' index='i'> ###c### ###i###</for>

  • 循环渲染 标签体 每次循环的变量都保存在 save 指定的变量中, 之后可以通过表达式取出 每次循环的索引保存在 index 指定的变量中

if 判断

<if var="c" [not='true']></if>

  • 如果条件为 true(默认) 则渲染标签体, 如果 not='true' 则条件取反, var 支持复杂表达式.

else

<else></else>

  • 如果 else 之配对的 if 被渲染则 else 不会渲染, 反之则渲染; else 必须与 if 配对且唯一配对, 未配对的 else 永远不被渲染;

api 发出 HTTP 请求

<api url='http://url/?parm' to='api1ret' [type='json/txt'] [method='get/post'] [exp='boolean'] [timeout='5']/>

  • 请求一个 API, method 指定方法 (默认get), 使用 type 指定的类型解析数据 (默认为 json), 并把结果保存在 to 指定的变量中; exp=true 则 url 中允许表达式, 如果请求出错在 to 变量上绑定一个 Error 对象; timeout 超时后发出异常, 单位 秒.

create 创建对象

<create to='objname' varname1-s='string' varname2-e='express' varname3-n='9' />

  • 创建一个对象 Object, 放入上下文的 to 指定的变量中 参数的说明: 由 nnn-T 形成的参数列表 nnn 指定一个属性, T 指定数据类型 T 的有效类型: 's': 字符串, 'e':表达式, 'i':整数, 'f':浮点数 如果不指定类型, 默认是字符串, 如果 to 指定的变量以及存在则什么都不做

set 设置变量, 或设置对象属性

<set to='varname' [attr='attrname'] value='abc' [exp='false']/>

  • 设置 to 指定的属性的 attr 值为 value, 如果 attr 未设置, 则直接修改 to 指定的变量的值 如果 exp==true (默认false), 则从上下文中取数据 修改系统变量会抛出异常

del 删除变量/对象

<del to='varname'/>

  • 删除上下文中的变量, 不会抛出异常, 但无法删除一些系统变量

script 脚本

<script [src='/script1.js'] [runat='server/client']/>

  • 如果 runat==server (默认是client) 设置了 src 属性则运行一个服务端脚本文件, 相对于 /private/script 目录, 否则不设置 src 可以直接写服务端脚本. 脚本运行在沙箱中, 能力受限;

  • 脚本中可用的变量:

    • query : Object, 请求页面时设置的 GET 参数.
    • module : Object, 与 nodejs 中的 module 定义相同, 用于分辨引用时模块.
    • module.exports : 像 nodejs 一样导出一个模块. 另一个模块可以用 require() 来引入.
  • 可用函数:

    • val(name [, value]), name 是变量名, 设置 value 则 set 变量, 否则 get 变量.
    • end(), 脚本运行完成, 脚本中必须调用这个方法, 否则请求不返回.
    • write(Object), 写出字符串到页面, 必须在页面渲染完成前调用, (不能在 setTimeout 中调用).
    • require(name, cb), 引用一个模块, 被引用模块在 /private/script 目录中存放.
    • console.log(), 在控制台打印消息.

pit 渲染标签体

<pit/>

  • 在用户自定义标签库中, 渲染调用这个标签库时的标签体

never 不会被渲染

<never></never>

  • 不会进行任何处理的标签, 用于写注释

stop 停止渲染

<stop/>

  • 无条件停止渲染.

[未完成]

<error msg=''/>

  • 抛出一个异常, 并停止渲染

<log msg='' [lv='info']/>

  • 记录日志, lv == info (默认), lv 可以是 debug/warn/error/info

<plain src='/index.html'/>

  • 将文件作为普通文本输出到浏览器

Api

var mas = require('masquerade-html-lib')

mas 本身是一个函数: `Function(Object app_pool, String baseurl, Function mid_created_cb(Mid mid))`
这个函数为 `mixer-lib` 设计; app_pool 是 mixer:whenLoad 的回调对象;
baseurl 服务路径, 当中间件被创建完成 mid_created_cb 会被调用并传递 mid 对象;

mas.mid(String baseurl, Object config, Bool debug, FSObject fs_lib)

baseurl  服务的路径, mas 将这个路径作为服务的根路径映射到 public 的本地路径上;  
config   配置参数, 设置为空则从配置文件中加载, 注意此时需要等待配置加载完成, 见 `configuration-lib`;  
debug    设置为 true 出错后将在客户端打印完整的程序堆栈 (这将泄漏本地路径);  
fs_lib   默认为系统 fs;  
返回: Mid 对象

mas.listen(port, [path, callback])

在 port 端口上启动 http 服务, 并设置一个服务路径 path (默认 '/'),
当服务器启动 callback 函数被调用, 返回
  { http : Class http.Server (HTTP)[https://nodejs.org/dist/latest-v6.x/docs/api/http.html],
    mid  : Class Mid }

Class Mid

这是一个实例化的中间件, 需要挂载到 http 服务器上, 每个实例都可以配置成不同的状态.

Mid.add_plugin(info)

将插件放入服务中, 多个服务的插件配置可以是不同的, 创建插件见 '插件' 一节.

其他 api, 列出只作为完整性参考, 他们都是内部实现, 可能变更接口

mas.template.html_complier

mas.template.parseHtmlStructure

mas.tool.string_buf

mas.tool.rendering

mas.tool.expression_complier

mas.tool.isSystemVar

mas.tool.addSystemVar

mas.tool.forEachSystemVar

mas.tool.comment

mas.tool.nextId

mas.tool.parseExp

mas.base.html_builder

目录结构

这些配置在 config/config.js 中, 这些目录必须存在, 否则会出错

/[masquerade dir]           -- 项目根目录
    /private                -- 浏览器不可以直接访问的目录
        /include            -- 包含目录
        /script             -- node 脚本目录
        /tag                -- 自定义标签库目录
    /public                 -- 浏览器可以直接访问的目录
        /[some-other-files]

插件扩展

下文是关于扩展程序时需要的知识, 深入定制模板才需要查看.

上下文中的对象

这些对象可以通过 bird 表达式引用, 比如要引用 context.query.id 则使用表达式 ###qeury.id###; 如果要获取请求头中的信息使用 ###getHeader('Context-Type')###.

context: { // [r155]

[-- 在 http 中间件中有效的属性: --]
    nextId : Function()               -- 生成一个不重复的 ID
    session: Function()               -- 返回与客户端绑定的数据 (!待实现)
    query  : Object                   -- Http 请求参数
    builder: html_builder             -- 生成 html 代码的对象见 base.js
    expression: expression_complier   -- 编译并解析表达式的方法 (过时, 使用 parse)
    parse  : Function(String)         -- 编译一个字符串(其中可以有表达式), 返回的对象有 val(context) 可以取得结果
    baseurl: String                   -- 中间件解析器根路径
    filepool: Object                  -- 系统文件池
    setHeader: function(name, value)  -- 设置 HTTP 应答头域的值
    getHeader: function(name)         -- 取得 HTTP 请求头域的值
    getVmContext: function()
    log : function(...)               -- 写日志
    config : {}                       -- 读取运行时配置, runtime_

[-- 只在当前标签范围中有效的属性: [r175]--]
    tag_scope: {
        controler: {
            disable_sub()             -- 不渲染签体中的元素
            enable_sub()              -- (默认) 渲染标签体中的元素
        }        
        body: [ Buffer1, Buffer2 ... BufferN ]
                                      -- 标签体中静态文字的缓冲对象, 允许修改
                                      -- buffer 中的数据, 但修改 body 本身无效

        attr: Object                  -- 标签中的属性
        attr_str: String              -- 标签属性原始字符串
        name: String                  -- 标签名
        selfend: bool                 -- 自结束标签为 true
    }
}

渲染器函数定义

渲染器在不同的模块中有不同的定义 除了附加在后面的参数, 之前的参数的意义总是相同的

基础渲染器:

function(next, buf, context)

next    -- 渲染器中必须调用 next() 通知下一个渲染器开始渲染, next之后的代码无效
buf     -- 必须有 write 方法的对象, 可以通过 string_buf 创建
context -- 上下文对象, 由初始渲染器创建

基础渲染器的所有参数都不允许空, next 必须被调用, 否则后面的元素都不会渲染

模板渲染器:

function(next, buf, context, tag_over)

tag_over : `tag_over(function() { /* 当标签体渲染完成, 这里会被回调 */ })`

(其他参数同上) 自闭和的标签这个参数为空, 否则当内容全部渲染完成后通过该方法注册的函数被调用,
tag_over 的调用必须在 next 被调用之前完成, 否则不保证结果正确

插件代码模板

插件的完整实现, 可以参考 lib/systag/ 目录中系统插件的实现方式

//
// 创建中间件对象
//
var mid = mas.mid('/www');

//
// 在加入应用前,
// 添加插件实现复杂标签, 如果出错会抛出异常
// 客户端可以忽略这个异常, 则这个插件不会加载
//
mid.add_plugin( plugin_info: { name: '标签名', func: plugin_function } );

//
// 插件对象的渲染函数,
// taginfo 在 r175:tag_scope 中有说明,
// 当一个模板在编译时, 标签被声明, 这个函数被调用, 进行初始化的操作,
// 所有费时的操作都应该在初始化时完成, 如解析标签(动态)属性
//
function plugin_function(taginfo, userTagFactory, errorHandle, filename) {

    //
    // 必须返回一个渲染器函数, 当模板被渲染时, 这个函数被调用
    // 渲染器可以是异步执行, 最后必须调用 next
    //
    return function(next, buf, context, tag_over) {
        // next     -- 当这个标签渲染完成, 必须调用这个方法
        // buf      -- 是一个缓冲区对象, 可以用 .write() 写出字符串
        // context  -- 上下文对象见 r155

        // tag_over -- 自结束标签为空, 调用该方法注册一个回调函数
        // 当标签体中的标签也渲染完成时, 这个回调函数会被调用
        // 回调函数声明: function() { return 'stop'; }
        // 返回 stop 是可选的, 如果返回, 渲染会被终止! 当需要修改
        // 默认的渲染流程时会用到这个特性, 比如 for 循环的实现
    }
}