grunt之dev-pro环境切换

在项目开发过程中和发布阶段需要在开发环境(dev)和生产环境(pro)之间切换,静态文件引用的切换等等。

使用grunt要如何解决上述问题,这里提供一个案列供参考。

用到的grunt插件:

文件合并:grunt-contrib-concat

javascript压缩:grunt-contrib-uglify

css 压缩:grunt-css

临时文件清理:grunt-contrib-clean

javascript代码检测:grunt-contrib-jshint

文件替换插件:grunt-string-replace

根据内容是否变化生成有哈希值文件名插件:grunt-rev

插件的具体用法可以到npm官网查看:https://www.npmjs.org/

在dev与pro之间切换的时候我们需要把页面上引用的未压缩合并的静态文件(A)和压缩合并后的文件(B)进行对应的切换操作,并且当文件内容改变后需要重新生成新的压缩合并文件用来处理cdn缓存问题。

考虑到随时可以进行环境切换所以项目中静态文件保留两份A和B,

在view页面上引入静态文件的地方加上标记用来方便查找切换,比如:

<!-- grunt-import-css bootstripCss -->

<link href="/Css/dest/603d3616.bootstrip.min.css" rel="stylesheet" />



<!--/grunt-import -->



<!-- grunt-import-js mainJs -->

<script src="/Js/dest/3e083a76.main.min.js"></script>

<!--/grunt-import -->

标记自己配置的,只要方便查找就行。

在切换的时候遍历对应的文件夹里面所有的文件,查找文件里面出现匹配的标记,然后替换。(我这里用的是grunt-string-replace插件 ,也有类似其他的插件)

从dev切换到pro的时候需要检测压缩和的文件内容是否变化,变化了就生成对应的新的文件。

