省时省心的自动化工具 - Grunt使用介绍

很多人都知道,一个实际的项目,是应该有开发(development)版和发布(released)版的区分的(发布版也常用其他的表达方式,比如线上online,产品production)。真正的线上产品需要经过测试和优化,保证其品质(如访问速度,稳定性)。从开发完成到线上发布,应该经过一些流程,常见的就是错误检查,单元测试,代码压缩。

有一种观点是”Great developers are lazy.”,也就是说,开发过程中很多流程性的工作,要想办法让自己更轻松些。对此,普遍认同的做法就是自动化automation)。

就一个前端的项目而言,先来看看开发版与发布版的大致差异。

开发版与发布版

从直观的感受简单说的话,css的差异是:

css的差异

javascript的差异是:

javascript的差异

此外,各类格式的图片也可以做一定程度的优化,减小文件大小。可见,作为发布版,主要是从各个层面减小文件大小,提升访问速度。

Grunt是一个由node编写的自动化工具。对于我这样从事前端开发的人来说,比起其他的后端语言,Grunt这种使用javascript的工具会显得更亲切,更适合。

Grunt安装初始

我自己用的电脑是windows,所以说的是windows下的安装(各位看到的linux/mac安装教程还少么 (。・д・)ノ )。

首先,如果你还没有安装node,请到node官网下载。windows系统中使用的是一个.msi安装包,点击安装即可。

Grunt直接通过npm安装。如果不知道npm是什么,可点击维基百科-npm查看。就算不知道它是什么也没关系,现在的node安装包已经内置了npm,直接使用即可。

快捷键Win+R打开windows中的运行窗口,然后输入cmd,打开命令提示符,在其中输入:

npm install -g grunt-cli

这一步是安装Grunt的命令行支持(command line interface,简称CLI),在这之后,命令提示符中将会识别grunt命令。

到此,Grunt并不能称为安装完毕。这是因为,Grunt本身不是全局使用的,任何具体的工作目录,如果要使用Grunt,都需要安装一次Grunt。这样做也是因为不同的工作目录,需要通过Grunt做的自动化工作也不同,因此需要独立配置。

使用Grunt必须要配置两个文件。一个是package.json,另一个是Gruntfile.js(准确地说,还可以是Gruntfile.coffee,但本文不介绍这个)。

文件之一:package.json

npm对工作目录有一个要求。这个要求是:根目录位置处有一个package.json文件。这个文件定义了工作目录对应的一些项目信息(名字,描述),以及包(就是npm模块)依赖关系。它可以很简单,如下:

{
    "name": "huayixia",
    "version": "1.0.0",
    "description": "huayixia website"
}

你可以复制上面的内容自己手工创建package.json文件。如果你希望更官方一些,你可以在该工作目录位置处打开命令提示符:(属于小技巧,请看下图)

在某一目录打开cmd

然后输入:

npm init

接下来命令行中会问你一些问题,简单输入答复后(如果要留空,直接回车就可以),就可以在目录中自动生成一个package.json

在有了package.json之后,就可以为工作目录安装Grunt。在工作目录位置的命令提示符中输入:

npm install grunt --save-dev

后面的--save-dev不是必须的,但建议写上。它的作用是,在安装的同时,把Grunt的安装信息写入package.json。在有--save-dev安装操作后,package.json的内容会变成这样:

{
  "name": "huayixia",
  "version": "1.0.0",
  "description": "huayixia website",
  "devDependencies": {
    "grunt": "~0.4.1"
  }
}

从中可以看到devDependencies部分,已有Grunt的信息。同时,目录中会多出node_modules目录,里面存放的是Grunt的源文件。使用Grunt不需要管这个目录,

Grunt的实际工作,必须要结合各类Grunt插件Grunt Plugins)进行。根据工作目录的实际情况,从Grunt插件列表中选择需要的插件安装到目录即可。插件列表中,有星星标识的的”contrib”系列,是官方团队提供的。大部分情况下,推荐使用官方插件(不然怎么叫官方( ̄▽ ̄))。

插件的安装方式和安装Grunt一样。比如安装”grunt-contrib-uglify”(javascript压缩工具),在目录位置的命令提示符中输入:

npm install grunt-contrib-uglify --save-dev

同样,建议写上--save-dev,以记录到package.json文件中。插件的源文件也会存放到node_modules目录中。

文件之二:Gruntfile.js

