zoukankan      html  css  js  c++  java
  • 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 = //*[wW]*?*/|//[^ ]* |//[^ ]*$|"(?:[^"\]|\[wW])*"|'(?:[^'\]|\[wW])*'|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(/ /g, '\r')  
    119.     .replace(/ /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(/ /).length - 1;  
    215.   
    216.         // 压缩多余空白与注释  
    217.         if (compress) {  
    218.             code = code  
    219.             .replace(/s+/g, ' ')  
    220.             .replace(/<!--[wW]*?-->/g, '');  
    221.         }  
    222.           
    223.         if (code) {  
    224.             code = replaces[1] + stringify(code) + replaces[2] + " ";  
    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(/ /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 + " ";  
    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$]*)(.*)/); // 单词边界符  
    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 ';  
    8.     for (var name in e) {  
    9.         message += '<' + name + '> ' + e[name] + ' ';  
    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 %>*/ '  
    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)

  • 相关阅读:
    Developers’ Musthave: the new Microsoft AllInOne Code Framework Sample Browser and 3500+ samples
    8774
    DCOM
    9个最棒的代码片段资源网站
    WCF中的几种地址总结
    如何用C#编写DCOM服务器
    C++ DCOM服务器和C#客户端互操作完全解释
    理解Prism中MVVM的Command与CommandParameter
    WCF REST 基础教程
    细说ASP.NET Forms身份认证
  • 原文地址:https://www.cnblogs.com/linewman/p/9918572.html
Copyright © 2011-2022 走看看