做前端项目,如果没有一个自动化构建工具,手动处理那简直就是坑爹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: "", 8 //输出目录,同上 9 output: "release", 10 11 //是否自动跳过未更新的文件 12 //若任务对象有同名属性,则以任务对象的值为主 eg: dir、output、skipOutput、autoSkip、enable、preload、rename、registerText、runText 13 autoSkip: true, 14 15 //重命名规则 16 rename: "%f.name%.%date(‘yyyyMMddHHmm‘)%%f.ext%", 17 cleanRename: true, 18 19 //注册任务处理模块,基于根目录 20 register: { 21 concat: "./module/concat.js", 22 format: "./module/format.js", 23 cmd: "./module/cmd.js", 24 25 //若处理程序相同,可重用已注册的模块 eg: copy:"format" 26 copy: "./module/copy.js" 27 }, 28 29 //注册文本处理模块,基于根目录 30 //registerText: {}, 31 registerText: "./module/text/*.js", 32 33 //默认执行的文本处理模块(按顺序执行),*表示其它模块 34 runText: ["replace", "before", "after", "*"], 35 36 //任务:文件合并 37 concat: { 38 title: "文件合并", 39 40 dir: "js/src", 41 output: "/js", 42 43 //可以简写为 {"src/a.js":["a/t1.js", "a/t2.js", "a/t3.js"]} 44 list: [ 45 { 46 dir: "a", 47 src: ["t1.js", "t2.js", "t3.js"], 48 dest: "src/a.js" 49 }, 50 { 51 dir: "b", 52 src: ["t1.js", "t2.js", "D:/t.js"], 53 dest: "src/b.js" 54 }, 55 { 56 src: ["a.js", "b.js"], 57 dest: "ab.js" 58 } 59 ], 60 61 //在文件内容之前添加文本,见 ./module/text/append.js 62 before: [ 63 "//build:%NOW% by Qbuild.js [email protected]\n", 64 65 //给不同文件追加不同文本,不适用有同名文件的情况 66 { 67 //其它文件追加的文本 68 "def": "//%f.fullname%", 69 //ab.js追加的文本 70 "ab.js": "//a.js+b.js\n" 71 } 72 ], 73 74 //在文件内容之后添加文本,同上,见 ./module/text/append.js 75 after: [ 76 { 77 "ab.js": "\n//append after test!" 78 } 79 ], 80 81 replace: [ 82 //移除\r字符,第一个参数可以是正则表达式或字符串,若是字符串,则需要指定第3个参数(正则表达式标记 eg:g、i、m或其组合) 83 [/\r/g, ""], 84 //移除VS引用 85 [/\/\/\/\s*<reference path="[^"]*" \/>\n/gi, ""] 86 ], 87 88 //禁用文件重命名 89 rename: false 90 }, 91 92 //任务:文件格式化 93 format: { 94 title: "格式化html文件", 95 //autoSkip: false, 96 rename: false, 97 98 //注册单独的文本处理模块,|开头表示程序所在目录 99 registerText: { 100 include: "|./module/text/custom/document.write.js", 101 rename_link: "|./module/text/custom/rename_link.js" 102 }, 103 104 include: "/**(head|bottom).js", 105 106 //可配置引用匹配规则 107 //rename_link: { 108 // match: /<(script|link|img)[^>]+?(src|href)=([‘"])([^>]+?)\3[^>]*>/ig, 109 // index: 4 110 //}, 111 112 runText: ["replace", "before", "after", "include", "rename_link"], 113 114 //要扫描的目录,可为数组,默认只扫描当前目录下的文件,若要扫描子孙目录,请使用*或** 115 //扫描根目录下所有子目录 eg:/* 116 //扫描根目录下所有子孙目录(包括子目录的子目录等) eg:/** 117 //dir: ["ab*/*", "m"], 118 119 //一般output可省略,将自动保持原始文件夹结构 120 output: "www", 121 122 //要匹配的文件,支持正则表达式 eg: (*|/demo/**).html 123 //*可匹配斜杆之外的字符,2个*可匹配所有字符 124 match: "**.html", 125 //要排除的文件 126 exclude: "**.old.html", 127 128 replace: [ 129 //移除html注释 130 [/(<!--(?!\[if\s)([^~]|~)*?-->)/gi, ""], 131 //移除空script标签 132 [/\s*<script(\s+type="[^"]+")?>\s*?<\/script>/gi,""], 133 //移除无效的空格或换行 134 [/(<div[^>]*>)[\s\r\n]+(<\/div>)/gi, "$1$2"], 135 //移除多余的换行 136 [/(\r?\n)(\r?\n)+/g, "$1"], 137 //移除首尾空格 138 [/^\s+|\s+$/, ""] 139 ] 140 }, 141 format0: { 142 title: "格式化css文件", 143 //enable: false, 144 145 dir: "css", 146 match: "*.css", 147 148 replace: [ 149 //移除css注释 150 [/\/\*([^~]|~)*?\*\//g, ""], 151 //移除多余的换行 152 [/(\r?\n)(\r?\n)+/g, "$1"], 153 //移除首尾空格 154 [/^\s+|\s+$/, ""] 155 ] 156 }, 157 158 //任务:调用命令行压缩js 159 cmd: [ 160 { 161 title: "压缩js", 162 163 dir: ["js", "m/js"], 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", 168 exclude: "data/**.js", 169 170 replace: [ 171 //去掉文件头部压缩工具可能保留的注释 172 [/^\/\*([^~]|~)*?\*\//, ""] 173 ], 174 175 //可针对单一的文件配置 before、after,def 表示默认 176 before: [ 177 { 178 "def": "//[email protected]\n", 179 "Q.js": "//Q.js [email protected]\n" 180 }, 181 "//build:%NOW%\n" 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 //由于js、css进行了重命名,更新html引用需依赖这两项,所以先执行js压缩和css格式化 202 run: ["concat", "cmd", "format0", "format", "copy"] 203 };
代码下载
写在最后
由于图片较多,暂时先介绍到这。下次再介绍运行机制及插件的编写。
如果本文或本项目对您有帮助,请不吝点个赞。如果有什么意见或建议,欢迎交流!