zoukankan      html  css  js  c++  java
  • 前端打包构建工具grunt快速入门(大篇幅完整版)

    打包的目的和意义就不用叙述了直接上干货

    http://www.gruntjs.net/getting-started里面的教程也太简单了,需要下一番功夫去研究才行。本文将grunt打包的常用方法都用实例描述,更加清晰易懂。

    1.    第一个简单的grunt打包


     1)需要安装nodejs:http://www.cnblogs.com/chuaWeb/p/nodejs-npm.html

      本人的nodejs工程目录为F:chuaNodejs(后续所有相对路径都是相对于这个目录)

    2)命令行到nodejs目录(需要系统管理员权限,不然后续过程中会报错)执行npm install -g grunt-cli

    3)在nodejs工程目录下建一个package.json,内容为

    {
      "name": "my-first-grunt",
      "file": "jquery",
      "version": "0.1.0",
      "devDependencies": {
        "grunt": "~0.4.5",
        "grunt-contrib-jshint": "~0.10.0",
        "grunt-contrib-nodeunit": "~0.4.1",
        "grunt-contrib-uglify": "~0.5.0"
      }
    }

      其中file属性在Gruntfile.js中要用到的属性,打包源名称

      然后将devDependencies下面的包给下载下来,比如下载grunt: npm install grunt --save-dev 其他包下载方式一样

      需要注意的是package.json中的数据必须是严格的json数据格式(连添加注释都是不可以的)。

    4) 在nodejs工程目录下建一个Gruntfile.js,内容为

     1 module.exports = function (grunt) {
     2   // 项目配置
     3   grunt.initConfig({
     4     pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
     5     uglify: {
     6       options: {
     7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
     8       },
     9       build: {
    10         src: 'src/<%=pkg.file %>.js',
    11         dest: 'dest/<%= pkg.file %>.min.js'
    12       }
    13     }
    14   });
    15   // 加载提供"uglify"任务的插件
    16   grunt.loadNpmTasks('grunt-contrib-uglify');
    17   // 默认任务
    18   grunt.registerTask('default', ['uglify']);
    19 }

      里面pkg读取package.json文件,然后可以访问其内容中的属性,如pkg.file。build属性src是待压缩的文件,dest是压缩重定向到该文件。

      所以现在我要建立一个src目录,目录下面保存了一个叫做jquery.js的文件

    5)命令行运行:grunt

      输出

    Running “uglify:build” (uglify) task
    File dest/jquery.min.js created: 277.14 kB ->93.35 kB
    >> 1 file created. 
    Done.

      创建了dest/jquery.min.js

      

      注意grunt命令和grunt uglify等价。当然也可以带上任务名称default:grunt default能等到同样结果。

    6)总结:

      grunt.initConfig:

      为当前项目初始化一个配置对象,其中传入的 configObject 参数可以用在后续的task中,可以通过grunt.config 方法访问。几乎每个项目的 Gruntfile 都会调用此方法。

      注意,任何 <% %> 模板字符串只会在取到配置数据后才被处理。

      不同的插件有各自的参数,比如例子中的uglify插件用到的参数有options和build。详细信息需要参考各个插件。

      initConfig详情参考:http://www.gruntjs.net/api/grunt.config#grunt.config.init

      grunt.loadNpmTasks:

      grunt打包主要是用到各种插件,比如上面的压缩用的插件uglify。加载插件需要使用该方法。

      从指定的 Grunt 插件中加载任务。此插件必须通过npm安装到本地,并且是参照 Gruntfile.js 文件的相对路径。

      详情参考:http://www.gruntjs.net/api/grunt.task#grunt.task.loadnpmtasks

      grunt.registerTask:

      注册 "别名任务" 或 任务函数。此方法支持以下两种类型:

      别名任务(如果指定了一个任务列表,那么,新注册的任务将会是这一个或多个任务的别名(alias)。当此"别名任务"执行时,taskList中的所有任务都将按指定的顺序依次执行。taskList 参数必须是一个任务数组。):grunt.task.registerTask(taskName, taskList)

      上面的例子就是别名任务。定义一个"default" 任务,当执行 Grunt 且不通过参数指定任务时,第二个参数中的任务将依序执行

      任务函数(如果传入description和taskFunction,每当任务运行时,指定的函数(taskFunction)都会被执行。此外,当执行 grunt --help时,前面指定的描述(description)就会显示出来。特定任务的属性和方法在任务函数内部通过this对象的属性即可访问。如果任务函数返回false表示任务失败。):grunt.task.registerTask(taskName, description, taskFunction)

      下一个例子我们就试一下这个任务函数,现在刚才例子每一个步骤目的就清晰了。

      详情参考:http://www.gruntjs.net/api/grunt.task#grunt.task.registertask

    2. 使用任务函数方式实现刚才的那个打包。


      其他的东西都没有变,Gruntfile.js变成了

     1 module.exports = function (grunt) {
     2   // 加载提供"uglify"任务的插件
     3   grunt.loadNpmTasks('grunt-contrib-uglify');
     4   // 任务函数
     5   grunt.registerTask('build', 'uglify 使用 任务函数版', function () {
     6     //任务列表
     7     var tasks = ['uglify'];
     8     // 项目配置
     9     grunt.initConfig({
    10       pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
    11     });
    12     var uglifyTask = {
    13       options: {
    14         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
    15       },
    16       build: {
    17         src: 'src/<%=pkg.file %>.js',
    18         dest: 'dest/<%= pkg.file %>.min.js'
    19       }
    20     }
    21     //将一个或多个任务放入队列中
    22     grunt.task.run(tasks);
    23     //给当前项目的 Grunt 配置中的uglify属性设置一个值。
    24     grunt.config.set("uglify", uglifyTask);
    25   });
    26 }

      然后去命令行运行: grunt bulid

      和第一个不同的是运行命令必须带上了任务名称build。

      注意前面提到的任何 <% %> 模板字符串只会在取到配置数据后才被处理。

    3. 合并压缩


      有些时候为了减少请求需要合并多个文件,且需要压缩。使用uglify即可做到这一点。

      Gruntfile.js代码

     1 module.exports = function (grunt) {
     2   // 项目配置
     3   grunt.initConfig({
     4     pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
     5     uglify: {
     6       options: {
     7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */
    ',//压缩目标文件头部注释
     8         mangle: false//变量和函数名称不压缩
     9       },
    10       my_target: {//该对象名称随意
    11         files: {
    12           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
    13         }
    14       }
    15     }
    16   });
    17   // 加载提供"uglify"任务的插件
    18   grunt.loadNpmTasks('grunt-contrib-uglify');
    19   // 默认任务
    20   grunt.registerTask('default', ['uglify']);
    21 }

      文件压缩的顺序按照files中定义的数组的顺序压缩。我们可以通过options.mangle来设置变量和函数名称是否压缩。还可以有下面的用法

    1 options: {
    2   banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */
    ',//压缩目标文件头部注释
    3   mangle: {
    4     except: ["jQuery"]//不压缩的关键字列表
    5   }
    6 }

      最终jquery.js和router.js合并压缩成libs.min.js

      详情参考:https://www.npmjs.com/package/grunt-contrib-uglify

    4. 合并压缩require配置的文件。


      首先需要下载grunt-contrib-requirejs插件:npm install grunt-contrib-requirejs --save-dev

      比如我们的执行文件main.js使用的是require来模块化加载,代码如下

     1 require.config({
     2   baseUrl: "",
     3   paths: {
     4     "jquery": "src/jquery",
     5     "bootstrap": "src/bootstrap.min",
     6     "validator": "src/bootstrapValidator.min"
     7   },
     8   shim: {
     9     "bootstrap":["jquery"],
    10     "beyond": ["bootstrap"],
    11     "validator": ["bootstrap"]
    12   }
    13 });
    14 requirejs(['validator'], function (v) {
    15   //代码
    16 });

      我们希望jquery/bootstrap/validator几个文件合并成一个,避免多次请求。

      我们新建一个grunt配置文件gruntCfg.json将main.js的require文件配置代码段拷贝到这个配置文件。并写入输入输出目标。源码如下

     1 {
     2   "requirejs": {
     3     "main": {
     4       "options": {
     5         "baseUrl": "",
     6         "paths": {
     7           "jquery": "src/jquery",
     8           "bootstrap": "src/bootstrap.min",
     9           "validator": "src/bootstrapValidator.min"
    10         },
    11         "shim": {
    12           "bootstrap":["jquery"],
    13           "validator": ["bootstrap"]
    14         },
    15         "include":["validator","jquery","bootstrap"],
    16         "out":"dest/libs.js"
    17       }
    18     }
    19   }
    20 }

      上面include中我打乱了顺序,为了测试压缩顺序我在三个库的前面都添加了console.log(“我是” + 模块名称)

      修改Gruntfile.js

     1 module.exports = function (grunt) {
     2   grunt.loadNpmTasks('grunt-contrib-requirejs');
     3   //为了介绍自定义任务搞了一个这个
     4   grunt.registerTask('build', 'require', function () {
     5 
     6     //设置requireJs的信息
     7     var taskCfg = grunt.file.readJSON('gruntCfg.json');
     8     var requireTask = taskCfg.requirejs;
     9 
    10     //添加人任务列表
    11     grunt.task.run(['requirejs']);
    12     grunt.config.set("requirejs", requireTask);
    13   });
    14 }

      好了现在看一下相关文件的文件结构如下

      

      执行build任务:grunt build

      文件夹dest下多了一个libs.js文件

      

      打开来看

      

      第一行代码就有我刚才添加的console。继续找我添加的标志的话发现压缩顺序是:jQuery->bootstrap->bootstrapValidator。和我们的shim依赖顺序一致。说明合并压缩的顺序没有问题。

      更多详情请查看:https://www.npmjs.com/package/grunt-contrib-requirejs

    5. 多任务


      我们先看一下使用别名任务来执行多个任务的情况,Gruntfile.js源码如下

     1 module.exports = function (grunt) {
     2   // 项目配置
     3   grunt.initConfig({
     4     pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
     5     uglify: {
     6       options: {
     7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
     8       },
     9       build: {
    10         src: 'src/<%=pkg.file %>.js',
    11         dest: 'dest/<%= pkg.file %>.min.js'
    12       },
    13       my_target1: {
    14         files: {
    15           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
    16         }
    17       },
    18       my_target2: {
    19         files: {
    20           'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
    21         }
    22       }
    23     },
    24     requirejs: {
    25       "main": {
    26         "options": {
    27           "baseUrl": "",
    28           "paths": {
    29             "jquery": "src/jquery",
    30             "bootstrap": "src/bootstrap.min",
    31             "validator": "src/bootstrapValidator.min"
    32           },
    33           "shim": {
    34             "bootstrap":["jquery"],
    35             "validator": ["bootstrap"]
    36           },
    37           "include":["validator","jquery","bootstrap"],
    38           "out":"dest/libs.js"
    39         }
    40       },
    41       "main2": {
    42         "options": {
    43           "baseUrl": "",
    44           "paths": {
    45             "jquery": "src/jquery",
    46             "bootstrap": "src/bootstrap.min",
    47             "validator": "src/bootstrapValidator.min"
    48           },
    49           "shim": {
    50             "bootstrap":["jquery"],
    51             "validator": ["bootstrap"]
    52           },
    53           "include":["validator","jquery","bootstrap"],
    54           "out":"dest/libs2.js"
    55         }
    56       }
    57     }
    58 
    59   });
    60   // 加载提供"uglify"任务的插件
    61   grunt.loadNpmTasks('grunt-contrib-uglify');
    62   grunt.loadNpmTasks('grunt-contrib-requirejs');
    63   // 默认任务
    64   grunt.registerTask('default', ['uglify',"requirejs"]);
    65 }

      执行:grunt

      dest文件夹下多出了5个文件

      

      源码解析是:任务列表有两个任务'uglify'和"requirejs",'uglify'有三个子任务:build/ my_target1/ my_target2, "requirejs"有两个子任务main/main2。最终这五个子任务完成后生成的结果就是dest下多出的5个文件。

      还可以使用任务函数方式注册多个任务。Gruntfile.js源码如下

     1 module.exports = function (grunt) {
     2   grunt.initConfig({
     3     log: {
     4       l1: [1,2,3],
     5       l2: 'hello world',
     6       l3: false,
     7       l4: {name: "chua"},
     8       l5: 1,
     9       //这个是不行的l6: undefined,
    10       //这个是不行的l7: null
    11       l8: function(){alert("test")}
    12     }
    13   });
    14 
    15   grunt.registerMultiTask('log','log stuff.', function(){
    16       grunt.log.writeln(this.target + ': ' + this.data);
    17   });
    18 }

      执行:grunt log

      

      我们使用自定义方式实现先前的多任务Gruntfile.js源码如下

     1 module.exports = function (grunt) {
     2   // 项目配置
     3   grunt.initConfig({
     4     pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
     5     log: {
     6       uglify: {
     7         options: {
     8           banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
     9         },
    10         build: {
    11           src: 'src/<%=pkg.file %>.js',
    12           dest: 'dest/<%= pkg.file %>.min.js'
    13         },
    14         my_target1: {
    15           files: {
    16             'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
    17           }
    18         },
    19         my_target2: {
    20           files: {
    21             'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
    22           }
    23         }
    24       },
    25       requirejs: {
    26         "main": {
    27           "options": {
    28             "baseUrl": "",
    29             "paths": {
    30               "jquery": "src/jquery",
    31               "bootstrap": "src/bootstrap.min",
    32               "validator": "src/bootstrapValidator.min"
    33             },
    34             "shim": {
    35               "bootstrap":["jquery"],
    36               "validator": ["bootstrap"]
    37             },
    38             "include":["validator","jquery","bootstrap"],
    39             "out":"dest/libs.js"
    40           }
    41         },
    42         "main2": {
    43           "options": {
    44             "baseUrl": "",
    45             "paths": {
    46               "jquery": "src/jquery",
    47               "bootstrap": "src/bootstrap.min",
    48               "validator": "src/bootstrapValidator.min"
    49             },
    50             "shim": {
    51               "bootstrap":["jquery"],
    52               "validator": ["bootstrap"]
    53             },
    54             "include":["validator","jquery","bootstrap"],
    55             "out":"dest/libs2.js"
    56           }
    57         }
    58       }
    59     }
    60   });
    61   // 加载提供"uglify"任务的插件
    62   grunt.loadNpmTasks('grunt-contrib-uglify');
    63   grunt.loadNpmTasks('grunt-contrib-requirejs');
    64   
    65   grunt.registerMultiTask('log','log stuff.', function(){
    66     if(this.target == "uglify"){
    67       //添加人任务列表
    68       grunt.task.run(['uglify']);
    69       grunt.config.set("uglify", this.data);
    70     }else if(this.target == "requirejs"){
    71       //添加人任务列表
    72       grunt.task.run(['requirejs']);
    73       grunt.config.set("requirejs", this.data);
    74     }
    75   });
    76 }

      执行:grunt log

      照样得到先前的结果

      

      说到底和先前的别名任务没有什么不同。

    6. 压缩整个文件夹下的js文件


      压缩src下的所有js文件,Gruntfile.js源码

     1 module.exports = function (grunt) {
     2   grunt.initConfig({
     3     uglify: {
     4       my_target: {
     5         files: [{
     6           expand: true,
     7           cwd: 'src',
     8           src: '**/*.js',
     9           dest: 'dest'
    10         }]
    11       }
    12     }
    13   });
    14   grunt.loadNpmTasks('grunt-contrib-uglify');
    15   grunt.registerTask('default', ['uglify']);
    16 }

      源码文件结构(注意src/router下面还有一个js文件)

      

      执行:grunt

      目标文件结构

      

      所以这个方法还是比较方便的,他会遍历源文件夹下的所有文件(包括子文件夹)然后压缩。

      刚才上面的方式没有拷贝src文件夹,下面这种方式拷贝了src文件夹

     1 module.exports = function (grunt) {
     2   grunt.initConfig({
     3     uglify: {
     4       my_target: {
     5         files: [{
     6           expand: true,
     7           //cwd: 'src',
     8           src: 'src/**/*.js',
     9           dest: 'dest'
    10         }]
    11       }
    12     }
    13   });
    14   grunt.loadNpmTasks('grunt-contrib-uglify');
    15   grunt.registerTask('default', ['uglify']);
    16 }

      执行:grunt

      目标文件结构变成

      

      src下所有的js都被压缩并保持原来的目录结构。

    7. grunt-contrib-requirejs插件的更详细使用


      我们用实例来说明。现在我们的文件结构是这样子的

      

      main.js是我们使用require的真实配置文件,源码如下

     1 require.config({
     2   baseUrl: "",
     3   paths: {
     4     "jquery": "src/jquery",
     5     "bootstrap": "src/bootstrap.min",
     6     "validator": "src/bootstrapValidator.min"
     7   },
     8   shim: {
     9     "bootstrap":["jquery"],
    10     "beyond": ["bootstrap"],
    11     "validator": ["bootstrap"]
    12   }
    13 });
    14 requirejs(['validator'], function (v) {
    15   //代码
    16 });

      Gruntfile.js的源码

     1 module.exports = function (grunt) {
     2   grunt.initConfig({
     3     "requirejs": {
     4       "main": {
     5         "options": {
     6           "baseUrl": ".",
     7           "mainConfigFile": "main.js",//指定配置文件
     8           "name": "test",//会将对应的文件压缩到main.js依赖的文件的前面压缩。但是会在main.js非依赖文件后面压缩(比如router.js)
     9           "include":["jquery","bootstrap","validator","src/router/router.js"],//要压缩在一起的文件(会包括name对应的文件)
    10           "out":"dest/libs.js"
    11         }
    12       }
    13     }
    14   });
    15   grunt.loadNpmTasks('grunt-contrib-requirejs');
    16   grunt.registerTask('default', ['requirejs']);
    17 }

      需要说明的是name指定的文件内容会在main.js配置的依赖文件压缩之前压缩,但是如果include中还包含其他非main.js依赖的文件,则会在main.js非依赖文件后面压缩。

      我们的test.js源码为

    1 console.log("这是我随便测试用的一个js");

      然后我们执行:grunt

      结果在dest下生成一个libs.js压缩文件

      

      并且这个文件里面包含的压缩文件的顺序是:router.js->test.js->jquery.js-> bootstrap.min.js-> bootstrapValidator.min.js。

      所以说配置include中文件会依序压缩到libs.js,但是main.js依赖的文件会放在最后(依赖会逐层往上查找依赖),而name指定的文件会在非依赖文件之后依赖文件之前压缩。

      require模板文件打包

      模板文件使用到require工程上的text.js文件,路径:http://github.com/requirejs/text

      我们这里建立一个模板文件test.html

    1 <!DOCTYPE html>
    2 <html>
    3 <head>
    4   <title>test</title>
    5 </head>
    6 <body>
    7 </body>
    8 </html>

      实际上现在test.html没有用到任何模板相关的运用,我们只是做打包例子,所以不管其他,我们只需要知道模板文件一般是html文件即可

      现在工程的文件结构是

      

      Gruntfile.js的源码为

     1 module.exports = function (grunt) {
     2   grunt.initConfig({
     3     "requirejs": {
     4       "main": {
     5         "options": {
     6           baseUrl: ".",
     7           paths: {
     8             "jquery": "src/jquery",
     9             "bootstrap": "src/bootstrap.min",
    10             "validator": "src/bootstrapValidator.min",
    11             "text": "text"//引入requirejs项目下解析模板引擎
    12           },
    13           shim: {
    14             "bootstrap":["jquery"],
    15             "beyond": ["bootstrap"],
    16             "validator": ["bootstrap"]
    17           },
    18           "include":["jquery","bootstrap","validator","text!test.html"],          "out":"dest/libs.js"
    19         }
    20       }
    21     }
    22   });
    23   grunt.loadNpmTasks('grunt-contrib-requirejs');
    24   grunt.registerTask('default', ['requirejs']);
    25 }

      执行命令行:grunt

      dest文件下多了一个libs.js,查看其中是否有模板文件test.html中的内容

      

      说明模板被一同压缩进去了。关键是"text!test.html"这句话。test会将模板test.html解析成js脚本形式。

    8.  cssmin打包样式文件


      需要用npm下载cssmin插件:npm install grunt-contrib-cssmin --save-dev

      Gruntfile.js文件源码

     1 module.exports = function (grunt) {
     2   grunt.initConfig({
     3     cssmin: {
     4       compress: {
     5         files: {
     6           'dest/t.min.css': ["src/t1.css","src/t2.css"]
     7         }
     8       }
     9     }
    10   });
    11 
    12   grunt.loadNpmTasks('grunt-contrib-cssmin');
    13 
    14 }

      命令行执行:grunt cssmin

      两个css文件压缩打包到dest/t.min.css

    9. htmlmin打包html文件


      需要用npm下载cssmin插件:npm install grunt-contrib-htmlmin --save-dev

      Gruntfile.js源码

     1 module.exports = function (grunt) {
     2   grunt.initConfig({ 
     3     htmlmin: {
     4       main: {
     5         options:{
     6           removeComments: true,
     7           collapseWhitespace: true
     8         },
     9         files:{
    10           "dest/test.html": "test.html"
    11         }
    12       }
    13     }
    14   });
    15 
    16   grunt.loadNpmTasks('grunt-contrib-htmlmin');
    17   grunt.registerTask("default",["htmlmin"]);
    18 }

      执行命令:grunt

      test.html压缩到dest/test.html

      

    10. copy拷贝文件


      需要下载copy插件npm install grunt-contrib-copy --save-dev

      将src文件夹(包括内容和子文件内容)拷贝到dest目录下,Gruntfile.js源码

     1 module.exports = function (grunt) {
     2   grunt.initConfig({ 
     3     copy: {
     4       main: {
     5         expand: true,
     6         src: 'src/**',
     7         dest: 'dest/'
     8       }
     9     }
    10   });
    11 
    12   grunt.loadNpmTasks('grunt-contrib-copy');
    13   grunt.registerTask("default",["copy"]);
    14 }

      运行:grunt

      src被完美的拷贝到dest下

       

      只拷贝src的第一层子文件,Gruntfile.js源码

     1 module.exports = function (grunt) {
     2   grunt.initConfig({ 
     3     copy: {
     4       main: {
     5         expand: true,
     6         src: 'src/*',
     7         dest: 'dest/'
     8       }
     9     }
    10   });
    11 
    12   grunt.loadNpmTasks('grunt-contrib-copy');
    13   grunt.registerTask("default",["copy"]);
    14 }

      运行结果

      

      这个时候router是空文件夹。

      所以这里我们需要明白路径中“*”只表示当前这一层,“**”表示需要递归子文件夹   

      如果只是拷贝src中的内容而不用src包裹则需要cwd属性

     1 module.exports = function (grunt) {
     2   grunt.initConfig({ 
     3     copy: {
     4       main: {
     5         expand: true,
     6         cwd: "src/",
     7         src: '*',//也可以是数组形式["*"],可以过滤多种类型
     8         dest: 'dest/'
     9       }
    10     }
    11   });
    12 
    13   grunt.loadNpmTasks('grunt-contrib-copy');
    14   grunt.registerTask("default",["copy"]);
    15 }

      执行结果是

      

      注意下面这种写法会报错

    module.exports = function (grunt) {
      grunt.initConfig({ 
        copy: {
          main: {
            expand: true,
            cwd: "src",
            src: '/*',//会报错,不能以/开头,会被认为是绝对路径
            dest: 'dest/'
          }
        }
      });
    
      grunt.loadNpmTasks('grunt-contrib-copy');
      grunt.registerTask("default",["copy"]);
    }

      拷贝src文件夹下指定类型的文件,Gruntfile.js源码

    module.exports = function (grunt) {
      grunt.initConfig({ 
        copy: {
          main: {
            expand: true,
            src: 'src/*.js',
            dest: 'dest/'
          }
        }
      });
    
      grunt.loadNpmTasks('grunt-contrib-copy');
      grunt.registerTask("default",["copy"]);
    }

      执行:grunt

      结果src的js文件随src文件夹被拷贝

      

      递归拷贝src文件夹下所有子文件夹中的js文件

     1 module.exports = function (grunt) {
     2   grunt.initConfig({ 
     3     copy: {
     4       main: {
     5         expand: true,
     6         src: 'src/**/*.js',
     7         dest: 'dest/'
     8       }
     9     }
    10   });
    11 
    12   grunt.loadNpmTasks('grunt-contrib-copy');
    13   grunt.registerTask("default",["copy"]);
    14 }

      执行结果

      

      将所有指定类型的文件提取到同一层,Gruntfile.js源码

     1 module.exports = function (grunt) {
     2   grunt.initConfig({ 
     3     copy: {
     4       main: {
     5         flatten: true,//所有文件提取到dest下
     6         expand: true,
     7         src: 'src/**/**.js',
     8         dest: 'dest/'
     9       }
    10     }
    11   });
    12 
    13   grunt.loadNpmTasks('grunt-contrib-copy');
    14   grunt.registerTask("default",["copy"]);
    15 }

      执行结果

      

      我们发现router/router.js被提取到了目标目录下,这也是flatten的作用

    11. 使用contrib-watch和newer实时监听文件更改


      这里需要用到两个插件,下载这两个插件

      grunt-contrib-watch —— 作用是实现我们一开始需求的“自动化”!它会监听需要处理的文件的变动,一旦有变动就会自动执行相应处理。但是它有一个问题,就是每当监听到一处变动时,就会大费周章地把所有被监听的文件都处理一遍;

      grunt-newer —— 作用是处理上方watch的毛病,让watch在监听到某个文件变动时,仅仅对变动的文件进行事务处理。

      我们以合并压缩为例,Gruntfile.js源码

     1 module.exports = function (grunt) {
     2   // 项目配置
     3   grunt.initConfig({
     4     uglify: {
     5       my_target: {//该对象名称随意
     6         files: {
     7           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
     8         }
     9       }
    10     },
    11     watch: {
    12       watchJs: {
    13         files: ["src/**/*.js"],
    14         tasks: ["newer:uglify"]//一旦监听到files中文件修改,立马触发uglify任务
    15       }
    16     }
    17   });
    18   // 加载提供"uglify"任务的插件
    19   grunt.loadNpmTasks('grunt-contrib-uglify');
    20   grunt.loadNpmTasks('grunt-contrib-watch');
    21   grunt.loadNpmTasks('grunt-newer');
    22   // 默认任务
    23   grunt.registerTask('default', ['uglify',"watch"]);
    24 }

      上面watch任务有一个子任务watchJs监听js的变动,一旦监听到files更改就触发uglify任务。

      

    12. 使用autoprefixer自动为CSS规则添加最合适的前缀兼容浏览器


      Autoprefixer解析CSS文件并且添加浏览器前缀到CSS规则里,使用Can I Use的数据来决定哪些前缀是需要的。

      需要下载grunt-autoprefixer插件

      Gruntfile.js源码实例

     1 module.exports = function (grunt) {
     2   // 项目配置
     3   grunt.initConfig({
     4     autoprefixer : {
     5       my_target: {//该对象名称随意
     6         expand:true,
     7         src: "src/**/*.css",
     8         dest: "dest/"
     9       }
    10     },
    11     watch: {
    12       watchJs: {
    13         files: ["src/**/*.css"],
    14         tasks: ["newer:autoprefixer"]//一旦监听到files中文件修改,立马触发任务
    15       }
    16     }
    17   });
    18   // 加载提供"uglify"任务的插件
    19   grunt.loadNpmTasks('grunt-autoprefixer');
    20   grunt.loadNpmTasks('grunt-contrib-watch');
    21   grunt.loadNpmTasks('grunt-newer');
    22   // 默认任务
    23   grunt.registerTask('default', ['newer:autoprefixer',"watch"]);
    24 }

      这样监听了所有css更改,每次更改都会先添加浏览器兼容前缀。我们可以放心的在样式文件中按照最新的W3C规范来正常书写CSS而不需要浏览器前缀。

    13. 总结


      总的来说grunt压缩打包都是基于插件,各种插件的作用可以查看官网文档。

      在运行任务函数指定的任务的时候可以通过冒号分割来传递参数。比如下面的例子

    module.exports = function (grunt) {
      //为了介绍自定义任务搞了一个这个
      grunt.registerTask('test', '任务函数实例', function (arg1, arg2) {
        if (arguments.length === 0) {
          grunt.log.writeln(this.name + " 没有参数");
        } else {
          var join = Array.prototype.join;
          grunt.log.writeln(this.name + " 的参数有" + join.call(arguments,","));
        }
      });
    }

      执行:grunt test

      打印:

    Runing “test” task
    test 没有参数

      执行:grunt test:1

      打印:

    Runing “test:1” (test) task
    test 的参数有1

      执行:grunt test:1:2

      打印:

    Runing “test:1:2” (test) task
    test 的参数有1,2

      正常来说我们的html/css/js文件都是用不同的文件夹保存的,所以我们可以分成三种任务来处理。这些任务都可以配置在一起,最后一次性打包,这部分根据各自实际项目情况来处理。

      ok,如果你从头到尾看完并把上面的实例执行,那么grunt的基本功能就没有问题了。更多的需要看具体的插件使用了。

      

      码字不容易,求推荐。

  • 相关阅读:
    二分查找
    Android手机APN设置(中国移动 联通3G 电信天翼),解决不能上网的问题
    cocos2dx 3.1从零学习(三)——Touch事件(回调,反向传值)
    Groovy新手教程
    总结一下用caffe跑图片数据的研究流程
    JAVA数组的定义及用法
    开机黑屏 仅仅显示鼠标 电脑黑屏 仅仅有鼠标 移动 [已成功解决]
    LeetCode——Reverse Words in a String
    oracle 库文件解决的方法 bad ELF interpreter: No such file or directory
    布局文件提示错误“No orientation specified, and the default is horizontal. This is a common so...”
  • 原文地址:https://www.cnblogs.com/chuaWeb/p/grunt.html
Copyright © 2011-2022 走看看