
# 介绍

`iart` 是一个简约, 超快的模板引擎.

采用作用域预声明的技术来优化模板渲染速度, 从而获得接近 JavaScript 极限的运行性能

## 特性

1. 拥有接近 JavaScript 渲染极限的性能
2. 调式友好: 语法, 运行时错误日志精确到模板所在行
3. 支持子模版等

![DsZ5W.png](https://s1.328888.xyz/2022/05/18/DsZ5W.png '性能对比')
![Dsjky.png](https://s1.328888.xyz/2022/05/18/Dsjky.png '错误日志')

## 模板

iart 同时支持两种模板语法. 标准语法可以让模板更容易读写; 原始语法具有强大的逻辑处理能力.

### 标准语法

```html
{{if user}}
  <h2>{{user.name}}</h2>
{{/if}}
```

### 原始语法

```ejs
<% if(user){ %>
  <h2><%= user.name %></h2>
<% } %>
```

原始语法兼容`EJS`,`Underscore`,`LoDash`

## 渲染模板

```js
import Art from '../lib/iart/index.js';
const html = Art.render(`<h1>{{user.name}}</h1>`, {
  user:{
    name:'zhangsan'
  }
});
```

## 核心方法

```js
import Art from '../lib/iart/index.js';
// 将模板源代码编译成函数并立刻执行
Art.render(source, data, options);
```

# 语法

`iart` 支持标准语法与原始语法. 标准语法可以让模板易读写, 而原始语法拥有强大的逻辑表达能力.

标准语法支持基本模板语法以及基本 JavaScript 表达式; 原始语法支持任意 JavaScript 语句, 这和`EJS`一样.

## 输出

### 标准语法1

```html
{{value}}
{{data.key}}
{{data['key']}}
{{a ? b : c}}
{{a || b}}
{{a + b}}
```

### 原始语法1

```ejs
<%= value %>
<%= data.key %>
<%= data['key'] %>
<%= a ? b : c %>
<%= a || b %>
<%= a + b %>
```

模板一级特殊变量可以使用`$data`加下标的方式访问:

```html
{{$data['user list']}}
```

## 原文输出

### 标准语法2

```html
{{@ value}}
```

### 原始语法2

```ejs
<%- value %>
```

> 原文输出语句不会对`html`内容进行转义处理, 可能存在安全风险, 请谨慎使用.

## 条件

### 标准语法3

```html
{{if value}} ... {{else}} ... {{/if}}
{{if v1}} ... {{else if v2}} ... {{/if}}
```

### 原始语法3

```ejs
<% if (value) { %> ... <% } else { %> ... <% } %>
<% if (v1) { %> ... <% } else if(v2) { %> ... <% } %>
```

## 循环

### 标准语法4

```html
{{each target}}
  {{$index}}---{{$value}}
{{/each}}
```

### 原始语法4

```ejs
<% for(var i = 0; i < target.length; i++ ){ %>
  <%= i %>---<%= target[i]%>
<% } %>
```

1. `target`支持`array`与`object`的迭代, 其默认值为`$data`.
2. `$value`与`$index`可以自定义: `{{each target val key}}`.

## 变量

### 标准语法5

```html
{{set temp = data.sub.content}}
```

### 原始语法5

```ejs
<% var temp = data.sub.content; %>
```

## 子模版

### 标准语法6

```html
{{include 'tpl_domid_or_tpl_url'}}
{{include 'tpl_domid_or_tpl_url', data}}
```

### 原始语法6

```ejs
<% include('tpl_domid_or_tpl_url') %>
<% include('tpl_domid_or_tpl_url', data) %>
```

> 传入的是存放模板的容器的 DOM ID, 则使用`document.getElementById('domid').innerHTML`获取模板内容
>
> 传入的是存放模板的文件路径, 则使用`fetch`函数异步获取

## 过滤器

### 注册过滤器

```js
import Art from '../lib/iart/index.js';
Art.defopt..imports.dateFormat = function(date, format){/*[code..]*/};
Art.defopt..imports.timestamp = function(value){return value * 1000};
```

过滤器函数第一个参数接受目标值.

### 标准语法7

```html
{{data | timestamp | dateFormat 'yyyy-MM-dd hh:mm:ss'}}
```

`{{value | filter}}`过滤器语法类似管道操作符, 它的上一个输出作为下一个输入.

### 原始语法7

```ejs
<%= $imports.dateFormat($imports.timestamp(date), 'yyyy-MM-dd hh:mm:ss') %>
```

> 如果想修改 `{{` `}}` 与 `<%` `%>`, 请参考`解析规则`;

# 解析规则

`Art.defopt.rules`

`iart`可以自定义模板解析规则, 默认配置了原始语法与标准语法.

## 修改界定符

```js
import Art from '../lib/iart/index.js';
// 原始语法的界定符规则
Art.defopt.rules[0].test = /<%(#?)((?:==|=#|[=-])?)[ \t]*([\w\W]*?)[ \t]*(-?)%>/;
// 标准语法的界定符规则
Art.defopt.rules[1].test = /{{([@#]?)[ \t]*(\/?)([\w\W]*?)[ \t]*}}/;
```

它们是一个正则表达式, 你可以只修改界定符部分. 例如修改 `<%` `%>` 为 `<?` `?>`:

```js
import Art from '../lib/iart/index.js';
var rule = Art.defopt.rules[0];
rule.test = new RegExp(rule.test.source.replace('<%', '<\\\?').replace('%>', '\\\?>'));
```

## 添加语法

从一个简单的例子说起, 让模板引擎支持ES6`${name}`模板字符串的解析:

```js
import Art from '../lib/iart/index.js';
Art.defopt.rules.push({
  test: /\${([\w\W]*?)}/,
  use: function(match, code) {
    return {
      code: code,
      output: 'escape'
    }
  }
});
```

其中`test`是匹配字符串正则, `use`是匹配后的调用函数. 关于`use`函数:

- 参数: 一个参数为匹配到的字符串, 其余的参数一次接收`test`正则的分组匹配内容
- 返回值: 必须返回一个对象, 包含`code`与`output`两个字段 :
  - `code`转换后的 JavaScript 语句
  - `output`描述`code`的类型, 可选值:
    - `escape` 编码后进行输出
    - `raw` 输出原始内容
    - `false` 不输出任何内容

值得一提的是, 语法规则对渲染速度没有影响, 模板引擎编译器会帮你优化渲染性能.

# 模板变量

`Art.defopt.imports`

模板通过`$imports`可以访问到模板外部的全局变量与导入的变量

## 导入变量

```js
import Art from '../lib/iart/index.js';
Art.defopt.imports.log = console.log;
```

```ejs
<% $imports.log('hello world') %>
```

## 内置变量清单

- `$data`传入模板的数据
- `$imports`外部导入的变量以及全局变量
- `print`字符串输出函数
- `include`子模版载入函数

# 选项

```js
/** 模板编译器默认配置 */
const settings: ArtDefaults = {
 // 是否启动调试
 debug: false,

 // 模板内容
 source: '',

 // 模板语法规则列表
 rules: [nativeRule, artRule],

 // 是否开启对模板输出语句自动编码功能。为 false 则关闭编码输出功能
 // escape 可以防范 XSS 攻击
 escape: true,

 // 子模板编译适配器
 include,

 // 忽略的变量。被模板编译器忽略的模板变量列表
 ignore: [],

 // 编译出错时是否重试
 recompile: false,

 // 导入的模板变量
 imports: runtime
};
```
