Skip to content

mustache模版引擎的工作原理入门 #14

@iscarecrow

Description

@iscarecrow

上一篇underscore模板引擎的工作原理,介绍到underscore采用正则替换模板变量,输出函数,并执行获取HtmlString,但是存在的问题如下:

内容包括

  • 函数直接执行存在问题
  • mustache字符串扫描过程Scanner
  • token转换成htmlString Writer
  • xss攻击防御、报错机制、模版缓存如何处理

函数直接执行存在问题

  • xss攻击防御
  • 报错机制
  • 模版缓存

mustache如何解决这些问题

接下来我们讨论mustache是如何运行的

mustache模版方法
  • Scanner
  • Writer
  • Context
思路
  1. Scanner逐个扫描整个字符串,通过不同类型进行存储token
  2. Write将token按类型进行渲染

Scanner扫描

scanner的扫描方法,整个字符串从左往右。输入输出如下,调用parseTemplate

input = '12{{title}}'3;

// parseTemplate, token [type,content,字符串起始位置,字符串结束位置]
output = [
	['text',1, 0,1],
	['text',2, 1,2],
    ['name','title',2,11],
    ['text',3,11,12]
]

// squashTokens 合并
output = [
	['text',12,0,2],
	['name','title',2,11],
	['text',11,12]
]

扫描机制

  • scan
  • scanUntil
  • eos (input)
// 1.扫描字符串text
var openingTagRe = /\{\{\s*/
var input = '12{{title}}3';
var value =  scanner.scanUntil(openingTagRe)
// 扫描到{{, 获取12(text type), value循环.
var output = '{{title}}3'

// 2.去除开始符号{{
input = '{{title}}3'
output = 'title}}3'

// 3.匹配变量name 
var closingTagRe = /\s*\}\}/
var input = 'title}}3'
var x = scanner.scanUntil(closingTagRe)
// 扫描到}}, 获取title(name type)
var output = '}}3'

// 4.去除结束符号}}
input = '}}3'
output = '3'

// 5.循环1步骤
var input = 3
var output = '';

Writer 数据写入

  • renderTokens 分发不同type的渲染

此处根据token类型( #、^、>、&、name、text),使用renderTokens填写变量

// loop squashTokens render
for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
	// 类型 #、^、>、&、name、text
	symbol = token[0];
	value = render(symbol)
	buffer +=value
}
// buffer就是最终要渲染的字符串

======== to be continued =========

缓存问题解析

Context

  • lookup
  • push
xss防御问题解析 escape
  • mustache.escape
var title = "<h1>dddd</h1>"
var input = "<h3>12{{title}}</h3>";
var output = "<h3>12&lt;h1&gt;ddddd&lt;&#x2F;h1&gt;</h3>"

var string = '<h1>dddd</h1>';

var entityMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
    '/': '&#x2F;',
    '`': '&#x60;',
    '=': '&#x3D;'
  };

 function escapeHtml (string) {
    return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
      return entityMap[s];
    });
  }
报错问题解析

throw,因为整个htmlString是逐个解析的,所以能够在需要报错的节点直接抛异常

  • {{ }} 报错
  • 输入template出错

参考资料

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions