• 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") %> */
    '
     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*-->[sS]*?<!--s*/grunt-imports*-->/ig;
    101     var gruntImportItemReg = /(<!--s*grunt-import-(w+)s+(w+)s*-->)([sS]*?)(<!--s*/grunt-imports*-->)/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]+'
    ';
    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 += '
    ';
    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

  • 相关阅读:
    Spring Boot(十一):Spring Boot 中 MongoDB 的使用
    你干啥的?Lombok
    面试必备的分布式事物方案
    Shiro框架详解 tagline
    List中的ArrayList和LinkedList源码分析
    计算机内存管理介绍
    Struts2.5 伪静态的配置
    Hibernate——hibernate的配置测试
    Struts2.5的的环境搭建及跑通流程
    Jsp敏感词过滤
  • 原文地址:https://www.cnblogs.com/lmh2072005/p/3946655.html
Copyright © 2020-2023  润新知