应用Grunt自动化地优化你的项目前端

在不久前我曾写了一篇 应用r.js来优化你的前端 的文章,为大家介绍了r.js这个实用工具,它可以很好地压缩、合并前端文件并打包整个项目。但是如果将r.js放到项目中,我们不得不顾及到一个问题——项目每维护一次,就需要维护的人员输入一次rjs运行口令重新打包项目,自然是非常繁琐的事情。另外如果我们的项目用sass来写样式,可能还得外开一个koala。如果我们能让项目自己处理自己的所有事宜,那一切就美好多了。

针对上述问题,今天我们就利用更为大众的工具——Grunt,来自动化地处理前端事务(其实rjs也是使用了Grunt的concat和uglify等插件)。

我们依旧使用一个非常简单的、名为before的项目(你可以在我的Github下载这个案例)来作为示例,它是一个很纯净的项目,还没有使用任何前端工具对其进行操作:

你可以试着运行根目录下的index.html文件,它会显示一张幻灯片。

接下来我们将在before项目上使用Grunt自动化前端事务。

操作需求

由于Grunt是运行与node上的,故要求你的电脑安装了nodeJS(点我下载);

由于我们这边使用了sass来写样式,故要求你的电脑安装了Ruby(注意Mac是默认安装有Ruby的,如果是Windows或其它系统请点此下载安装)。

安装时建议把三个可以勾选的选项都勾上(特别要勾选上第二个,这样才会添加环境变量),安装后点击 “所有程序” -  “Ruby.13...” -  “start command prompt with Ruby”,打开Ruby命令行界面并输入指令:

gem install sass

注意该指令必须要在FQ的情况下才执行,不然可能会导致无法安装sass的错误:

