首页 > 网站 > WEB开发 > 正文

grunt配置太复杂?使用Qbuild进行文件合并、压缩、格式化等处理

2024-04-27 14:06:59
字体:
来源:转载
供稿:网友
grunt配置太复杂?使用Qbuild进行文件合并、压缩、格式化等处理

上次简单介绍了下Qbuild的特点和配置,其实实现一个自动化工具并不复杂,往简单里说,无非就是筛选文件和处理文件。但Qbuild的源码也并不少,还是做了不少工作的。

1. 引入了插件机制。在Qbuild中称作模块,分为任务处理模块(如合并、压缩等处理)和文本处理模块(如内容添加和替换等处理),一个任务处理模块可以有多个文本处理模块。任务和文本处理模块均可以按指定的顺序执行,可以指定要执行的模块。每个任务的配置可以继承或覆盖全局配置,既保证了简洁,也保证了灵活。2. 文件筛选支持通配符(*和**)和正则表达式,支持排除规则。支持基于文件夹定位。支持文件变动检测,跳过未更新的文件,大大提升处理效率。3. 模块路径和文件夹路径支持绝对路径,支持基于配置文件所在路径(以./开头),支持基于自定义的根目录(以/开头,全局root配置),支持基于程序所在路径(以|开头)。4. 支持简单的参数引用和函数调用。eg:以下f为文件对象,仅列出部分属性 f: {dir,dest,fullname,filename:"test.js",name:"test",ext:".js",stat:{size:165346}} %Q.formatSize(f.stat.size)% =>Q.formatSize(165346) =>161.47KB %f.filename.toUpperCase().replace('.','$&parsed.')% => TEST.parsed.JS5. 提供简单易用的api,以简化插件编写。

下面分别介绍每个功能的使用。

文件合并