Gruntfile.js文件:

  1 module.exports = function(grunt) {

  2     var fs = require('fs');

  3 

  4     // 配置

  5     var isDev = false;   //is develop

  6 

  7     var cssLink = '<link href="importUrl" rel="stylesheet" />',

  8         jsLink = '<script src="importUrl"><\/script>';

  9     //视图文件路径

 10     var viewPath = 'Views';

 11     //dev、pro环境对应静态文件关联配置

 12     var staticConfig = {

 13         'bootstripCss':{

 14             dev:[

 15                 'Css/bootstrap.css',

 16                 'Css/font-awesome.min.css'

 17             ],

 18             pro:'Css/dest/bootstrip.min.css'

 19         },

 20         'IEhtml5Js':{

 21             dev:[

 22                 'Js/html5shiv.js',

 23                 'Js/respond.min.js'

 24             ],

 25             pro:'Js/dest/IEhtml5Js.min.js'

 26         },

 27         'mainJs':{

 28             dev:['Js/Common.js',Js/main.js'],

 29             pro:'/Js/dest/main.min.js'

 30         }

 31     };

 32 

 33     //concatConfig合并配置  uglifyJsConfig js压缩配置  cssminConfig css压缩配置

 34     var concatConfig = {}, uglifyJsConfig = {}, cssminConfig = {};

 35     var fileType = 'js';

 36     var proFiles = [];  //所有生产环境文件

 37     for(var i in staticConfig){

 38         if(/css$/i.test(i)){

 39             fileType = 'css';

 40         }else if(/js$/i.test(i)){

 41             fileType = 'js';

 42         }

 43         proFiles.push(staticConfig[i]['pro']);

 44         //配置合并的文件

 45         concatConfig[i] = {

 46             'files' : {}  //{a:[b,c]} 目标文件,源文件

 47         };

 48         if(staticConfig[i]['options']){

 49             //合并配置项

 50             concatConfig[i]['options'] = staticConfig[i]['options'];

 51         }

 52         //合并的文件临时存放目录tmp

 53         concatConfig[i]['files']['tmp/concat/'+i+'.'+fileType] = staticConfig[i]['dev'].concat([]);

 54         //js 压缩

 55         if(fileType == 'js'){

 56             uglifyJsConfig[i] = {

 57                 'files' : {}  //{a:[b,c]} 目标文件,源文件

 58             };

 59             uglifyJsConfig[i]['files'][staticConfig[i]['pro']] = ['tmp/concat/'+i+'.'+fileType];

 60             if(staticConfig[i]['options']){

 61                 //压缩配置项

 62                 uglifyJsConfig[i]['options'] = staticConfig[i]['options'];

 63             }else{

 64                 uglifyJsConfig[i]['options'] = {

 65                     banner : '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'

 66                 }

 67             }

 68         }else if(fileType == 'css'){

 69             //css 压缩

 70             cssminConfig[i] = {

 71                 'files' : {}  //{a:[b,c]} 目标文件,源文件

 72             };

 73             cssminConfig[i]['files'][staticConfig[i]['pro']] = ['tmp/concat/'+i+'.'+fileType];

 74             if(staticConfig[i]['options']){

 75                 //压缩配置项

 76                 cssminConfig[i]['options'] = staticConfig[i]['options'];

 77             }

 78         }

 79     }

 80     //获取对应路径里的文件

 81     function getFileInfoFn(path){

 82         var fileInfo = [],

 83             files = fs.readdirSync(path);

 84         files.forEach(function(item) {

 85             var tmpPath = path + '/' + item;

 86             var stat = fs.lstatSync(tmpPath);

 87             if (!stat.isDirectory()){

 88                 fileInfo.push({'file':tmpPath,'cTime':fs.statSync(tmpPath).ctime})

 89             } else {

 90                 fileInfo = fileInfo.concat(getFileInfoFn(tmpPath));

 91             }

 92         });

 93         return fileInfo;

 94     }

 95 

 96     //视图文件

 97     var viewFiles = getFileInfoFn(viewPath);

 98     //replaceConfig 在切换dev、pro环境时需要替换文件路径的视图文件配置

 99     //gruntImportReg  替换的正则

100     var gruntImportReg = /<!--\s*grunt-import-\w+\s+\w+\s*-->[\s\S]*?<!--\s*\/grunt-import\s*-->/ig;

101     var gruntImportItemReg = /(<!--\s*grunt-import-(\w+)\s+(\w+)\s*-->)([\s\S]*?)(<!--\s*\/grunt-import\s*-->)/i;

102     var replaceConfig = {

103         'dist':{

104             options: {

105                 replacements: [

106                     {

107                         pattern: gruntImportReg,

108                         replacement: function(matchStr){

109                             //搜索合并压缩的最新文件

110                             var fileInfo = getFileInfoFn('/Js/dest').concat(getFileInfoFn('Css/dest'));

111                             fileInfo = fileInfo.sort(function(a, b){

112                                 return a['cTime'] - b['cTime'];

113                             })

114                             for(var i in staticConfig){

115                                 var proFile = staticConfig[i]['pro'].split('/');

116                                 proFile = proFile[proFile.length -1].replace(/\./g,'\\.');

117                                 fileInfo.forEach(function(v, k){

118                                     if(new RegExp("\\."+proFile).test(v['file'])){

119                                         staticConfig[i]['pro'] = v['file'];

120                                         return false;

121                                     }

122                                 })

123                             }

124 

125                             gruntImportItemReg.lastIndex = 0;

126                             var matchItem = matchStr.match(gruntImportItemReg);

127                             var files = [], importLink = '',

128                                 ret = matchItem[1]+'\n';

129                             if(isDev){

130                                 files = staticConfig[matchItem[3]]['dev'];

131                             }else{

132                                 files = [staticConfig[matchItem[3]]['pro']];

133                             }

134                             if(matchItem[2] == 'js'){

135                                 importLink = jsLink;

136                             }else if(matchItem[2] == 'css'){

137                                 importLink = cssLink;

138                             }

139                             files.forEach(function(v, k){

140                                 ret += importLink.replace('importUrl', v);

141                                 ret += '\n';

142                             });

143                             ret += matchItem[5];

144                             return ret;

145                         }

146                     }

147                 ]

148             },

149             files:{}

150         }

151     };

152     viewFiles.forEach(function(v, k){

153         replaceConfig['dist']['files'][v['file']] = v['file'];

154     });

155     //grunt 配置

156     grunt.initConfig({

157         'pkg' : grunt.file.readJSON('package.json'),

158         'concat' : concatConfig,   //合并任务

159         'uglify' : uglifyJsConfig, //uglify js 压缩,

160         'cssmin': cssminConfig, //css 压缩,

161         'clean': {

162             test: ['tmp']  //创建的临时文件

163         },

164         'jshint': {

165             js: ['Js/*.js', 'Js/**/*.js','Js/**/**/*.js']

166         },

167         'string-replace':replaceConfig,  //替换路径

168         'watch': {

169             scripts: {

170                 files: ['Js/*.js', 'Js/**/*.js','Js/**/**/*.js'],

171                 tasks: ['jshint']

172             }

173         },

174         'rev': {

175             files: {

176                 src: proFiles

177             }

178         }

179     });

180 

181     // loadNpmTasks

182     grunt.loadNpmTasks('grunt-contrib-concat');

183 

184     grunt.loadNpmTasks('grunt-contrib-uglify');

185 

186     grunt.loadNpmTasks('grunt-css');

187     //clear

188     grunt.loadNpmTasks('grunt-contrib-clean');

189 

190     grunt.loadNpmTasks('grunt-contrib-jshint');

191 

192     //dev、production

193 

194     grunt.loadNpmTasks('grunt-string-replace');

195 

196     grunt.loadNpmTasks('grunt-contrib-watch')

197 

198     grunt.loadNpmTasks('grunt-rev');

199 

200     //注册任务:

201 

202     // 默认任务

203     grunt.registerTask('default', ['concat', 'uglify','cssmin','clean']);

204 

205     grunt.registerTask('jsHint', ['jshint']);

206 

207     grunt.registerTask('watch', ['watch']);

208 

209     //根据文件内容生产文件

210     grunt.registerTask('setCacheFile',['rev']);

211     //切换dev pro 环境

212     grunt.registerTask('transfer',['string-replace']);

213 

214     grunt.registerTask('quick', ['default', 'setCacheFile', 'transfer']);

215 

216 }; 
View Code

package.json:

 1 {

 2   "name": "test2",

 3   "version": "0.1.0",

 4   "author": "bossliu",

 5   "homepage": "###",

 6   "devDependencies": {

 7     "grunt": "~0.4.0",

 8     "grunt-contrib-clean":"~0.4.0rc5",

 9     "grunt-contrib-jshint": "~0.1.1rc5",

10     "grunt-contrib-uglify": "~0.1.2",

11     "grunt-contrib-concat": "~0.1.1",

12     "grunt-string-replace":"~0.2.7",

13     "grunt-contrib-watch":"~0.6.1",

14     "grunt-rev":"~0.1.0",

15     "grunt-css":   ">0.0.0"

16   }

17 }
View Code

index.html:

<!DOCTYPE html>

<html>

<head>

<title>grunt test</title>

<!-- grunt-import-css bootstripCss -->

<link href="Css/dest/603d3616.bootstrip.min.css" rel="stylesheet" />

<!--/grunt-import -->

</head>

<body>

  grunt test



<!-- grunt-import-js IEhtml5Js -->

<script src="Js/dest/56b83730.IEhtml5Js.min.js"></script>

<!--/grunt-import -->



<!-- grunt-import-js mainJs -->

<script src="Js/dest/3e083a76.main.min.js"></script>

<!--/grunt-import -->

</body>

</html>

 

参考文档:

http://www.infoq.com/cn/news/2014/03/env-spec-build-tool-compare/

http://www.infoq.com/cn/articles/front-end-engineering-and-performance-optimization-part1

 

你可能感兴趣的:(grunt)