【深刻淺出Node.js系列十六】grunt讓Nodejs規範起來

#0 系列目錄#javascript

一個應用開發到必定階段,廣泛會遇到一個問題。當功能愈來愈多,代碼量愈來愈大,bug修復愈來愈頻繁,開發人員一波一波的交替,…..應該用會向着愈來愈不可控發展。咱們不能再準確估計新功能的開發時間,也不知道一個bug修復後是否會引起另外一個bug出現。全部的程序開發,都會面臨着這樣的問題。css

C/C++程序經過makefile管理編譯測試打包的過程,Java程序經過Maven,Ant實現項目構建管理功能,Python有pip,Ruby有gem。在Nodejs的領域,咱們一樣須要一個項目構建工具,這就是Grunt。Grunt能夠執行像壓縮, 編譯, 單元測試, 代碼檢查以及打包發佈的任務html

#1 Grunt介紹# Grunt是一個自動化的項目構建工具. 若是你須要重複的執行像壓縮, 編譯, 單元測試, 代碼檢查以及打包發佈的任務. 那麼你能夠使用Grunt來處理這些任務, 你所須要作的只是配置好Grunt, 這樣能很大程度的簡化你的工做.java

若是在團隊中使用Grunt, 你只須要與其餘人員約定好使用Grunt應該規避的問題, 就可以很方便的自動化的處理大部分的常見工做任務, 你所付出的努力幾乎爲0.node

#2 Grunt安裝# Grunt和Grunt插件都是經過npm, Node.js包管理器安裝和管理的.jquery

##2.1 安裝grunt-cli## grunt-cli並不grunt,grunt-cli的做用是管理本地各版本的grunt,讓命令行能夠直接執行grunt命令。git

下面全局安裝grunt-cli(-g)github

~ D:\workspace\javascript>npm install -g grunt-cli

D:\toolkit\nodejs\grunt -> D:\toolkit\nodejs\node_modules\grunt-cli\bin\grunt
grunt-cli@0.1.9 D:\toolkit\nodejs\node_modules\grunt-cli
├── resolve@0.3.1
├── nopt@1.0.10 (abbrev@1.0.4)
└── findup-sync@0.1.2 (lodash@1.0.1, glob@3.1.21)

咱們看到grunt-cli彷佛作了一個軟件連接,把grunt腳本複製到nodejs安裝根目錄裏。web

##2.2 全局安裝grunt##shell

~ D:\workspace\javascript>npm install -g grunt

~ D:\workspace\javascript>grunt
grunt-cli: The grunt command line interface. (v0.1.9)

Fatal error: Unable to find local grunt.

If you're seeing this message, either a Gruntfile wasn't found or grunt
hasn't been installed locally to your project. For more information about
installing and configuring grunt, please see the Getting Started guide:

http://gruntjs.com/getting-started

執行grunt命令,咱們發現系統報錯了,提示不能加載本地庫。由於,grunt命令執行,是須要當前目錄中包括package.json和Gruntfile.js兩個文件

package.json,是npm項目配置文件

Gruntfile.js,是專門用來配置grunt的配置文件

##2.3 建立一個express3的項目##

~ D:\workspace\javascript>express -e nodejs-grunt
~ D:\workspace\javascript>cd nodejs-grunt && npm install	 
~ D:\workspace\javascript\nodejs-grunt>npm install grunt --save-dev

安裝-save-dev,就能夠,直接把grunt做爲devDependencies寫入的package.json中。

~ vi package.json

{
  "name": "nodejs-grunt",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.2.2",
    "ejs": "*"
  },
  "devDependencies": {
    "grunt": "~0.4.1",
  }
}

而後,咱們再執行grunt,系統提示缺乏Gruntfile文件

~ D:\workspace\javascript\nodejs-grunt>grunt
A valid Gruntfile could not be found. Please see the getting started guide for
more information on how to configure grunt: http://gruntjs.com/getting-started
Fatal error: Unable to find Gruntfile.

建立Gruntfile文件:

~ vi Gruntfile.js

module.exports = function(grunt) {
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/<%= pkg.name %>.js',
        dest: 'build/<%= pkg.name %>.min.js'
      }
    }
  });
  // Load the plugin that provides the "uglify" task.
  grunt.loadNpmTasks('grunt-contrib-uglify');
  // Default task(s).
  grunt.registerTask('default', ['uglify']);
};

再次運行grunt,這時提示是grunt-contrib-uglify包找不到,是Gruntfile.js配置文件中的錯誤了。

