artTemplate源码

主要实现:通过拼接字符串的方式构建编译函数,辅助函数通过在编译函数字符串体内以var methodName=function(){}方式传入,因此编译函数字符串体内就可以使用methodName方式加以调用;用户数据通过向编译函数传参注入,赋值给$data后,就可以使用$data.value的方式使用;if、each语句预先通过parser方法将其拼接为js形式的if、each语法。

 

1.构建编译函数

compile.js

 

  1. /** 
  2.  * 编译模板 
  3.  * 2012-6-6 @TooBug: define 方法名改为 compile,与 Node Express 保持一致 
  4.  * @name    template.compile 
  5.  * @param   {String}    模板字符串 
  6.  * @param   {Object}    编译选项 
  7.  * 
  8.  *      - openTag       {String}      // 逻辑语法开始标签 "{{" 或 "<%" 
  9.  *      - closeTag      {String}      // 逻辑语法开始标签 "}}" 或 "%>" 
  10.  *      - filename      {String}      // 用于报错时提醒用户模板字符串的模板名,并作为cacheStore的属性存储编译函数 
  11.  *      - escape        {Boolean}     // html字符串转义,编码: <%=value%> 不编码:<%=#value%> 
  12.  *      - compress      {Boolean}     // 是否压缩多余空白和注释 
  13.  *      - debug         {Boolean}     // 是否开启调试模式编译模板字符串 
  14.  *      - cache         {Boolean}     // 是否缓存模板字符串编译结果 
  15.  *      - parser        {Function}    // 语法转换插件钩子,"<%"、"%>"间内部值预处理,默认defaults.parser 
  16.  * 
  17.  * @return  {Function}  渲染方法 
  18.  */  
  19. // 通过compiler以字符串形式拼接编译函数体,最终转化成函数输出  
  20. var compile = template.compile = function (source, options) {  
  21.     // 合并默认配置  
  22.     options = options || {};  
  23.     for (var name in defaults) {  
  24.         if (options[name] === undefined) {  
  25.             options[name] = defaults[name];  
  26.         }  
  27.     }  
  28.   
  29.     var filename = options.filename;  
  30.   
  31.     try {  
  32.         var Render = compiler(source, options);  
  33.     } catch (e) {  
  34.         e.filename = filename || 'anonymous';  
  35.         e.name = 'Syntax Error';  
  36.   
  37.         return showDebugInfo(e);  
  38.     }  
  39.       
  40.     // 对编译结果进行一次包装  
  41.     function render (data) {  
  42.         try {  
  43.             return new Render(data, filename) + '';  
  44.         } catch (e) {  
  45.             // 运行时出错后自动开启调试模式重新编译  
  46.             if (!options.debug) {  
  47.                 options.debug = true;  
  48.                 return compile(source, options)(data);  
  49.             }  
  50.             return showDebugInfo(e)();  
  51.         }  
  52.     }  
  53.       
  54.     render.prototype = Render.prototype;  
  55.     render.toString = function () {  
  56.         return Render.toString();  
  57.     };  
  58.   
  59.     if (filename && options.cache) {  
  60.         // 缓存模板字符串解析函数  
  61.         cacheStore[filename] = render;  
  62.     }  
  63.   
  64.     return render;  
  65. };  
  66.   
  67. // 数组迭代  
  68. var forEach = utils.$each;  
  69.   
  70. // 静态分析模板变量  
  71. var KEYWORDS =  
  72.     // 关键字  
  73.     'break,case,catch,continue,debugger,default,delete,do,else,false'  
  74.     + ',finally,for,function,if,in,instanceof,new,null,return,switch,this'  
  75.     + ',throw,true,try,typeof,var,void,while,with'  
  76.   
  77.     // 保留字  
  78.     + ',abstract,boolean,byte,char,class,const,double,enum,export,extends'  
  79.     + ',final,float,goto,implements,import,int,interface,long,native'  
  80.     + ',package,private,protected,public,short,static,super,synchronized'  
  81.     + ',throws,transient,volatile'  
  82.   
  83.     // ECMA 5 - use strict  
  84.     + ',arguments,let,yield'  
  85.   
  86.     + ',undefined';  
  87.   
  88. // 滤除多行注释、单行注释、单双引号包裹字符串、点号+空格后的字符串  
  89. var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g;  
  90. // 滤除变量,如{{if admin}}中的admin  
  91. var SPLIT_RE = /[^\w$]+/g;  
  92. // 滤除js关键字  
  93. var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g');  
  94. // 滤除数字  
  95. var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g;  
  96. // 滤除起始、结尾的多个逗号  
  97. var BOUNDARY_RE = /^,+|,+$/g;  
  98. // 以$或,分割  
  99. var SPLIT2_RE = /^$|,+/;  
  100.   
  101. // 获取变量  
  102. function getVariable (code) {  
  103.     return code  
  104.     .replace(REMOVE_RE, '')  
  105.     .replace(SPLIT_RE, ',')  
  106.     .replace(KEYWORDS_RE, '')  
  107.     .replace(NUMBER_RE, '')  
  108.     .replace(BOUNDARY_RE, '')  
  109.     .split(SPLIT2_RE);  
  110. };  
  111.   
  112. // 字符串转义  
  113. function stringify (code) {  
  114.     return "'" + code  
  115.     // 单引号与反斜杠转义  
  116.     .replace(/('|\\)/g, '\\$1')  
  117.     // 换行符转义(windows + linux)  
  118.     .replace(/\r/g, '\\r')  
  119.     .replace(/\n/g, '\\n') + "'";  
  120. }  
  121.   
  122. // 通过模板字符串和options配置,拼接编译函数体,template.compile方法中转化成函数  
  123. function compiler (source, options) {  
  124.     var debug = options.debug;// 是否开启调试模式编译模板字符串  
  125.     var openTag = options.openTag;// 逻辑语法开始标签 "{{"  
  126.     var closeTag = options.closeTag;// 逻辑语法闭合标签 "}}"  
  127.     var parser = options.parser;// 语法转换插件钩子,默认的钩子为拼接if、each、echo等语句  
  128.     var compress = options.compress;// 是否压缩多余空白和注释  
  129.     var escape = options.escape;// html字符串转义,编码: <%=value%> 不编码:<%=#value%>  
  130.       
  131.     var line = 1;  
  132.   
  133.     // uniq记录定义编译函数体内已定义的方法名或属性名,防止重复定义  
  134.     var uniq = {$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1};  
  135.   
  136.     var isNewEngine = ''.trim;// '__proto__' in {}  
  137.     var replaces = isNewEngine  
  138.     ? ["$out='';", "$out+=", ";", "$out"]  
  139.     : ["$out=[];", "$out.push(", ");", "$out.join('')"];  
  140.   
  141.     var concat = isNewEngine  
  142.         ? "$out+=text;return $out;"  
  143.         : "$out.push(text);";  
  144.             
  145.     var print = "function(){"  
  146.     +      "var text=''.concat.apply('',arguments);"  
  147.     +       concat  
  148.     +  "}";  
  149.   
  150.     var include = "function(filename,data){"  
  151.     +      "data=data||$data;"  
  152.     +      "var text=$utils.$include(filename,data,$filename);"  
  153.     +       concat  
  154.     +   "}";  
  155.   
  156.     var headerCode = "'use strict';"  
  157.     + "var $utils=this,$helpers=$utils.$helpers,"  
  158.     + (debug ? "$line=0," : "");  
  159.       
  160.     var mainCode = replaces[0];  
  161.   
  162.     var footerCode = "return new String(" + replaces[3] + ");"  
  163.       
  164.     // html与逻辑语法分离  
  165.     forEach(source.split(openTag), function (code) {  
  166.         code = code.split(closeTag);  
  167.           
  168.         var $0 = code[0];  
  169.         var $1 = code[1];  
  170.           
  171.         // code: [html] 以openTag起始,无closeTag闭合,处理成html字符串形式  
  172.         if (code.length === 1) {  
  173.             mainCode += html($0);  
  174.            
  175.         // code: [logic, html] 以openTag起始,有closeTag闭合,处理成logic+html字符串形式  
  176.         } else {  
  177.             mainCode += logic($0);  
  178.               
  179.             if ($1) {  
  180.                 mainCode += html($1);  
  181.             }  
  182.         }  
  183.     });  
  184.       
  185.     var code = headerCode + mainCode + footerCode;  
  186.       
  187.     // 调试语句,试用try-catch方法捕获错误,报错  
  188.     if (debug) {  
  189.         code = "try{" + code + "}catch(e){"  
  190.         +       "throw {"  
  191.         +           "filename:$filename,"  
  192.         +           "name:'Render Error',"  
  193.         +           "message:e.message,"  
  194.         +           "line:$line,"  
  195.         +           "source:" + stringify(source)  
  196.         +           ".split(/\\n/)[$line-1].replace(/^\\s+/,'')"  
  197.         +       "};"  
  198.         + "}";  
  199.     }  
  200.       
  201.     try {  
  202.         // code用于拼接字符串构建函数  
  203.         var Render = new Function("$data", "$filename", code);  
  204.         Render.prototype = utils;  
  205.         return Render;  
  206.     } catch (e) {  
  207.         e.temp = "function anonymous($data,$filename) {" + code + "}";  
  208.         throw e;  
  209.     }  
  210.   
  211.     // 处理 HTML 语句  
  212.     function html (code) {  
  213.         // 记录行号,调试模式下输出处理失败的行号  
  214.         line += code.split(/\n/).length - 1;  
  215.   
  216.         // 压缩多余空白与注释  
  217.         if (compress) {  
  218.             code = code  
  219.             .replace(/\s+/g, ' ')  
  220.             .replace(/<!--[\w\W]*?-->/g, '');  
  221.         }  
  222.           
  223.         if (code) {  
  224.             code = replaces[1] + stringify(code) + replaces[2] + "\n";  
  225.         }  
  226.   
  227.         return code;  
  228.     }  
  229.       
  230.     // 处理逻辑语句  
  231.     function logic (code) {  
  232.   
  233.         var thisLine = line;  
  234.          
  235.         if (parser) {  
  236.             // 语法转换插件钩子,默认的钩子为拼接if、each、echo等语句  
  237.             code = parser(code, options);   
  238.         } else if (debug) {  
  239.             // 记录行号  
  240.             code = code.replace(/\n/g, function () {  
  241.                 line ++;  
  242.                 return "$line=" + line +  ";";  
  243.             });  
  244.         }  
  245.           
  246.         // 输出语句. 编码: <%=value%> 不编码:<%=#value%>  
  247.         // <%=#value%> 等同 v2.0.3 之前的 <%==value%>  
  248.         if (code.indexOf('=') === 0) {  
  249.             var escapeSyntax = escape && !/^=[=#]/.test(code);  
  250.   
  251.             code = code.replace(/^=[=#]?|[\s;]*$/g, '');  
  252.   
  253.             // 对内容编码  
  254.             if (escapeSyntax) {  
  255.                 var name = code.replace(/\s*\([^\)]+\)/, '');  
  256.   
  257.                 // 排除 utils.* | include | print,当name值为utils中内部方法或print、include  
  258.                 // headerCode中,this关键字指向$utils,$escape可直接调用,对html中'、"、<、>、&进行转义  
  259.                 if (!utils[name] && !/^(include|print)$/.test(name)) {  
  260.                     code = "$escape(" + code + ")";  
  261.                 }  
  262.   
  263.             // 不编码  
  264.             } else {  
  265.                 code = "$string(" + code + ")";  
  266.             }  
  267.               
  268.             code = replaces[1] + code + replaces[2];  
  269.         }  
  270.           
  271.         if (debug) {  
  272.             code = "$line=" + thisLine + ";" + code;  
  273.         }  
  274.           
  275.         // 提取模板中的方法名,在headerCode中注入该方法的内容,拼接的函数体内就可以通过方法名调用  
  276.         forEach(getVariable(code), function (name) {  
  277.               
  278.             // name 值可能为空,在安卓低版本浏览器下  
  279.             if (!name || uniq[name]) {  
  280.                 return;  
  281.             }  
  282.   
  283.             var value;  
  284.   
  285.             // 声明模板变量  
  286.             // 赋值优先级:  
  287.             // [include, print] > utils > helpers > data  
  288.             if (name === 'print') {  
  289.                 value = print;  
  290.             } else if (name === 'include') {  
  291.                 value = include;  
  292.             } else if (utils[name]) {  
  293.                 value = "$utils." + name;  
  294.             } else if (helpers[name]) {  
  295.                 value = "$helpers." + name;  
  296.             } else {  
  297.                 value = "$data." + name;  
  298.             }  
  299.               
  300.             headerCode += name + "=" + value + ",";  
  301.             uniq[name] = true;  
  302.         });  
  303.           
  304.         return code + "\n";  
  305.     }  
  306.       
  307. };  

 

2.if、each、print、echo、include语句及过滤函数预处理

syntax.js

  1. // 语法转换插件钩子,"<%"、"%>"间内部值预处理,拼接if、each、print、include、echo语句等,参见compiler模块  
  2.   
  3. defaults.openTag = '{{';  
  4. defaults.closeTag = '}}';  
  5.   
  6. // {{value | filterA:'abcd' | filterB}}形式,调用$helpers下方法对value进行过滤处理  
  7. var filtered = function (js, filter) {  
  8.     var parts = filter.split(':');  
  9.     var name = parts.shift();  
  10.     var args = parts.join(':') || '';  
  11.   
  12.     if (args) {  
  13.         args = ', ' + args;  
  14.     }  
  15.   
  16.     return '$helpers.' + name + '(' + js + args + ')';  
  17. }  
  18.   
  19. // 语法转换插件钩子,"<%"、"%>"间内部值预处理,拼接if、each、print、include、echo语句等,参见compiler模块  
  20. defaults.parser = function (code, options) {  
  21.     // var match = code.match(/([\w\$]*)(\b.*)/); // \b单词边界符  
  22.     // var key = match[1];  
  23.     // var args = match[2];  
  24.     // var split = args.split(' ');  
  25.     // split.shift();  
  26.     code = code.replace(/^\s/, '');// 滤除起始的空格  
  27.   
  28.     var split = code.split(' ');  
  29.     var key = split.shift();  
  30.     var args = split.join(' ');  
  31.   
  32.     switch (key) {  
  33.         // 拼接if语句  
  34.         case 'if':  
  35.             code = 'if(' + args + '){';  
  36.             break;  
  37.         case 'else':  
  38.             if (split.shift() === 'if') {  
  39.                 split = ' if(' + split.join(' ') + ')';  
  40.             } else {  
  41.                 split = '';  
  42.             }  
  43.   
  44.             code = '}else' + split + '{';  
  45.             break;  
  46.         case '/if':  
  47.             code = '}';  
  48.             break;  
  49.   
  50.         // 拼接each语句  
  51.         case 'each':  
  52.             var object = split[0] || '$data';  
  53.             var as     = split[1] || 'as';  
  54.             var value  = split[2] || '$value';  
  55.             var index  = split[3] || '$index';  
  56.               
  57.             var param   = value + ',' + index;  
  58.               
  59.             if (as !== 'as') {  
  60.                 object = '[]';  
  61.             }  
  62.               
  63.             code =  '$each(' + object + ',function(' + param + '){';  
  64.             break;  
  65.         case '/each':  
  66.             code = '});';  
  67.             break;  
  68.   
  69.         // 拼接print语句  
  70.         case 'echo':  
  71.             code = 'print(' + args + ');';  
  72.             break;  
  73.   
  74.         // 拼接print、include语句  
  75.         case 'print':  
  76.         case 'include':  
  77.             code = key + '(' + split.join(',') + ');';  
  78.             break;  
  79.   
  80.         default:  
  81.             // 过滤器(辅助方法),value为待过滤的变量,filterA为helpers下方法名,'abcd'为filterA参数  
  82.             // {{value | filterA:'abcd' | filterB}}  
  83.             // >>> $helpers.filterB($helpers.filterA(value, 'abcd'))  
  84.             // TODO: {{ddd||aaa}} 不包含空格  
  85.             if (/^\s*\|\s*[\w\$]/.test(args)) {  
  86.   
  87.                 var escape = true;  
  88.   
  89.                 // {{#value | link}}  
  90.                 if (code.indexOf('#') === 0) {  
  91.                     code = code.substr(1);  
  92.                     escape = false;  
  93.                 }  
  94.   
  95.                 var i = 0;  
  96.                 var array = code.split('|');  
  97.                 var len = array.length;  
  98.                 var val = array[i++];  
  99.   
  100.                 for (; i < len; i ++) {  
  101.                     val = filtered(val, array[i]);  
  102.                 }  
  103.   
  104.                 code = (escape ? '=' : '=#') + val;  
  105.   
  106.             // 即将弃用 {{helperName value}}  
  107.             } else if (template.helpers[key]) {  
  108.                 code = '=#' + key + '(' + split.join(',') + ');';  
  109.               
  110.             // 内容直接输出 {{value}}  
  111.             } else {  
  112.                 code = '=' + code;  
  113.             }  
  114.             break;  
  115.     }  
  116.       
  117.     return code;  
  118. };  

3.辅助函数

utils.js

  1. var toString = function (value, type) {  
  2.   
  3.     if (typeof value !== 'string') {  
  4.   
  5.         type = typeof value;  
  6.         if (type === 'number') {  
  7.             value += '';  
  8.         } else if (type === 'function') {  
  9.             value = toString(value.call(value));  
  10.         } else {  
  11.             value = '';  
  12.         }  
  13.     }  
  14.   
  15.     return value;  
  16. };  
  17.   
  18. var escapeMap = {  
  19.     "<": "&#60;",  
  20.     ">": "&#62;",  
  21.     '"': "&#34;",  
  22.     "'": "&#39;",  
  23.     "&": "&#38;"  
  24. };  
  25.   
  26. var escapeFn = function (s) {  
  27.     return escapeMap[s];  
  28. };  
  29.   
  30. var escapeHTML = function (content) {  
  31.     return toString(content)  
  32.     .replace(/&(?![\w#]+;)|[<>"']/g, escapeFn);  
  33. };  
  34.   
  35. var isArray = Array.isArray || function (obj) {  
  36.     return ({}).toString.call(obj) === '[object Array]';  
  37. };  
  38.   
  39. var each = function (data, callback) {  
  40.     var i, len;          
  41.     if (isArray(data)) {  
  42.         for (i = 0, len = data.length; i < len; i++) {  
  43.             callback.call(data, data[i], i, data);  
  44.         }  
  45.     } else {  
  46.         for (i in data) {  
  47.             callback.call(data, data[i], i);  
  48.         }  
  49.     }  
  50. };  
  51.   
  52. var utils = template.utils = {  
  53.     $helpers: {},  
  54.     $include: renderFile,  
  55.     $string: toString,  
  56.     $escape: escapeHTML,  
  57.     $each: each   
  58. };  

helper.js,可由用户添加过滤函数等

 

 

 

  1. /** 
  2.  * 添加模板辅助方法 
  3.  * @name    template.helper 
  4.  * @param   {String}    名称 
  5.  * @param   {Function}  方法 
  6.  */  
  7. template.helper = function (name, helper) {  
  8.     helpers[name] = helper;  
  9. };  
  10.   
  11. var helpers = template.helpers = utils.$helpers;  

 

4.编译接口

template.js

  1. /** 
  2.  * 模板引擎 
  3.  * @name    template 
  4.  * @param   {String}            模板名 
  5.  * @param   {Object, String}    数据。如果为字符串,则作为模板字符串进行编译,缓存并返回编译函数 
  6.  *                                  如果为对象,则作为传给编译函数的数据,最终返回编译结果 
  7.  * @return  {String, Function}  渲染好的HTML字符串或者渲染方法 
  8.  */  
  9. var template = function (filename, content) {  
  10.     return typeof content === 'string'  
  11.     ?   compile(content, {  
  12.             filename: filename  
  13.         })  
  14.     :   renderFile(filename, content);  
  15. };  
  16.   
  17. template.version = '3.0.0'; 

renderFile.js

 

 

 

  1. /** 
  2.  * 渲染模板(根据模板名) 
  3.  * @name    template.render 
  4.  * @param   {String}    模板名,页面元素id 
  5.  * @param   {Object}    数据,data传入为空时,返回结果为编译函数 
  6.  * @return  {String}    渲染好的字符串 
  7.  */  
  8. var renderFile = template.renderFile = function (filename, data) {  
  9.     var fn = template.get(filename) || showDebugInfo({  
  10.         filename: filename,  
  11.         name: 'Render Error',  
  12.         message: 'Template not found'  
  13.     });  
  14.     return data ? fn(data) : fn;  
  15. };  

get.js

 

 

 

 

  1. /** 
  2.  * 获取编译缓存(可由外部重写此方法) 
  3.  * @param   {String}    模板名 
  4.  * @param   {Function}  编译好的函数 
  5.  */  
  6. template.get = function (filename) {  
  7.   
  8.     var cache;  
  9.       
  10.     if (cacheStore[filename]) {  
  11.         // 获取使用内存缓存的编译函数  
  12.         cache = cacheStore[filename];  
  13.     } else if (typeof document === 'object') {  
  14.         // 通过模板名获取模板字符串,编译,并返回编译函数  
  15.         var elem = document.getElementById(filename);  
  16.           
  17.         if (elem) {  
  18.             var source = (elem.value || elem.innerHTML)  
  19.             .replace(/^\s*|\s*$/g, '');  
  20.             cache = compile(source, {  
  21.                 filename: filename  
  22.             });  
  23.         }  
  24.     }  
  25.   
  26.     return cache;  
  27. };  

render.js

 

 

 

 

  1. /** 
  2.  * 渲染模板 
  3.  * @name    template.render 
  4.  * @param   {String}    模板字符串 
  5.  * @param   {Object}    数据 
  6.  * @return  {String}    编译函数 
  7.  */  
  8. template.render = function (source, options) {  
  9.     return compile(source, options);  
  10. }; 

 

5.错误提示

onerror.js

  1. /** 
  2.  * 模板错误事件(可由外部重写此方法),触发console.error提示错误信息 
  3.  * @name    template.onerror 
  4.  * @event 
  5.  */  
  6. template.onerror = function (e) {  
  7.     var message = 'Template Error\n\n';  
  8.     for (var name in e) {  
  9.         message += '<' + name + '>\n' + e[name] + '\n\n';  
  10.     }  
  11.       
  12.     if (typeof console === 'object') {  
  13.         console.error(message);  
  14.     }  
  15. };  
  16.   
  17. // 模板调试器  
  18. var showDebugInfo = function (e) {  
  19.   
  20.     template.onerror(e);  
  21.       
  22.     return function () {  
  23.         return '{Template Error}';  
  24.     };  
  25. };  

6.配置

compile.js

  1. /** 
  2.  * 设置全局配置 
  3.  * @name    template.config 
  4.  * @param   {String}    名称 
  5.  * @param   {Any}       值 
  6.  */  
  7. template.config = function (name, value) {  
  8.     defaults[name] = value;  
  9. };  
  10.   
  11. var defaults = template.defaults = {  
  12.     openTag: '<%',    // 逻辑语法开始标签  
  13.     closeTag: '%>',   // 逻辑语法结束标签  
  14.     escape: true,     // 是否编码输出变量的 HTML 字符  
  15.     cache: true,      // 是否开启缓存(依赖 options 的 filename 字段)  
  16.     compress: false,  // 是否压缩输出  
  17.     parser: null      // 自定义语法格式器 @see: template-syntax.js  
  18. };  

7.外层包裹,适用于amd/cmd/commonjs环境,同seajs

intro.js

  1. /*! 
  2.  * artTemplate - Template Engine 
  3.  * https://github.com/aui/artTemplate 
  4.  * Released under the MIT, BSD, and GPL Licenses 
  5.  */  
  6.    
  7. !(function () { 

outro.js

 

  1. // RequireJS && SeaJS  
  2. if (typeof define === 'function') {  
  3.     define(function() {  
  4.         return template;  
  5.     });  
  6.   
  7. // NodeJS  
  8. else if (typeof exports !== 'undefined') {  
  9.     module.exports = template;  
  10. else {  
  11.     this.template = template;  
  12. }  
  13.   
  14. })(); 

 

附:拼接js文件实现使用grunt

Gruntfile.js配置

  1. module.exports = function (grunt) {  
  2.   
  3.     var sources_native = [  
  4.         'src/intro.js',  
  5.         'src/template.js',  
  6.         'src/config.js',  
  7.         'src/cache.js',  
  8.         'src/render.js',  
  9.         'src/renderFile.js',  
  10.         'src/get.js',  
  11.         'src/utils.js',  
  12.         'src/helper.js',  
  13.         'src/onerror.js',  
  14.         'src/compile.js',  
  15.                     //<<<< 'src/syntax.js',  
  16.         'src/outro.js'  
  17.     ];  
  18.   
  19.     var sources_simple = Array.apply(null, sources_native);  
  20.     sources_simple.splice(sources_native.length - 1, 0, 'src/syntax.js');  
  21.   
  22.   
  23.     grunt.initConfig({  
  24.         pkg: grunt.file.readJSON('package.json'),  
  25.         meta: {  
  26.             banner: '/*!<%= pkg.name %> - Template Engine | <%= pkg.homepage %>*/\n'  
  27.         },  
  28.         concat: {  
  29.             options: {  
  30.                 separator: ''  
  31.             },  
  32.   
  33.             'native': {  
  34.                 src: sources_native,  
  35.                 dest: 'dist/template-native-debug.js'  
  36.             },  
  37.   
  38.             simple: {  
  39.                 src: sources_simple,  
  40.                 dest: 'dist/template-debug.js'  
  41.             }  
  42.         },  
  43.         uglify: {  
  44.             options: {  
  45.                 banner: '<%= meta.banner %>'  
  46.             },  
  47.             'native': {  
  48.                 src: '<%= concat.native.dest %>',  
  49.                 dest: 'dist/template-native.js'  
  50.             },  
  51.             simple: {  
  52.                 src: '<%= concat.simple.dest %>',  
  53.                 dest: 'dist/template.js'  
  54.             }  
  55.         },  
  56.         qunit: {  
  57.             files: ['test/**/*.html']  
  58.         },  
  59.         jshint: {  
  60.             files: [  
  61.               'dist/template-native.js',  
  62.               'dist/template.js'  
  63.             ],  
  64.             options: {  
  65.                 curly: true,  
  66.                 eqeqeq: true,  
  67.                 immed: true,  
  68.                 latedef: true,  
  69.                 newcap: true,  
  70.                 noarg: true,  
  71.                 sub: true,  
  72.                 undef: true,  
  73.                 boss: true,  
  74.                 eqnull: true,  
  75.                 browser: true  
  76.             },  
  77.             globals: {  
  78.                 console: true,  
  79.                 define: true,  
  80.                 global: true,  
  81.                 module: true  
  82.             }  
  83.         },  
  84.         watch: {  
  85.             files: '<config:lint.files>',  
  86.             tasks: 'lint qunit'  
  87.         }  
  88.     });  
  89.   
  90.     grunt.loadNpmTasks('grunt-contrib-uglify');  
  91.     grunt.loadNpmTasks('grunt-contrib-jshint');  
  92.     //grunt.loadNpmTasks('grunt-contrib-qunit');  
  93.     //grunt.loadNpmTasks('grunt-contrib-watch');  
  94.     grunt.loadNpmTasks('grunt-contrib-concat');  
  95.   
  96.   
  97.     grunt.registerTask('default', ['concat', /*'jshint',*/ 'uglify']);  
  98.   
  99. };  

 

package.json

 

 

  1. {  
  2.   "name": "art-template",  
  3.   "description": "JavaScript Template Engine",  
  4.   "homepage": "http://aui.github.com/artTemplate/",  
  5.   "keywords": [  
  6.     "util",  
  7.     "functional",  
  8.     "template"  
  9.   ],  
  10.   "author": "tangbin <sugarpie.tang@gmail.com>",  
  11.   "repository": {  
  12.     "type": "git",  
  13.     "url": "git://github.com/aui/artTemplate.git"  
  14.   },  
  15.   "main": "./node/template.js",  
  16.   "version": "3.0.3",  
  17.   "devDependencies": {  
  18.     "express": "~4.4.3",  
  19.     "grunt-cli": "*",  
  20.     "grunt": "*",  
  21.     "grunt-contrib-jshint": "*",  
  22.     "grunt-contrib-concat": "*",  
  23.     "grunt-contrib-uglify": "*"  
  24.   },  
  25.   "license": "BSD"  
  26. }  

其他

[我的博客,欢迎交流!](http://rattenking.gitee.io/stone/index.html)

[我的CSDN博客,欢迎交流!](https://blog.csdn.net/m0_38082783)

[微信小程序专栏](https://blog.csdn.net/column/details/18335.html)

[前端笔记专栏](https://blog.csdn.net/column/details/18321.html)

[微信小程序实现部分高德地图功能的DEMO下载](http://download.csdn.net/download/m0_38082783/10244082)

[微信小程序实现MUI的部分效果的DEMO下载](http://download.csdn.net/download/m0_38082783/10196944)

[微信小程序实现MUI的GIT项目地址](https://github.com/Rattenking/WXTUI-DEMO)

[微信小程序实例列表](http://blog.csdn.net/m0_38082783/article/details/78853722)

[前端笔记列表](http://blog.csdn.net/m0_38082783/article/details/79208205)

[游戏列表](http://blog.csdn.net/m0_38082783/article/details/79035621)

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值