Gruntfile.js相当于Grunt的配置文件,也必须位于根目录。这个文件建议手工创建(模板也可以创建,但模板的使用并不简单,所以还是复制起来更容易)。我自己的目录需要做的自动化工作分别是:css代码压缩,图片优化,js代码压缩。我选用了3个对应的插件来完成,分别是grunt-contrib-cssmingrunt-contrib-imagemingrunt-contrib-uglify。最后我的Gruntfile.js的内容是:(为方便说明,精简了细节部分)

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    myname: "yuki" //自定义变量
    uglify: {
      options: { //grunt插件都有options
        report: "min"
      },
      minify: { // minify只是一个target命名,可以自定
        expand: true,
        cwd: 'dev/js/',
        src: ['*.js'],
        dest: 'online/js/'
      }
    },
    cssmin: {
      options: {},
      minify: {}
    },
    imagemin: {
      options: {},
      minify: {}
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-imagemin');

  grunt.registerTask('default', ['cssmin', 'imagemin', 'uglify']);
};

接下来做详细说明。首先,module.exports = function(grunt) {};是一整个函数,它就像一个容器一样(module.exports是node中的语法,用于代码导出,以供其他javascript脚本使用)。所有的配置代码都应该写在这个函数内。

然后,在函数内,由空行的分隔,可以看出有三部分。先来说明很简单的后两部分。

grunt.loadNpmTasks();是加载插件任务。其实就是说,你如果要使用哪个插件的功能,请在这部分用这句代码把插件任务添加进去。

grunt.registerTask();是注册任务,默认有一个default。默认的意思就是说,你最后使用的时候,在目录的命令提示符里直接输入:

grunt

就相当于输入了grunt default,然后会执行注册的任务命令。函数第二个参数一般用数组,里面依次对应这个任务命令会执行的各个插件任务,而且会按照指定的顺序进行。比如上面的Gruntfile.js配置代码,对应的就是按顺序依次执行cssminimageminuglify这几个插件任务了。

插件任务可以单独执行,比如只需要图片优化(对应”imagemin”),可以输入:

grunt imagemin

可以注册更多的任务命令,使用其他的命名。比如

grunt.registerTask('custom', ['cssmin', 'imagemin']);

对应使用的时候,输入:

grunt custom

Grunt插件配置

下面来看比较复杂的grunt.initConfig();。这个函数调用的时候使用的Object类别的参数,即包含了配置的全部信息。

这个Object参数中,只要不和插件名冲突,可以任意自定义变量,如上面的Gruntfile.js文件中的pkg(它调用了Grunt的一个函数读取json文件信息),myname。此外的部分,则对应插件各自的配置信息,如cssminuglify

然后,在每一个插件信息内,可以定义选项options,它对应这个插件的具体配置,一般随插件不同,配置信息也不同,需要到插件的说明页查看。此外,是定义任务目标target)。大部分Grunt插件都是多任务的,因此可以定义多个,而且都可以自定义命名(除options外)。而且,每个任务目标内,也可以定义自己的目标级别的options,它会覆盖上一级的插件级别的options

在每个任务目标内,定义的是目标具体的操作内容说明。其中,最常见的就是文件操作Files)。文件操作的配置,是指定需要操作的文件,以及如何输出等,它是所有涉及文件操作的Grunt插件都遵守的。我最初用的时候,还很奇怪为什么每个插件的说明页贴了一堆示意代码,却没有对其中的配置内容说明完全,原来是因为这些是“公用”的…

以我最终使用的代码为例:

grunt.initConfig({
uglify: {
  minify: {
    expand: true,
    cwd: 'dev/js/',
    src: ['*.js'],
    dest: 'online/js/'
  }
});

这可能是比较常用的配置。其中的expand表示动态生成文件,当它为true的时候,才可以配置下面几项。cwd是指作为来源的所有src,都以其作为相对路径。src表示实际操作的文件,这里使用通配符,搭配了目录下的所有.js文件。dest是”destination”,表示目标文件的位置。在按照上面的代码设置后,uglify的任务执行效果,就是把所有dev/js/下的.js文件,都做压缩,处理得到的结果文件对应存放到online/js/目录中。

详细的配置指南,请查看官方的Configuring tasks

回到前面说的任务目标。还需要补充的是,任务目标也可以单独运行,比如输入:

grunt uglify:foo

则只会运行uglify任务的名称为foo的任务目标。显然,如果不用:指定目标,则会依次运行该任务中的所有任务目标。

Grunt使用

在配置好之后,就可以运行Grunt。很简单,在工作目录位置打开命令提示符,然后输入:

grunt

然后等待执行完毕。你可以看到其中的每一个任务的执行信息,比如我的情况:

运行grunt

这个过程十分迅速。任何时候需要的时候,执行一遍,就可以得到更新后的发布版。所以,真的是很省时省心。

结语

Grunt很像是一个工具平台,在看它的插件列表的时候,我发现了一些以前熟悉的东西,比如requireJS,compass,livereload。而原本这些工具,比如compass是ruby语言编写的。但在Grunt中,它就是node,所以,可以理解为,grunt整合了一系列的工具的node实现版。不过,无论怎样,它们都是为开发工作服务,让开发过程更轻松。

很推荐做前端开发的各位试试Grunt。

从jQuery分析隐藏元素的尺寸获取方法 闪之轨迹初玩感想