~ D:\workspace\javascript\nodejs-grunt>grunt
>> Local Npm module "grunt-contrib-uglify" not found. Is it installed?
Warning: Task "uglify" not found. Use --force to continue.

咱們編輯package.json, 在devDependencies中增長grunt-contrib-uglify的依賴庫:

~ vi package.json
{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.2.2",
    "ejs": "*"
  },
  "devDependencies": {
    "grunt": "~0.4.1"
    "grunt-contrib-uglify": "~0.1.1"
  }
}

~ D:\workspace\javascript\nodejs-grunt>npm install

咱們建立兩個目錄src和build,和nodejs-grunt.js的文件

~ D:\workspace\javascript\nodejs-grunt>mkdir src
~ D:\workspace\javascript\nodejs-grunt>mkdir build

~ D:\workspace\javascript\nodejs-grunt>vi src/nodejs-grunt.js
var sayHello = function(name){
    return "Hello " + name;
}

咱們再執行grunt:

~ D:\workspace\javascript\nodejs-grunt>grunt
Running "uglify:build" (uglify) task
File "build/nodejs-grunt.min.js" created.
Uncompressed size: 59 bytes.
Compressed size: 40 bytes gzipped (43 bytes minified).

Done, without errors.

grunt運行正常,而且執行了uglify:build的任務。打開build/nodejs-grunt.min.js文件:

~ D:\workspace\javascript\nodejs-grunt>vi build/nodejs-grunt.min.js

/*! nodejs-grunt 2013-08-17 */
var sayHello=function(l){return"Hello "+l};

#3 Grunt使用# 咱們能夠經過help幫助,看一下grunt怎麼用。

~ D:\workspace\javascript\nodejs-grunt>grunt --help
Grunt: The JavaScript Task Runner (v0.4.1)

Usage
 grunt [options] [task [task ...]]

Options
    --help, -h  Display this help text.
        --base  Specify an alternate base path. By default, all file paths are
                relative to the Gruntfile. (grunt.file.setBase) *
    --no-color  Disable colored output.
   --gruntfile  Specify an alternate Gruntfile. By default, grunt looks in the
                current or parent directories for the nearest Gruntfile.js or
                Gruntfile.coffee file.
   --debug, -d  Enable debugging mode for tasks that support it.
       --stack  Print a stack trace when exiting with a warning or fatal error.
   --force, -f  A way to force your way past warnings. Want a suggestion? Don't
                use this option, fix your code.
       --tasks  Additional directory paths to scan for task and "extra" files.
                (grunt.loadTasks) *
         --npm  Npm-installed grunt plugins to scan for task and "extra" files.
                (grunt.loadNpmTasks) *
    --no-write  Disable writing files (dry run).
 --verbose, -v  Verbose mode. A lot more information output.
 --version, -V  Print the grunt version. Combine with --verbose for more info.
  --completion  Output shell auto-completion rules. See the grunt-cli
                documentation for more information.

Options marked with * have methods exposed via the grunt API and should instead
be specified inside the Gruntfile wherever possible.

Available tasks
       uglify  Minify files with UglifyJS. *
       default  Alias for "uglify" task.

Tasks run in the order specified. Arguments may be passed to tasks that accept
them by using colons, like "lint:files". Tasks marked with * are "multi tasks"
and will iterate over all sub-targets if no argument is specified.

The list of available tasks may change based on tasks directories or grunt
plugins specified in the Gruntfile or via command-line options.

For more information, see http://gruntjs.com/

有兩方面是咱們須要注意的:

Options: grunt支持的命令

Available tasks: 當目錄可執行的任務

#4 Grunt經常使用插件#

grunt-contrib-uglify:壓縮js代碼

grunt-contrib-concat:合併js文件

grunt-contrib-qunit:單元測試

grunt-contrib-jshint:js代碼檢查

grunt-contrib-watch:監控文件修改並從新執行註冊的任務

  1. grunt-contrib-uglify:是執行壓縮JS代碼的任務。

  2. grunt-contrib-concat:是執行合併文件的任務。

插件安裝及更新到配置

~ D:\workspace\javascript\nodejs-grunt>npm install grunt-contrib-concat --save-dev

修改Gruntfile.js文件:

