Gruntfile.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. module.exports = function(grunt) {
  2. 'use strict';
  3. require('load-grunt-tasks')(grunt);
  4. var path = require('path');
  5. var fs = require('fs');
  6. var pkg = require('./package');
  7. var proj_namespace = path.join(pkg.description, pkg.name, pkg.version, '/');
  8. var ASSETS_URL = 'http://assets.dwstatic.com/'+ proj_namespace;
  9. var ipAddress = require('network-address')();
  10. var get_files = require('grunt-ejs-static/lib/get_files').get_files,
  11. get_data = require('grunt-ejs-static/lib/data').get_data,
  12. get_layout = require('grunt-ejs-static/lib/layout').get_layout,
  13. render_file = require('grunt-ejs-static/lib/render').render_file,
  14. write_file = require('grunt-ejs-static/lib/write_file').write_file,
  15. get_helper_functions = require('grunt-ejs-static/lib/get_helper_functions').get_helper_functions,
  16. ejs_static = require('grunt-ejs-static/lib/ejs_static'),
  17. _ = require('grunt-ejs-static/node_modules/underscore'),
  18. middleware_directory = require('grunt-contrib-connect/node_modules/connect/lib/middleware/directory'),
  19. url = require('url');
  20. var renderTpl = function (req, res, next){
  21. var reqPathName = decodeURIComponent(url.parse(req.originalUrl).pathname),
  22. reqFileName = reqPathName.substring(reqPathName.lastIndexOf('/')+1),
  23. localPathName = path.resolve('src/', reqPathName.substring(1)),
  24. renderedFile;
  25. fs.readFile(localPathName, function(err, file) {
  26. if (err) {return next();}
  27. var options = {
  28. path_to_data: 'src/data/config.json',
  29. file_extension: '.html',
  30. underscore: true
  31. },
  32. config_cover = ejs_static.get_files(options),
  33. config_default = {},
  34. htmlfiles; // local html file array
  35. fs.readdir(path.resolve('src/'), function(err, arr) {
  36. if (err) {console.log(err)}
  37. htmlfiles = _.filter(arr, function(item) {
  38. return item.lastIndexOf('.html') !== -1;
  39. });
  40. htmlfiles = _.map(htmlfiles, function(item) {
  41. return item.substring(0, item.lastIndexOf('.html'));
  42. });
  43. // cover config_default by config_cover
  44. _.each(htmlfiles, function(item) {
  45. config_default[item] = {};
  46. config_default[item]['path_to_layout'] = (config_cover[item] && config_cover[item]['path_to_layout']) || 'src/' + item + '.html';
  47. config_default[item]['path_to_data'] = (config_cover[item] && config_cover[item]['path_to_data']) || ["src/data/global.json"];
  48. });
  49. // rewrite config.json
  50. // fs.writeFile(path.resolve(__dirname, options.path_to_data), JSON.stringify(config_default, null, 4), function (err) {
  51. // if (err) throw err;
  52. // });
  53. Object.keys(config_default).forEach(function(key) {
  54. if (reqFileName === key + options.file_extension) {
  55. var fileData = ejs_static.get_data(key, config_default);
  56. var layoutData = ejs_static.get_layout(key, config_default, options);
  57. renderedFile = ejs_static.render_file(layoutData, fileData, _.extend({}, _));
  58. }
  59. });
  60. res.end(renderedFile || file);
  61. });
  62. });
  63. };
  64. grunt.initConfig({
  65. // 全局变量
  66. banner: '/*! Project: '+pkg.name+'\n * Version: '+pkg.version+'\n * Date: <%= grunt.template.today("yyyy-mm-dd hh:MM:ss TT") %>\n * Author: '+pkg.author.name+'\n */',
  67. connect: {
  68. site_src: {
  69. options: {
  70. hostname: ipAddress,
  71. port: 9000,
  72. base: ['src/'],
  73. livereload: true,
  74. open: true, //打开默认浏览器
  75. middleware: [
  76. function(req, res, next){
  77. return renderTpl(req,res,next);
  78. },
  79. middleware_directory(path.resolve('src/'))
  80. ]
  81. }
  82. },
  83. site_dest: {
  84. options: {
  85. hostname: ipAddress,
  86. port: 9001,
  87. base: ['dest/'],
  88. livereload: true,
  89. keepalive: true, //保持sever不退出
  90. open: true //打开默认浏览器
  91. }
  92. }
  93. },
  94. cssmin: {
  95. options: {
  96. banner: '<%= banner %>'
  97. },
  98. minify: {
  99. expand: true,
  100. cwd: 'dest/css',
  101. src: ['*.css', '!*.min.css'],
  102. dest: 'dest/css',
  103. ext: '.css'
  104. }
  105. },
  106. uglify: {
  107. options: {
  108. banner: '<%= banner %>',
  109. mangle: true
  110. },
  111. dist: {
  112. files: [{
  113. expand: true,
  114. cwd: 'dest/js',
  115. src: '**/*.js',
  116. dest: 'dest/js'
  117. }]
  118. }
  119. },
  120. clean: {
  121. build: ["dest"],
  122. release: ["dest/slice", "dest/data", "dest/partial"],
  123. zip: ["assets"],
  124. svn: [".tmp_svn"]
  125. },
  126. copy: {
  127. release: {
  128. expand: true,
  129. cwd: 'src/',
  130. src: ['**', '!sass', '!sass/{,*/}*', '!css/*.map', '!img/psd','!img/psd/{,*/}*'],
  131. dest: 'dest/'
  132. },
  133. zip_dest: {
  134. expand: true,
  135. cwd: 'dest/',
  136. src: ['js/{,*/}*', 'img/{,*/}*', 'css/*'],
  137. dest: 'assets/dest'
  138. },
  139. zip_src: {
  140. expand: true,
  141. cwd: 'src/',
  142. src: ['**', '!sass', '!sass/{,*/}*', '!css/*.map', '!img/psd','!img/psd/{,*/}*'],
  143. dest: 'assets/src'
  144. }
  145. },
  146. autoprefixer: {
  147. options: {
  148. browsers: ['> 1%', 'last 2 versions', 'ff 17', 'opera 12.1', 'ie 8']
  149. },
  150. dist: {
  151. expand: true,
  152. flatten: true,
  153. src: 'src/css/*.css',
  154. dest: 'src/css/'
  155. }
  156. },
  157. watch: {
  158. css: {
  159. files: ['src/sass/{,*/}*.scss'],
  160. tasks:['sass']
  161. },
  162. livereload: {
  163. options: {
  164. livereload: true
  165. },
  166. files: ['src/*.html', 'src/css/*.css', 'src/js/*.js', 'src/partial/*.ejs', 'src/data/*.json']
  167. }
  168. },
  169. imagemin: {
  170. options: {
  171. pngquant: true
  172. },
  173. dist: {
  174. files: [{
  175. expand: true,
  176. cwd: 'dest/img/',
  177. src: ['**/*.{png,jpg,jpeg}'], // 优化 img 目录下所有 png/jpg/jpeg 图片
  178. dest: 'dest/img/' // 优化后的图片保存位置,覆盖旧图片,并且不作提示
  179. }]
  180. }
  181. },
  182. adisprite: {
  183. all: {
  184. srcCss: 'dest/css',
  185. srcImg: 'dest/slice',
  186. destCss: 'dest/css',
  187. destImg: 'dest/img/sprite',
  188. 'padding': 5,
  189. 'algorithm': 'binary-tree',
  190. 'engine': 'gm',
  191. 'exportOpts': {
  192. 'format': 'png',
  193. 'quality': 90
  194. }
  195. }
  196. },
  197. sass: {
  198. dist: {
  199. options: {
  200. style: 'compact', //nested, compact, compressed, expanded
  201. sourcemap: true,
  202. noCache: true
  203. },
  204. files: [{
  205. expand: true,
  206. cwd: 'src/sass',
  207. src: ['*.scss','!_*.scss','!*/_*.scss'],
  208. dest: 'src/css',
  209. ext: '.css'
  210. }]
  211. }
  212. },
  213. ejs_static: {
  214. release:{
  215. options: {
  216. dest: 'dest/',
  217. path_to_data: 'dest/data/config.json',
  218. path_to_layouts: 'dest/',
  219. underscores_to_dashes: false,
  220. file_extension: '.html',
  221. underscore: true
  222. }
  223. }
  224. },
  225. concat: {
  226. trans_html: {
  227. options: {
  228. process: function(src, filepath) {
  229. var regex = /((href|src)=['"][\s]*)(?!http[s]?\:|\#|\/)([\?\#\=\/\w._-]*)([\s]*['"])/g;
  230. return src.replace(regex, '$1'+ASSETS_URL+'$3$4');
  231. }
  232. },
  233. files: [{
  234. expand: true,
  235. cwd: 'dest/',
  236. src: '*.html',
  237. dest: 'assets/dest/'
  238. }]
  239. }
  240. },
  241. compress: {
  242. zip: {
  243. options:{
  244. archive: 'assets.zip'
  245. },
  246. files: [{
  247. expand: true,
  248. cwd: 'assets/',
  249. src: '**'
  250. }]
  251. }
  252. },
  253. push_svn: {
  254. options: {
  255. message: '初始化项目:' + pkg.name,
  256. username: 'liujianxin',
  257. password: 'g2551',
  258. trymkdir: true
  259. },
  260. work: {
  261. src: './',
  262. dest: 'http://svn.duowan.com:9999/svn/design/work/' + __dirname.substring(__dirname.indexOf('/work/')+5),
  263. tmp: '.tmp_svn'
  264. },
  265. assets: {
  266. src: 'dest',
  267. dest: 'http://svn.duowan.com:9999/svn/web/program/assets/' + proj_namespace,
  268. tmp: '.tmp_svn'
  269. }
  270. }
  271. });
  272. // 默认任务
  273. grunt.registerTask('default', ['connect:site_src', 'watch']);
  274. // 自定义端口
  275. grunt.task.registerTask('port', 'multi port', function(arg) {
  276. if(arguments.length === 0){
  277. console.log('端口号不能为空!')
  278. }else{
  279. grunt.config.set('connect.port'+arg,{
  280. options: {
  281. hostname: ipAddress,
  282. port: arg,
  283. base: ['src/'],
  284. livereload: true,
  285. open: true,
  286. middleware: [
  287. function(req, res, next){
  288. return renderTpl(req,res,next);
  289. },
  290. middleware_directory(path.resolve('src/'))
  291. ]
  292. }
  293. });
  294. grunt.config.set('watch.livereload',{
  295. options: {
  296. livereload: arg+1
  297. },
  298. files: ['src/*.html', 'src/css/*.css', 'src/js/*.js']
  299. })
  300. grunt.task.run(['connect:port'+arg, 'watch']);
  301. }
  302. });
  303. // webserver 查看发布目录
  304. grunt.registerTask('dest', ['connect:site_dest']);
  305. // 发布任务
  306. grunt.registerTask('release', ['sass', 'clean:build', 'copy:release', 'adisprite', 'cssmin', 'uglify', 'imagemin', 'ejs_static:release', 'clean:release', 'connect:site_dest']);
  307. // release后,zip打包
  308. grunt.registerTask('zip',['copy:zip_src', 'copy:zip_dest', 'concat:trans_html', 'compress', 'clean:zip']);
  309. // 提交src和配置文件到工作svn
  310. grunt.task.registerTask('work', 'commit message', function(arg) {
  311. grunt.config.merge({
  312. push_svn:{
  313. options: {
  314. message: arg,
  315. pushIgnore: ['dest/**', '.DS_Store', '.idea/**', 'node_modules/**', '.tmp_svn/**', '.svn/**'],
  316. remove: true
  317. }
  318. }
  319. })
  320. grunt.task.run(['push_svn:work', 'clean:svn']);
  321. });
  322. // 提交dest到静态文件svn
  323. grunt.task.registerTask('assets', 'commit message', function(arg) {
  324. grunt.config.merge({
  325. push_svn:{
  326. options: {
  327. message: arg,
  328. pushIgnore: ['*.html', '.DS_Store', '.idea/**', '.tmp_svn/**', '.svn/**']
  329. }
  330. }
  331. })
  332. grunt.task.run(['push_svn:assets', 'clean:svn']);
  333. });
  334. };