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
留言列表