grunt.initConfig({
   pkg: grunt.file.readJSON('package.json'),
   concat:{
     options: {
       //定義一個字符串插入每一個文件之間用於鏈接輸出
       separator: ';'
     },
     dist: {
         src: ['src/*.js'],
         dest: 'build/<%= pkg.name %>.cat.js'
     }
   },
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['uglify','concat']);

在src目錄,新增長文件src/sayBye.js

~ vi src/sayBye.js

var sayBye = function(name){
    return "Bye " + name;
}

執行concat任務

~ D:\workspace\javascript\nodejs-grunt>grunt concat
Running "concat:dist" (concat) task
File "build/nodejs-grunt.cat.js" created.

Done, without errors.

查看生成的文件build/nodejs-grunt.cat.js

~ vi build/nodejs-grunt.cat.js

var sayHello = function(name){
    return "Hello " + name;
};var sayBye = function(name){
    return "Bye " + name;
}
  1. grunt-contrib-qunit:是執行QUint單元測試的任務。

插件安裝及更新到配置:

~ D:\workspace\javascript\nodejs-grunt>npm install grunt-contrib-qunit --save-dev

修改Gruntfile.js文件:

grunt.initConfig({
   pkg: grunt.file.readJSON('package.json'),
   qunit: {
       files: ['test/*.html']
   }
});
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.registerTask('default', ['uglify','concat','qunit']);

建立一個test目錄,並編寫用於測試的qunit.html文件:

~ mkdir test
~ vi test/qunit.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" media="screen" />
    <script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
    <script>
        test("hello", function() {
            ok(true, "world");
        });
    </script>
</head>
<body>
    <h1 id="qunit-header">QUnit example</h1>
    <h2 id="qunit-banner"></h2>
    <h2 id="qunit-userAgent"></h2>
    <ol id="qunit-tests"></ol>
</body>
</html>

執行qunit命令:

~ D:\workspace\javascript\nodejs-grunt>grunt qunit
Running "qunit:files" (qunit) task
Testing test/qunit.html .OK
>> 1 assertions passed (67ms)

Done, without errors.
  1. grunt-contrib-jshint:是執行代碼驗證的任務

插件安裝及更新到配置:

~ D:\workspace\javascript\nodejs-grunt>npm install grunt-contrib-jshint --save-dev

修改Gruntfile.js文件:

grunt.initConfig({
   pkg: grunt.file.readJSON('package.json'),
   jshint: {
       files: ['gruntfile.js', 'src/*.js', 'build/*.js'],
       options: {
           globals: {
               exports: true
           }
       }
   }
 });
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('default', ['uglify','concat','qunit','jshint']);

執行jshint代碼檢查:

~ D:\workspace\javascript\nodejs-grunt>grunt jshint
Running "jshint:files" (jshint) task
Linting src/nodejs-grunt.js ...ERROR
[L3:C2] W033: Missing semicolon.
}
Linting build/nodejs-grunt.cat.js ...ERROR
[L5:C2] W033: Missing semicolon.
}
Linting build/nodejs-grunt.min.js ...ERROR
[L2:C42] W033: Missing semicolon.
var sayHello=function(l){return"Hello "+l};

Warning: Task "jshint:files" failed. Use --force to continue.

Aborted due to warnings.

好多的錯誤啊,細看一下,都是」丟失分號」的錯誤。

~ vi src/sayBye.js
var sayBye = function(name){
    return "Bye " + name;
};
  1. grunt-contrib-watch,是監控指定文件被修改,從新啓動已註冊的任務

插件安裝及更新到配置:

~ D:\workspace\javascript\nodejs-grunt>npm install grunt-contrib-watch --save-dev

修改Gruntfile.js文件:

grunt.initConfig({
   pkg: grunt.file.readJSON('package.json'),
   watch: {
       files: ['<%= jshint.files %>'],
       tasks: ['jshint', 'qunit']
   }
 });

grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['uglify','concat','qunit','jshint']);

執行watch任務:

~ D:\workspace\javascript\nodejs-grunt>grunt watch
Running "watch" task
Waiting...OK

#手動修改src/sayBye.js文件,下面watch的任務被觸發
>> File "src\sayBye.js" changed.

Running "jshint:files" (jshint) task
Linting src/sayBye.js ...ERROR
[L3:C2] W033: Missing semicolon.
}
Linting build/nodejs-grunt.cat.js ...ERROR
[L3:C3] W032: Unnecessary semicolon.
};;var sayBye = function(name){
Linting build/nodejs-grunt.min.js ...ERROR
[L2:C42] W033: Missing semicolon.
var sayHello=function(l){return"Hello "+l};

Warning: Task "jshint:files" failed. Use --force to continue.

Aborted due to warnings.
Completed in 0.770s at Sat Aug 17 2013 20:49:15 GMT+0800 (中國標準時間) - Waiting...
相關文章
相關標籤/搜索