Gruntfile.js 13 KB

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