grunt-logo

Grunt 是近期很熱門的 Node.js 開發工具,
根據官方網頁的說法,
他是 JavaScript Task Runner,
柯南雖然看過了一些文章與介紹, 
但一直沒有花太多時間,
試試看到底怎麼使用,
趁著新年假期,
我稍微試了一下之後工作流程可能會用到的 Grunt 與 其 套件 (plugin),
並記錄下來,
算是另類的新年禮物給自己跟需要範例的朋友。

安裝 Grunt

> npm install -g grunt-cli //安裝 grunt 前要安裝 Node.js 最低版本要求要大於 0.8

建立 Node.js Project 

> mkdir grunt101 // grunt101 是 project name
> cd grunt101
> npm init

安裝 grunt 套件

grunt 的套件目前約有 二千多個,我試了以下幾個

> npm install grunt --save-dev
> npm install grunt-contrib-less --save-dev
> npm install grunt-contrib-jshint --save-dev
> npm install grunt-contrib-watch --save-dev
> npm install grunt-nodemon --save-dev
> npm install grunt-concurrent --save-dev
> npm install grunt-shell --save-dev

package.json

以上的指令不僅會幫我們在專案下安裝 grunt 套件,也會在 package.json 產生對應設定

{
  "name": "grunt-test",
  "version": "0.0.1",
  "description": "grunt test",
  "dependencies": {
    "mojito": ">0.8"
  },
  "devDependencies": {
    "grunt": "0.4.2",
    "grunt-contrib-less": "0.9.0",
    "grunt-contrib-watch": "0.5.3",
    "grunt-contrib-jshint": "~0.8.0"
    "grunt-nodemon": "0.2.0",
    "grunt-concurrent": "0.4.3",
    "grunt-shell": "~0.6.4",
  }
}

Grunt.js

Gruntfile.js 或 Gruntfile.coffee 是在專案目錄同一層的設定檔案,我們可以透過這個檔案設定 Grunt 要跑的 task 與 plugin。

目前我測試的完整 Gruntfile 如下:

/*jslint unparam:true */
'use strict';

var path = require('path');

module.exports = function (grunt) {
    grunt.initConfig({
        pkg: require('./package.json'),
        less: {
            development: {
                options: {
                    compress: true
                },
                files: [{
                    expand: true,     // Enable dynamic expansion.
                    cwd: 'less/',
                    dest: 'assets/',
                    src: ['**/*.less'], // Actual pattern(s) to match.
                    //flatten: true,
                    ext: '.css',   // Dest filepaths will have this extension.
                    rename: function (dest, matchedSrcPath, options) {
                        return path.join(dest, matchedSrcPath.replace('les2', 'module/1'));
                    }
                }]
            }
        },
        nodemon: {
            dev: {
                script: 'server.js'
            }
        },
        concurrent: {
            target: {
                tasks: ['less', 'jshint:myFile' ,'watch', 'nodemon'],
                options: {
                    logConcurrentOutput: true
                }
            }
        },
        watch: {
            styles: {
                // Which files to watch (all .less files recursively in the less directory)
                files: ['**/*.less'],
                tasks: ['less'],
                options: {
                    nospawn: true,
                    livereload: true
                }
            },
            jshint: {
                files: ['mojits/**/*.js'],
                tasks: ['jshint:myFile']
            }
        },
        shell: {
            pkgname: {
                options: {
                    stdout: true
                },
                command: 'echo <%= pkg.name %>'
            },
            ll: {
                options: {
                    stdout: true
                },
                command: 'ls -al'
            },
        },
        jshint: {
            options: {

            },
            myFile:  ['mojits/**/*.js']
        }
    });
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-nodemon');
    grunt.loadNpmTasks('grunt-shell');
    grunt.loadNpmTasks('grunt-contrib-jshint');

    grunt.registerTask('default', ['concurrent']);
    grunt.registerTask('ll', ['shell:ll']);
    grunt.registerTask('pkg', ['shell:pkgname']);
};

執行

基本上在專案的根目錄執行

> grunt

就可以執行

grunt 會去執行 一個叫 default 的 task

grunt.registerTask('default', ['concurrent']);

不過我們也可以自己寫其它的 task 在 gruntfile,例如:

grunt.registerTask('ll', ['shell']);

如此一來,我們就可以下

grunt ll

來執行

grunt.registerTask('ll', ['shell']);

中對應的 shell 設定內容

取得其它檔案中的設定值

如果我們想要取得其它檔案(例如 package.json) 的設定值,可以用

pkg: require('./package.json'),

接著用

<%= pkg.name %> 

就可以使用package.json 中 name 這個 key 的 value

grunt-contrib-less

這個外掛,可以幫助我們將 less 產生成 css,透過 files 這個 屬性,我們也可以指定 less 的來源與 css 的目的位置。

grunt-contrib-watch

watch 可以幫我們監視專案中的檔案,並在其變動後,執行設定的 task。

        watch: {
            styles: {
                files: ['**/*.less'],
                tasks: ['less'],
                options: {
                    nospawn: true,
                    livereload: true
                }
            },
            jshint: {
                files: ['mojits/**/*.js'],
                tasks: ['jshint:myFile']
            }
        },

例如,當 less 檔改變時,自動產生 css 檔,js 更新時,跑一下 jshint。

此外,watch 最神奇的地方是 live reload,一但設為 true,只要在 chrome 安裝 Livereload 的外掛

就可以邊改檔案(如less),然後瀏覽器自動反應修改後的狀態,我們不用再重新整理一次瀏覽器。

grunt-concurrent

這可以讓我們同一個task 執行好多子 grunt task

        concurrent: {
            target: {
                tasks: ['less', 'jshint:myFile' ,'watch', 'nodemon'],
                options: {
                    logConcurrentOutput: true
                }
            }
        },

像上面設定,我們就執行了 less, jshint, watch, nodemon 這些子 task

grunt-nodemon

這個外掛,當我們改變了被監視的檔案,就會幫我們重新啟動程式。

grunt-shell

顧名思義,就是可以執行 os 的 shell 指令

grunt-contrib-jshint

grunt 也可以幫我們執行 jshint 檢查 js 有沒有錯誤。

所有的 外掛,要用 loadNpmTasks 來載入

    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-nodemon');
    grunt.loadNpmTasks('grunt-shell');
    grunt.loadNpmTasks('grunt-contrib-jshint');

grunt 實在是很有趣的一個開發工具,這個年假花了一些時間研究,真的一點都不浪費假期呢!

PS: 懶得打 code 的朋友,本文測試的 grunt project 放在 https://github.com/ddsakura/grunt101

    全站熱搜

    賽拉維‧柯南 發表在 痞客邦 留言(0) 人氣()