不过有时候系统可能会提示这个错误信息:

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (https://bb-m.rubygems.org/gems/multi_json-1.3.2.gem)

解决方法是在这里下载证书(http://curl.haxx.se/ca/cacert.pem),比如下载到 D:/ruby/cacert.pem, 然后再环境变量里新建一个SSL_CERT_FILE这个环境变量,并把变量值设为这个文件路径即可:

 

另外,我们后续编译sass的时候,若.scss文件中存在中文注释,Ruby可能会因为识别不了中文编码而导致出错。不过解决方法很简单,点击此处查看

安装GRUNT CLI

我们打开 Node.js command prompt 进入node命令行界面:

在命令行界面输入以下代码并回车运行,此举是安装Grunt全局命令行,从而我们可以在电脑任何位置调用grunt命令语句:

npm install -g grunt-cli

Grunt配置

Grunt的入门其实可以参考官方入门,虽然这篇官方指引写的很烂,却也告诉我们,Grunt配置离不开两个文件—— package.jsonGruntfile.js ,我们一般都把它们放置在项目根目录上 。

其中 package.json 作用是记录项目的名称(随便起个名字就行)、版本号(随便起个数字串就行)和插件依赖,创建package.json完全不用手动,我们只需要把node命令行定位到项目下(假设我们把上述的before项目放在E盘),然后输入以下指令并回车执行,便会在项目根目录自动创建一个初始化的 package.json 文件:

npm init

回车后node会问你若干个问题,包括项目名啊版本号啊什么有的没的,你有心情可以写一写,没心情就一路按回车下来即可:

这时你会发现根目录下就这样多了个叫package.json的文件:

里面有node帮我们预先定义好的json代码。不过我各人并不喜欢使用 npm init 这种婆妈的形式来自动生成package.json,还不如自己手动创建一个package.json,并输入简洁的代码:

{
  "name": "before",
  "version": "1.0.0"
}

是的,初始化咱只要就这么俩行即可,其实我甚至希望能简短到只有 {  } 即可。可惜 name 和 version 对于 package.json 来说是非常重要的俩个属性,缺一不可(可以查看这里了解更多package.json属性的作用)

安装插件

Grunt只是一个载体,实际要用起来得使用各种五花八门的grunt插件(有点类似在Sublime上我们可以安装并使用各种sb插件)。

而我们的before项目需要运用到下面几个插件:

grunt —— 这个不用说了,就是Grunt它自己本身;

grunt-contrib-uglify —— 作用是压缩项目js文件;

grunt-contrib-sass —— 作用是编译项目中的sass为(压缩版的)css文件;

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

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

然而在node中,安装grunt插件的命令为:

npm install <插件名> --save-dev

其中后面的 “--save-dev” 表示保存为依赖,即在安装好插件后,会将此插件依赖写入package.json文件中(记得我们前面说到package.json的作用之一是记录项目的插件依赖么)。

于是我们在项目的根目录下分别运行下述命令安装插件:

npm install grunt --save-dev

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

npm install grunt-contrib-sass --save-dev

npm install grunt-contrib-watch --save-dev

运行时可能会提示如下的警告:

这是因为咱在package.json里没有写一些description等婆妈的东西,故这里的WARN不痛不痒直接无视它即可。

插件安装好后会发现项目根目录上多了个叫“node_modules”的文件夹,是用来存放我们安装好的插件的。另外我们打开package.json,会发现它已经自动加入了插件依赖信息:

配置Gruntfile.js文件

开始我们就提到grunt有2个不可缺少的文件 —— package.json 和 Gruntfile.js 文件,package.json咱已轻松搞定,下面新建一个Gruntfile.js 文件并输入以下代码:

module.exports = function(grunt) {
  grunt.initConfig({ 
    pkg: grunt.file.readJSON('package.json'),
    //上面是固定好的,不用管它,照搬即可。
    //下面是各插件事务的配置,顺序不分先后
    sass: { // grunt-contrib-sass的事务定义
      tocss: {
        options: {       
          style: 'compressed', //以压缩模式编译css,这样咱们也没必要使用grunt-contrib-cssmin插件了
          sourcemap:'none'  //设置不要配套输出map文件
        },
        files: [{
            expand:true,
            cwd:'css',//css目录下
            src:'**/*.scss',//所有css文件
            dest: 'css',//输出到此目录下
            ext: '.css'
        }]
      }
    },
    uglify: {  // grunt-contrib-uglify的事务定义
      compressjs: {
        files: [{
            expand:true,
            cwd:'js',//js目录下
            src:'**/*.js',//所有js文件
            dest: 'output/js'//输出到此目录下
        }]
      }
    },
    watch: {  // grunt-contrib-watch的事务定义
      all: {
        files: ['css/**/*.scss','js/**/*.js'],
        tasks: ['newer:sass','newer:uglify']
      }
    }
  });
  //grunt.loadNpmTasks() 是告诉Grunt,咱们要使用哪些插件,顺序不分先后
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-sass');
  grunt.loadNpmTasks('grunt-newer');
  //grunt.registerTask('default', [])是告诉Grunt,我们在node命令行输入grunt指令后要执行哪些事务
  grunt.registerTask('default', ['newer:sass','newer:uglify','watch']);  //注意 "newer:XXX"是插件grunt-newer的事件定义,表示对冒号后面的事务生效
};

Gruntfile.js的配置或许算是配置Grunt的一个难点吧,它的作用是告诉Grunt要使用哪些插件(安装了不代表一定要用对吧,当然要用的话一定得安装)、每个插件又要进行怎样的事务操作。

其实Gruntfile.js最最简单的初始化框架是这样的:

module.exports = function(grunt) {
  grunt.initConfig({ 
    pkg: grunt.file.readJSON('package.json'),

    插件事务名称: { 
      ........//事务定义
    }
  });
  //grunt.loadNpmTasks() 是告诉Grunt,咱们要使用哪些插件,顺序不分先后
  grunt.loadNpmTasks('插件名');

  //grunt.registerTask('default', [])是告诉Grunt,我们在node命令行输入grunt指令后要执行哪些事务
  grunt.registerTask('default', ['插件事务名称']);  
};

稍微推敲下,很容易理解代码的含义。如若了解更灵活、复杂的Gruntfile.js配置,可以点此查看指引

一切都捣鼓好后,我们可以直接在node命令行(依旧定位在根目录下哦,其实可以不用再唠嗑了)输入

grunt

回车执行后便进入自动化执行状态,只要有js或者scss文件变动,变动的文件就会重新被压缩或编译:

像本章的例子是使用了sass来写样式,如果你只写原生的css,又希望能压缩样式文件,那么可以使用 grunt-contrib-cssmin 插件,其具体配置可以点此查看,本文就不赘述了。

共勉~

donate

posted @ 2014-09-21 00:32  vajoy  阅读(4288)  评论(3编辑  收藏  举报
Copyright © 2014 - 2022 VaJoy Studio