做前端项目,如果没有一个自动化构建工具,手动处理那简直就是坑爹O(∩_∩)O。于是上网了解了下,grunt用的人不少,功能也挺强大。看了一下grunt的配置(包括gulp),感觉稍显复杂。当时项目结构非常简单,就是单文件夹下的html文件,再加上js、css、图片。需要的功能也就js的合并和压缩,html和css的简单格式化,功能简单,So easy……开搞,搞定第一版,一直用到今年。最近整理项目,感觉只支持单一文件夹,功能全内置,实在不够灵活,于是重写了第二版。功能实现没什么难的,麻烦的是打造一个可扩展性良好的架构,要配置简单,任务流程完全自主配置,插件、执行顺序完全可控,文本还要能单独处理,最好能和任务一样配置、控制方便。终于搞定了!一个良好的架构真是很花时间和精力,大家推荐支持一下呗O(∩_∩)O
关于Qbuild.js(姑且这么叫之吧)
- 轻量高效,易于配置。支持js压缩、文件合并、格式化、复制和重命名等。
- 基于js的配置文件,支持自定义任务模块和文本处理,支持模块重用。
- 灵活的文件扫描规则,支持通配符(*和**),支持正则表达式,支持排除规则。
- 自动跳过未更新的文件,大大提升处理效率。
- 重命名文件时,自动更新文件引用(可配置)。
- 自定义输出目录,并保持文件引用(可配置)。
- 支持将通过 document.write 输出内容的js文件,直接将js引用替换为输出内容。
最后一点可能有人不了解,比如一个html网站,头部和尾部内容在很多html文件里是一样的,便于开发(避免变动一处要修改n个文件),可以将内容整合到js文件中,通过 document.write(html) 输出,而发布时却想将内容直接集成到html文件里(考虑到SEO优化、加载性能等),可以使用本工具实现。我承认这个功能比较蛋疼,可能很多人并不会用到,不过既然实现了,就放上来了,而且对后面实现文件重命名(比如js、css)后自动更新文件(比如html文件)引用有不少帮助。最重要的是全插件模式,任君配置。
先看下运行效果:
以下是 demo/index.html 文件的变化,输出文件夹为 release/www/index.html
第二次运行,仅修改 demo/index.html 文件,截取部分运行结果
如何使用
1. 安装Node.js和压缩工具(uglify或 Google Closure Compiler(需java支持))
2. 下载示例代码,将build文件夹放到你的项目中,配置好build.data.js,执行 node build/build.js (Windows 可直接运行 build.bat )
3. 示例配置见 build/build.data.js 和 demo/build/build.data.js ,2种不同的情况,可供参考
更多见 https://github.com/devin87/build.js
配置代码(build.data.js)
由于注释较多,默认折叠
1 //build 配置文件 2 module.exports = { 3 //根目录,默认为配置文件所在路径,所有目录均基于此目录 4 //绝对路径优先;若以./开头则基于配置文件路径(下同) 5 root: "../", 6 //输入目录,以下所有dir目录均基于此目录(若以/开头则直接基于根目录) 7 dir: "demo", 8 //输出目录,同上 9 output: "release", 10 11 //是否自动跳过未更新的文件 12 //若任务对象有同名属性,则以任务对象的值为主 eg: dir、output、skipOutput、autoSkip、enable、preload、rename、registerText、runText 13 autoSkip: true, 14 15 //不保存自定义存储数据 16 //noStore: false, 17 18 //文件重命名 19 //rename: "%f.name%.%date('yyyyMMddHHmm')%%f.ext%", 20 //清理上次生成的文件 21 //cleanDest: true, 22 23 //注册任务处理模块,基于根目录,默认导入./module/*.js 24 /*register: { 25 concat: "./module/concat.js", 26 format: "./module/format.js", 27 cmd: "./module/cmd.js", 28 29 //若处理程序相同,可重用已注册的模块 eg: copy:"format" 30 copy: "./module/copy.js" 31 },*/ 32 33 //注册文本处理模块,基于根目录,默认导入./module/text/*.js 34 //registerText: {}, 35 //registerText: "./module/text/*.js", 36 37 //默认执行的文本处理模块(按顺序执行),*表示其它模块 38 runText: ["replace", "before", "after", "*"], 39 40 //任务:文件合并 41 concat: { 42 title: "文件合并", 43 44 //指定要运行的文本模块和执行顺序 45 //runText: ["replace", "before", "after", "*"], 46 47 dir: "js/src", 48 output: "js-concat", 49 50 //可以简写为 {"src/a.js":["a/t1.js", "a/t2.js", "a/t3.js"]} 51 list: [ 52 { 53 dir: "a", 54 src: ["t1.js", "t2.js", "t3.js"], 55 dest: "src/a.js" 56 }, 57 { 58 dir: "b", 59 src: ["t1.js", "t2.js", "D:/t.js"], 60 dest: "src/b.js" 61 }, 62 { 63 //不从父级继承,以/开头直接基于root定义的目录 64 dir: "/release/js-concat/src", 65 src: ["a.js", "b.js"], 66 dest: "ab.js" 67 } 68 ], 69 70 //在文件内容之前添加文本,见 ./module/text/append.js 71 before: [ 72 "//build:%NOW% by Qbuild.js devin87@qq.com ", 73 74 //给不同文件追加不同文本,不适用有同名文件的情况 75 { 76 //其它文件追加的文本 77 "def": "//%f.fullname% ", 78 //ab.js追加的文本 79 "ab.js": "//a.js+b.js " 80 } 81 ], 82 83 //在文件内容之后添加文本,同上,见 ./module/text/append.js 84 after: [ 85 { 86 "ab.js": " //append after test!" 87 } 88 ], 89 90 replace: [ 91 //移除 字符,第一个参数可以是正则表达式或字符串,若是字符串,则需要指定第3个参数(正则表达式标记 eg:g、i、m或其组合) 92 [/ /g, ""], 93 //移除VS引用 94 [////s*<reference path="[^"]*" /> /gi, ""] 95 ], 96 97 //禁用文件重命名 98 rename: false 99 }, 100 101 //任务:文件格式化 102 format: [ 103 { 104 title: "格式化html文件", 105 //autoSkip: false, 106 107 //注册单独的文本处理模块 108 registerText: { 109 include: "./module/text/custom/document.write.js" 110 }, 111 112 //传给 document.write.js 的参数 113 include: "/demo/js/**(head|bottom).js", 114 115 //dir: "", 116 117 //一般output可省略,将自动保持原始文件夹结构 118 //output: "", 119 120 //要匹配的文件,可为数组 eg:["about/*.html", "m/*.html"] 121 //*可匹配斜杆之外的字符,2个*可匹配所有字符 122 match: "**.html", 123 //要排除的文件 124 exclude: "**.old.html", 125 126 //默认会优化匹配规则以加速扫描 eg:[ab]/*.js => { dir:"[ab]",match:"*.js" } 127 //若想在一些特殊情况下使用正则表达式,可以关闭优化 128 //matchOptimize: true, 129 130 replace: [ 131 //移除html注释 132 [/(<!--(?![ifs)([^~]|~)*?-->)/gi, ""], 133 //移除无效的空格或换行 134 [/(<div[^>]*>)[s ]+(</div>)/gi, "$1$2"], 135 //移除多余的换行 136 [/( ? )( ? )+/g, "$1"], 137 //移除首尾空格 138 [/^s+|s+$/, ""] 139 ] 140 }, 141 { 142 title: "格式化css文件", 143 //enable: false, 144 145 dir: "css", 146 match: "*.css", 147 148 replace: [ 149 //移除css注释 150 [//*([^~]|~)*?*//g, ""], 151 //移除多余的换行 152 [/( ? )( ? )+/g, "$1"], 153 //移除首尾空格 154 [/^s+|s+$/, ""] 155 ] 156 } 157 ], 158 159 //任务:调用命令行压缩js 160 cmd: [ 161 { 162 title: "压缩js", 163 164 //cmd: "java -jar D:\tools\compiler.jar --js=%f.fullname% --js_output_file=%f.dest%", 165 cmd: "uglifyjs %f.fullname% -o %f.dest% -c -m", 166 167 match: ["js/**.js", "m/js/**.js"], 168 exclude: "js/data/**.js|js/error.js", 169 170 replace: [ 171 //去掉文件头部压缩工具可能保留的注释 172 [/^/*([^~]|~)*?*//, ""] 173 ], 174 175 //可针对单一的文件配置 before、after,def 表示默认 176 before: [ 177 { 178 "def": "//devin87@qq.com ", 179 "Q.js": "//Q.js devin87@qq.com " 180 }, 181 "//build:%NOW% " 182 ] 183 } 184 ], 185 186 //任务:文件同步(复制) 187 copy: [ 188 { 189 title: "同步js数据", 190 dir: "js/data", 191 match: "**.js" 192 }, 193 { 194 title: "同步图片", 195 dir: "images", 196 match: "**" 197 } 198 ], 199 200 //要启动的任务,按顺序执行,不支持* 201 run: ["concat", "format", "cmd", "copy"] 202 };
代码下载
写在最后
由于图片较多,暂时先介绍到这。下次再介绍运行机制及插件的编写。
如果本文或本项目对您有帮助的话,请不吝点个赞。欢迎交流!