配置文件位于 build-demo/test 目录,下同。t-error.js 实际并不存在,此为演示异常情况。

 1 module.exports = { 2     root: "../", 3  4     concat: { 5         title: "文件合并", 6  7         dir: "demo/js/src", 8         output: "release/js-concat", 9 10         list: [11             {12                 dir: "a",13                 src: ["t1.js", "t2.js", "t3.js"],14                 dest: "a.js",15                 PRefix: "//----------- APPEND TEST (%f.filename%) -----------/n"16             },17             {18                 dir: "b",19                 src: ["t1.js", "t2.js", "t-error.js"],20                 dest: "b.js"21             },22             {23                 //不从父级继承,以/开头直接基于root定义的目录24                 dir: "/release/js-concat",25                 src: ["a.js", "b.js"],26                 dest: "ab.js"27             }28         ]29     }30 };

js压缩

调用命令行来执行js压缩。error.js 演示js代码异常的情况。现在压缩工具一般都带语法检测,可以方便的定位错误信息。

 1 module.exports = { 2     dir: "../demo", 3     output: "../release", 4  5     cmd: { 6         title: "压缩js", 7         //cmd: "java -jar D://tools//compiler.jar --js=%f.fullname% --js_output_file=%f.dest%", 8         cmd: "uglifyjs %f.fullname% -o %f.dest% -c -m", 9 10         match: "js/*.js",11         exclude: "js/error.js",12 13         before: "//build:%NOW%/n"14     }15 };

文件格式化

任务模块(format.js)并不直接执行html和CSS的格式化,而是调用文本处理模块(replace.js)来执行一些常规替换。

 1 module.exports = { 2     dir: "../demo", 3     output: "../release", 4  5     format: [ 6         { 7             title: "格式化html文件", 8  9             match: "*.html",10             exclude: "**.old.html",11 12             replace: [13                 //移除html注释14                 [/(<!--(?!/[if/s)([^~]|~)*?-->)/gi, ""],15                 //移除无效的空格或换行16                 [/(<div[^>]*>)[/s/r/n]+(<//div>)/gi, "$1$2"],17                 //移除多余的换行18                 [/(/r?/n)(/r?/n)+/g, "$1"],19                 //移除首尾空格20                 [/^/s+|/s+$/, ""]21             ]22         },23         {24             title: "格式化css文件",25 26             match: "css/*.css",27 28             replace: [29                 //移除css注释30                 [////*([^~]|~)*?/*///g, ""],31                 //移除多余的换行32                 [/(/r?/n)(/r?/n)+/g, "$1"],33                 //移除首尾空格34                 [/^/s+|/s+$/, ""]35             ]36         }37     ]38 };

文件同步(复制)

 1 module.exports = { 2     dir: "../demo", 3     output: "../release", 4  5     copy: [ 6         { 7             title: "同步js数据", 8             match: "js/data/**.js" 9         },10         {11             title: "同步图片",12             match: "images/**"13         }14     ]15 };

插件(模块)编写

1. 了解文件对象。每个任务流程可以有多个任务对象(如上文的文件格式化和复制),除文件合并较特殊(姑且称之为list模式,传入的对象均有src属性,可以传入多个文件路径,但不支持通配符和正则表达式),其它都一样(暂称为match模式,支持通配符和正则表达式)。list模式下,每个对象是一个文件对象;match模式下每个文件是一个文件对象。下面是它们的属性。

1> match模式

 1 { 2     dir,         //文件所在目录 3     destname,    //默认文件保存路径 4     dest,        //文件实际保存路径 5     fullname,    //文件完整路径 6     relname,     //相对于 config.dir 的路径 7     filename,    //文件名(带扩展名) 8     name,        //文件名(不带扩展名) 9     ext,         //文件扩展名10     stat,        //文件状态(最后访问时间、修改时间、文件大小等) {atime,mtime,size}11     12     skip,        //是否跳过文件13     14     //仅当启用重命名时15     rename,      //新文件名称(带扩展名)16     last_dest    //文件上次构建时的保存路径17 };

2> list模式

 1 { 2     dir,         //文件所在目录(for src) 3     destname,    //文件保存路径 4     dest,        //同destname 5     fullname,    //同destname 6     filename,    //文件名(带扩展名) 7     name,        //文件名(不带扩展名) 8     ext,         //文件扩展名 9     src,         //文件路径列表10     11     skip,        //是否跳过文件12     13     //仅对concat.js生效14     join,        //文件连接字符串15     prefix       //要在合并文件头部添加的内容(concat.js内部支持,不同于文本模块append.js)16 };

2. 提供的api,已注册到全局变量,支持直接调用。

 1 global.Qbuild = { 2     ROOT,        //配置文件所在目录,与config.root不同 3     ROOT_EXEC,   //文件执行路径,即build.js所在路径 4  5     config,      //配置对象 6      7     HOT,         //红色输出,用于print和log,下同 8     GREEN,       //绿色输出 9     YELLOW,      //黄色输出10     PINK,        //粉红色输出11 12     print:function (msg,color),  //输出控制台信息,不换行,可指定输出颜色13     log:function (msg,color),    //输出控制台信息并换行,可指定输出颜色14     error:function (msg),       //输出错误信息,默认黄色15 16     //注册模块17     //type:String|Array|Object18     //     String:模块类型 eg: register("concat",fn|object)19     //     Array: 模块数组 eg: register([module,module],bind)20     //     Object:模块对象 eg: register({type:module},bind)21     //module:模块方法或对象,当为function时相当于 { exec:fn } ,若type为模块数组或对象,则同bind22     //bind:文本模块绑定对象(文本模块只在此对象上生效),可以传入一个空对象以注册一个全局文本模块23     register: function (type, module, bind),24 25     //创建路径筛选正则表达式,将默认匹配路径的结束位置26     //pattern: 匹配规则,点、斜杠等会被转义,**表示所有字符,*表示斜杠之外的字符 eg: demo/**.html27     //isdir: 是否目录,若为true,将匹配路径的起始位置28     getPathRegex: function (pattern, isdir),29 30     //获取匹配的文件,默认基于config.root31     //pattern:匹配规则,支持数组 eg:["js/**.js","m/js/**.js"]32     //ops:可指定扫描目录、输出目录、排除规则、扫描时是否跳过输出目录 eg:{ dir:"demo/",output:"release/",exclude:"**.old.js",skipOutput:true }33     getFiles: function (pattern, ops) ,34     //获取相对路径,默认相对于config.dir35     getRelname: function (fullname, rel_dir),36     //获取不带扩展名的名称37     getNameWithoutExt: function (name),38     //设置文件变更 => map_dest[f.destname.toLowerCase()]={src: f.fullname, dest: f.dest}39     setChangedFile: function (f),40     //获取输出路径映射,返回 { map: map_dest, last: map_last_dest }41     getDestMap: function (),42     //确保文件夹存在43     mkdir: function (dir),44     //读取文件内容(f[read_key] => f.text),read_key 默认为fullname45     readFile: function (f, callback, read_key),46     //保存文件(f.text => f.dest)47     saveFile: function (f, callback),48 49     //简单文本解析,支持属性或函数的连续调用,支持简单参数传递,若参数含小括号,需用@包裹 eg:%Q.formatSize@(f.stat.size,{join:'()'})@%50     //不支持函数嵌套 eg:path.normalize(path.dirname(f.dest))51     //eg:parse_text("%f.name.trim().drop@({a:'1,2',b:'(1+2)'})@.toUpperCase()% | %Q.formatSize(f.stat.size).split('M').join(' M')%", { dest: "aa/b.js", name: "b.js", size: 666, stat: { size: 19366544 } })  => B.JS | 18.47 MB52     //eg:parse_text("%path.dirname(f.dest)%", { dest: "aa/b.js"});  => aa53     parseText: function (text, f),54 55     //执行命令行调用56     shell: function (cmd, callback),57 58     //运行文本处理模块59     runTextModules: function (f, task),60 61     //设置检测函数,检查文件是否需要更新62     setCheck: function (task, check),63 64     //自定义存储操作,文件默认为build.store.json65     store: {66         init: function (callback),   //读取json数据并解析67         get: function (key),68         set: function (key, value),69         save: function (callback)   //保存json数据到文件70     }71 };

3. 任务处理模块格式

 1 module.exports = { 2     //模块类型,即任务属性名称,可以为数组 3     type:"concat", 4      5     //可选,任务初始化时触发 6     //task:任务对象  => config[module.type] 7     init: function (task), 8      9     //可选,文件预处理函数10     check: function (f, task),11     12     //可选,任务处理完毕触发(仅对exec有效)13     after: function (task),14     15     //文件处理函数(针对单个文件)16     exec: function (f, task, callback),17     18     //文件处
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表