Skip to content

Commit

Permalink
Merge branch 'v4.8.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
aui committed May 7, 2017
2 parents 7f1eaf9 + 91fa949 commit 28a9501
Show file tree
Hide file tree
Showing 30 changed files with 481 additions and 340 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## v4.8.2

1. 修复子模板没有继承父模板编译 options 问题
2. 渲染函数参数可以为空

## v4.8.1

1. 修复低版本 NodeJS 报错问题
Expand Down
69 changes: 31 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

art-template 是一个渲染性能出众模板引擎,无论在 NodeJS 还是在浏览器中都可以运行。

[![chart](https://cloud.githubusercontent.com/assets/1791748/25561182/52b7c176-2d98-11e7-8270-da1aca0a80e4.png)](https://aui.github.io/art-template/example/web-test-speed/)
[![chart](https://cloud.githubusercontent.com/assets/1791748/25769656/13d09cb2-3252-11e7-9b31-b91110908bce.png)](https://aui.github.io/art-template/example/web-test-speed/)

[在线速度测试](https://aui.github.io/art-template/example/web-test-speed/)

Expand All @@ -17,11 +17,11 @@ art-template 是一个渲染性能出众模板引擎,无论在 NodeJS 还是
* 拥有接近 JavaScript 渲染极限的的性能
* 调试友好:语法、运行时错误日志精确到模板所在行;支持支持在模板文件上打断点(Webpack Loader)
* 支持压缩输出页面中的 HTML、CSS、JS 代码
* 支持 NodeJS 与 浏览器。支持 Express、Koa、Webpack
* 支持 Express、Koa、Webpack
* 支持模板继承与子模板
* 兼容 [EJS](http://ejs.co)[Underscore](http://underscorejs.org/#template)[LoDash](https://lodash.com/docs/#template) 模板语法
* 支持 ES 严格模式环境运行
* 支持原生 JavaScript 语法与简约语法混合书写
* 模板编译后的代码支持在严格模式下运行
* 支持 JavaScript 语句与模板语法混合书写
* 支持自定义模板的语法解析规则
* 浏览器版本仅 6KB 大小

Expand All @@ -32,15 +32,15 @@ art-template 是一个渲染性能出众模板引擎,无论在 NodeJS 还是
### 模板语法

```html
<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>

或:

{{if user}}
<h2>{{user.name}}</h2>
{{/if}}

或:

<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>
```

### NodeJS
Expand All @@ -54,22 +54,17 @@ var html = template(__dirname + '/tpl-user.art', {
});
```

### Web

1\. 使用浏览器版本:[lib/template-web.js](https://raw.githubusercontent.com/aui/art-template/master/lib/template-web.js)

2\. 在页面中存放模板:
### 浏览器

```html
<script src="lib/template-web.js"></script>
<script id="tpl-user" type="text/html">
<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>
{{if user}}
<h2>{{user.name}}</h2>
{{/if}}
</script>
```

3\. 渲染模板:

```js
var html = template('tpl-user', {
user: {
Expand Down Expand Up @@ -103,8 +98,6 @@ npm install art-template --save

下载:[lib/template-web.js](https://raw.githubusercontent.com/aui/art-template/master/lib/template-web.js)

浏览器版本没有文件加载、HTML 压缩的特性。

### Express

主页:[express-art-template](https://github.com/aui/express-art-template)
Expand Down Expand Up @@ -276,7 +269,7 @@ index.art:
### 过滤器

```js
// 向模板中导入全局变量
// 向模板中导入变量
template.defaults.imports.dateFormat = function(date, format){/*[code..]*/};
template.defaults.imports.timestamp = function(value){return value * 1000};
```
Expand All @@ -297,7 +290,7 @@ template.defaults.imports.timestamp = function(value){return value * 1000};
template.defaults.minimize = true;
```

art-template 的页面压缩功能是在编译阶段实现的,因此完全不影响渲染速度,并且能够加快网络传输速度。但也有一个限制,它会尝试“优化”未闭合的 HTML 标签,因此使用 `include` 语句载入模板片段请避免书写这样没有正确闭合的模板
art-template 的页面压缩功能是在编译阶段实现的,因此完全不影响渲染速度,并且能够加快网络传输速度。但也有一个限制,它会尝试“优化”未闭合的 HTML 标签,因此请避免书写这样没有正确闭合的模板

```html
<body>
Expand All @@ -308,11 +301,11 @@ art-template 的页面压缩功能是在编译阶段实现的,因此完全不
</body></html>
```

使用 [模板继承](#模板继承) 代替 `include` 可以避免这样的问题出现
使用子模板载入网页头与底公共部分的时候很容易出现此问题,解决方案是使用 [模板继承](#模板继承) 代替子模板

## 调试

设置 `template.defaults.debug=true` 后,它会设置如下选项
设置 `template.defaults.debug=true` 后,它会设置如下 [选项](#选项)

```json
{
Expand All @@ -330,32 +323,32 @@ art-template 的页面压缩功能是在编译阶段实现的,因此完全不

## 全局变量

### 内置变量清单
模板通过 `$imports` 可以访问到模板外部的全局变量。

* `$data` 传入模板的数据 `{Object|array}`
* `$imports` 外部导入的所有变量,等同 `template.defaults.imports` `{Object}`
* `print` 字符串输出函数 `{function}`
* `include` 子模板载入函数 `{function}`
* `extend` 模板继承模板导入函数 `{function}`
* `block` 模板块声明函数 `{function}`
### 内置变量清单

### 注入外部变量
* `$data` 传入模板的数据
* `$imports` 外部导入的变量以及全局变量
* `print` 字符串输出函数
* `include` 子模板载入函数
* `extend` 模板继承模板导入函数
* `block` 模板块声明函数

模板外部所有的变量都需要添加到 `template.defaults.imports` 后,模板才能使用。
### 导入变量

```js
template.defaults.imports.console = console;
template.defaults.imports.log = console.log;
```

```html
<% $imports.console.log('hello world') %>
<% $imports.log('hello world') %>
```

## 配置语法规则

### 修改界定符

art-template 支持修改默认模板界定符 `{{}}``<%%>`
art-template 支持修改默认模板界定符 `{{` `}}``<%` `%>`

```js
// 原生语法的界定符规则
Expand Down
1 change: 0 additions & 1 deletion _config.yml

This file was deleted.

2 changes: 1 addition & 1 deletion example/web-test-speed/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
duration: 150
},
renderTo: 'container',
height: categories.length * 40,
height: categories.length * 32,
type: 'bar'
},

Expand Down
2 changes: 1 addition & 1 deletion lib/compile/adapter/rule.art.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var artRule = {

// 旧版语法升级提示
var warn = function warn(oldSyntax, newSyntax) {
console.warn('Template upgrade:', '{{' + oldSyntax + '}}', '>>>', '{{' + newSyntax + '}}', '\n', options.filename || '');
console.warn('Template upgrade:', '{{' + oldSyntax + '}}', '->', '{{' + newSyntax + '}}', '\n', options.filename || '');
};

// v3 compat: #value
Expand Down
27 changes: 15 additions & 12 deletions lib/compile/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ var BLOCKS = '$$blocks';
/** 继承的布局模板的文件地址变量 */
var FROM = '$$from';

/** 导出布局模板函数 */
var LAYOUT = '$$layout';

/** 编译设置变量 */
var OPTIONS = '$$options';

Expand Down Expand Up @@ -86,10 +83,10 @@ var Compiler = function () {
this.external = (_external = {}, _external[DATA] = true, _external[IMPORTS] = true, _external[OPTIONS] = true, _external);

// 按需编译到模板渲染函数的内置变量
this.internal = (_internal = {}, _internal[OUT] = '\'\'', _internal[LINE] = '[0,0,\'\']', _internal[BLOCKS] = 'arguments[1]||{}', _internal[FROM] = 'null', _internal[LAYOUT] = 'function(){return ' + IMPORTS + '.$include(' + FROM + ',' + DATA + ',' + BLOCKS + ',' + OPTIONS + ')}', _internal[PRINT] = 'function(){' + OUT + '+=\'\'.concat.apply(\'\',arguments)}', _internal[INCLUDE] = 'function(src,data,block){' + OUT + '+=' + IMPORTS + '.$include(src,data||' + DATA + ',block,' + OPTIONS + ')}', _internal[EXTEND] = 'function(from){' + FROM + '=from}', _internal[BLOCK] = 'function(name,callback){if(' + FROM + '){' + OUT + '=\'\';callback();' + BLOCKS + '[name]=' + OUT + '}else{if(typeof ' + BLOCKS + '[name]===\'string\'){' + OUT + '+=' + BLOCKS + '[name]}else{callback()}}}', _internal);
this.internal = (_internal = {}, _internal[OUT] = '\'\'', _internal[LINE] = '[0,0,\'\']', _internal[BLOCKS] = 'arguments[1]||{}', _internal[FROM] = 'null', _internal[PRINT] = 'function(){' + OUT + '+=\'\'.concat.apply(\'\',arguments)}', _internal[INCLUDE] = 'function(src,data){' + OUT + '+=' + OPTIONS + '.include(src,data||' + DATA + ',arguments[2]||' + BLOCKS + ',' + OPTIONS + ')}', _internal[EXTEND] = 'function(from){' + FROM + '=from}', _internal[BLOCK] = 'function(name,callback){if(' + FROM + '){' + OUT + '=\'\';callback();' + BLOCKS + '[name]=' + OUT + '}else{if(typeof ' + BLOCKS + '[name]===\'string\'){' + OUT + '+=' + BLOCKS + '[name]}else{callback()}}}', _internal);

// 内置函数依赖关系声明
this.dependencies = (_dependencies = {}, _dependencies[PRINT] = [OUT], _dependencies[INCLUDE] = [OUT, IMPORTS, DATA, OPTIONS], _dependencies[EXTEND] = [FROM, /*[*/LAYOUT /*]*/], _dependencies[BLOCK] = [FROM, OUT, BLOCKS], _dependencies[LAYOUT] = [IMPORTS, FROM, DATA, BLOCKS, OPTIONS], _dependencies);
this.dependencies = (_dependencies = {}, _dependencies[PRINT] = [OUT], _dependencies[INCLUDE] = [OUT, OPTIONS, DATA, BLOCKS], _dependencies[EXTEND] = [FROM, /*[*/INCLUDE /*]*/], _dependencies[BLOCK] = [FROM, OUT, BLOCKS], _dependencies);

this.importContext(OUT);

Expand Down Expand Up @@ -270,18 +267,19 @@ var Compiler = function () {
Compiler.prototype.checkExpression = function checkExpression(script) {

// 没有闭合的块级模板语句规则
// 基于正则规则来补全语法不能保证 100% 准确,
// 但是在绝大多数情况下足以满足辅助开发调试的需要
var rules = [

// <% } %>
// <% }else{ %>
// <% }else if(a){ %>
[/^\s*}[\w\W]*?{?[\s;]*$/, ''],

// <% list.forEach(function(a,b){ %>
[/(^[\w\W]*?\s*function\s*\([\w\W]*?\)\s*{[\s;]*$)/, '$1})'],

// <% list.forEach((a,b)=>{ %>
[/(^.*?\(\s*[\w\W]*?=>\s*{[\s;]*$)/, '$1})'],
// <% fn(c,function(a,b){ %>
// <% fn(c, a=>{ %>
// <% fn(c,(a,b)=>{ %>
[/(^[\w\W]*?\([\w\W]*?(?:=>|\([\w\W]*?\))\s*{[\s;]*$)/, '$1})'],

// <% if(a){ %>
// <% for(var i in d){ %>
Expand Down Expand Up @@ -353,6 +351,7 @@ var Compiler = function () {

stacks.push('function(' + DATA + '){');
stacks.push('\'use strict\'');
stacks.push(DATA + '=' + DATA + '||{}');
stacks.push('var ' + context.map(function (_ref2) {
var name = _ref2.name,
value = _ref2.value;
Expand Down Expand Up @@ -385,7 +384,12 @@ var Compiler = function () {
});
}

stacks.push(extendMode ? 'return ' + LAYOUT + '()' : 'return ' + OUT);
if (extendMode) {
stacks.push(OUT + '=\'\'');
stacks.push(INCLUDE + '(' + FROM + ',' + DATA + ',' + BLOCKS + ')');
}

stacks.push('return ' + OUT);
stacks.push('}');

var renderCode = stacks.join('\n');
Expand Down Expand Up @@ -446,7 +450,6 @@ Compiler.CONSTS = {
LINE: LINE,
BLOCKS: BLOCKS,
FROM: FROM,
LAYOUT: LAYOUT,
ESCAPE: ESCAPE
};

Expand Down
26 changes: 12 additions & 14 deletions lib/compile/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
var detectNode = require('detect-node');
var runtime = require('./runtime');
var extend = require('./adapter/extend');
var include = require('./adapter/include');
var onerror = require('./adapter/onerror');
var caches = require('./adapter/caches');
var loader = require('./adapter/loader');
var include = require('./adapter/include');
var artRule = require('./adapter/rule.art');
var nativeRule = require('./adapter/rule.native');
var htmlMinifier = require('./adapter/html-minifier');
var resolveFilename = require('./adapter/resolve-filename');

/** 模板编译器默认配置 */
var defaults = {
var settings = {

// 模板内容。如果没有此字段,则会根据 filename 来加载模板内容
source: null,
Expand Down Expand Up @@ -47,6 +47,9 @@ var defaults = {
// 模板路径转换器
resolveFilename: resolveFilename,

// 子模板编译适配器
include: include,

// HTML 压缩器。仅在 NodeJS 环境下有效
htmlMinifier: htmlMinifier,

Expand Down Expand Up @@ -82,17 +85,12 @@ var defaults = {

};

/**
* 继承默认配置
* @param {Object} options
* @return {Object}
*/
defaults.$extend = function () {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return extend(options, defaults);
function Defaults() {
this.$extend = function (options) {
options = options || {};
return extend(options, options instanceof Defaults ? options : this);
};
};
Defaults.prototype = settings;

// 载入子模板的方法
runtime.$include = include;

module.exports = defaults;
module.exports = new Defaults();
File renamed without changes.
15 changes: 3 additions & 12 deletions lib/compile/es-tokenizer.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
"use strict";
'use strict';

var isKeyword = require('is-keyword-js');

// [email protected]
// Copyright 2014, 2015, 2016, 2017 Simon Lydell
// License: MIT. (See LICENSE.)
var jsTokens = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyu]{1,5}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g;

var matchToToken = function matchToToken(match) {
var token = { type: "invalid", value: match[0] };
if (match[1]) token.type = "string", token.closed = !!(match[3] || match[4]);else if (match[5]) token.type = "comment";else if (match[6]) token.type = "comment", token.closed = !!match[7];else if (match[8]) token.type = "regex";else if (match[9]) token.type = "number";else if (match[10]) token.type = "name";else if (match[11]) token.type = "punctuator";else if (match[12]) token.type = "whitespace";
return token;
};
var jsTokens = require('js-tokens').default;
var matchToToken = require('js-tokens').matchToToken;

/**
* 将逻辑表达式解释为 Tokens
Expand Down
6 changes: 5 additions & 1 deletion lib/compile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

var Compiler = require('./compiler');
var defaults = require('./defaults');
var TemplateError = require('./template-error');
var TemplateError = require('./error');

var debugRender = function debugRender(error, options) {
options.onerror(error, options);
Expand Down Expand Up @@ -43,6 +43,10 @@ var compile = function compile(source) {
options.compileDebug = true;
}

if (options.compileDebug) {
options.minimize = false;
}

// 转换成绝对路径
if (options.filename) {
options.filename = options.resolveFilename(options.filename, options);
Expand Down
Loading

0 comments on commit 28a9501

Please sign in to comment.