一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Grunt 新手一日入門 | 于江水

 瀟湘雨plgwyaef 2016-08-26

Grunt 新手一日入門

2014.06.20

當(dāng)時(shí)學(xué)習(xí) Grunt 的時(shí)候,真是很頭疼。分了兩個(gè)時(shí)間段,學(xué)習(xí)了兩次才硬啃下來,之后才能用在項(xiàng)目中。主要原因我認(rèn)為是學(xué)習(xí)資料和文檔上面寫的太高端了。這類的文檔或者資料有個(gè)顯著特點(diǎn),上來先簡單介紹一下這個(gè)玩意(Grunt 是一個(gè) JavaScript 任務(wù)運(yùn)行器),然后就是如何安裝,直接給你配置文件的語法,如何使用插件,新手往往看完還不知所以然。

就像我第一次學(xué)習(xí)的時(shí)候,只是大體知道 Grunt 很火,大家都在用,但耐著心看文檔和一些別人的學(xué)習(xí)總結(jié),還是困惑,這到底是個(gè)什么東西?究竟干什么用?為什么要這么麻煩配置這些東西?

到現(xiàn)在應(yīng)用在項(xiàng)目中也有一小段時(shí)間了,稍微有一點(diǎn)點(diǎn)經(jīng)驗(yàn),好吧,我決定寫一篇即便是新手也能馬上看懂的文章。

用途和使用場景

先不要管 Grunt,我們先來看下微硬公司小明和小紅的日常前端開發(fā)工作:

小明在開發(fā)一個(gè) JS 插件,寫了好多代碼,終于寫完了,放在 HTML 文件里調(diào)用一看,console 里面好多 error,于是就挨個(gè)調(diào)整修改。為了排除深層潛在問題,他還打開了 http://www./ 這個(gè)網(wǎng)站,把自己的代碼復(fù)制進(jìn)去用 jshint 檢測了,結(jié)果發(fā)現(xiàn)了好多細(xì)節(jié)問題和不規(guī)范的地方,依次修改。最后要發(fā)布了,他又打開了 http://tool./ 網(wǎng)站,把自己的代碼復(fù)制進(jìn)去,使用 Uglify 來壓縮了一下,提供一個(gè)壓縮版本。然后上傳到了 Github 上托管。

這時(shí)候,Github 突然有一個(gè) Issue,他看了一下,原來有個(gè)疏忽的地方,又進(jìn)行了修改,然后打開 jsHint 和 Uglify 在線壓縮網(wǎng)站進(jìn)行檢查和壓縮,再次發(fā)布上去。

于此同時(shí),小紅在做一個(gè)活動(dòng)頁面的前端重構(gòu)工作。她打開了正在做的 HTML 頁面,由于使用了 Sass,所以她打開了 Koala 在后臺(tái)幫她自動(dòng)編譯成 CSS,但是每次保存一下,想要看到效果,還是需要切換到瀏覽器,刷新一下。做交互處理的時(shí)候,她寫了一些 JS,為了規(guī)范,也使用 jshint 檢查了一下。終于做完了,這時(shí)候做了一下最后的優(yōu)化處理準(zhǔn)備上線,她把 icons 在 Photoshop 中合并成了一張圖片,并在 CSS 的對(duì)應(yīng)位置修改了一下,然后用在線壓縮工具把 CSS 和 JS 都?jí)嚎s了一遍,提交測試去了。

這就是他倆的工作,日復(fù)一日年復(fù)一年,有一天,小明終于受夠了,朝小紅發(fā)牢騷:哥要是再來回復(fù)制粘貼到網(wǎng)站上排錯(cuò)壓縮,哥就是逗逼!小紅滿眼淚花的說,你想好辦法了,幫我解決一下自動(dòng)刷新問題,我也受夠了。

于是小明工作都不做了,開始苦思冥想怎么開發(fā)一個(gè)可以自動(dòng)把寫的代碼發(fā)送到遠(yuǎn)程網(wǎng)站,讓他們檢查一下錯(cuò)誤并且壓縮好,再反回來生成一個(gè)文件。

開發(fā)一個(gè)任務(wù)自動(dòng)處理器

當(dāng)然,小明很快就不那么想了,因?yàn)橐蕾囃獠烤W(wǎng)站有很多意外因素,而且受限于網(wǎng)絡(luò)和網(wǎng)速,其次他們也沒提供有關(guān)接口來調(diào)用。但是他們都提供了一些算法之類的工具等。這樣可以在本地調(diào)用這些工具,來完成這些操作,甚至連網(wǎng)絡(luò)也不需要。

小明愉快的開始在筆記本上構(gòu)思這個(gè)工具的開發(fā)方法和需要的功能:

首先我需要先開發(fā)一個(gè)工具,可以調(diào)用這個(gè)工具對(duì)我的某個(gè)項(xiàng)目目錄里面的項(xiàng)目文件做一些操作,比如壓縮、查錯(cuò)、合并等。

如果要做成一個(gè)工具,可能不太好,或許別人還需要更多功能,但是我沒法開發(fā)這么多功能啊。要不我就做個(gè)框架把,然后每個(gè)功能做成一個(gè)插件,比如壓縮插件、合并插件。如果有人需要在他的項(xiàng)目里壓縮某個(gè)文件,他安裝一下我這個(gè)工具然后再安裝壓縮插件就好了。這樣有更多需求的人,可以自己編寫功能插件,然后配合我的工具使用。

慢著,他安裝完了工具和插件之后,要怎么來調(diào)用這個(gè)插件來處理項(xiàng)目文件?在程序界面上選擇文件,然后勾選選項(xiàng)?我的天,我就會(huì)寫點(diǎn) JS,哪里可能開發(fā)帶有界面的程序?慢著,用 JS ?他可以在項(xiàng)目文件夾中編寫一個(gè) JS 來設(shè)置任務(wù)??!然后我的工具會(huì)讀取這個(gè) JS,解析之后獲得他要執(zhí)行的任務(wù)(比如壓縮某某文件并改名成某某),然后調(diào)用插件完成任務(wù)。

太棒了。但是插件這么多,放在項(xiàng)目里肯定很大,而且又是不相關(guān)代碼,要不等他發(fā)布的時(shí)候自動(dòng)刪除這些插件文件把?不行,如果他要發(fā)給別人,別人要繼續(xù)開發(fā),還得重新安裝依次安裝這些插件,然后執(zhí)行任務(wù)。那怎么辦?要不我再用個(gè)文件記錄一下當(dāng)前項(xiàng)目中安裝或者需要的插件把!這樣只需要把這個(gè)文件和 JS 任務(wù)文件放在項(xiàng)目目錄里面,有需要的人,直接輸入一條命令安裝一下,然后立刻就可以執(zhí)行了。

我太聰明了!

贊

于是小明興奮的跑過去給小紅講了一下他的工具的開發(fā)思路,然后告訴她,他可以幫忙寫一個(gè)自動(dòng)刷新的插件。小紅反而淡定的說:等等,我好像見過這種東西,這不是 Grunt 嘛?

小明抓緊搜了一下 Grunt,看了一下文檔之后,對(duì)著小紅:尼瑪,你為什么不早說!

開始學(xué)習(xí) Grunt

Grunt 就是小明想的這樣一種自動(dòng)化任務(wù)處理工具,它就是一個(gè)工具框架,有很多插件擴(kuò)展它的功能。

Grunt 基于 Node.js ,用 JS 開發(fā),這樣就可以借助 Node.js 實(shí)現(xiàn)跨系統(tǒng)跨平臺(tái)的桌面端的操作,例如文件操作等等。此外,Grunt 以及它的插件們,都作為一個(gè) 包 ,可以用 NPM 安裝進(jìn)行管理。

所以 NPM 生成的 package.json 項(xiàng)目文件,里面可以記錄當(dāng)前項(xiàng)目中用到的 Grunt 插件,而 Grunt 會(huì)調(diào)用 Gruntfile.js 這個(gè)文件,解析里面的任務(wù)(task)并執(zhí)行相應(yīng)操作。

如果你對(duì) Node.js、NPM 這些名詞不太熟悉,建議先去搜索了解一下,因?yàn)橄旅娴拿顣?huì)涉及到它們,但是本文不會(huì)過多介紹。

安裝 Grunt

Grunt 依賴 Node.js 所以在安裝之前確保你安裝了 Node.js。然后開始安裝 Grunt。

實(shí)際上,安裝的并不是 Grunt,而是 Grunt-cli,也就是命令行的 Grunt,這樣你就可以使用 grunt 命令來執(zhí)行某個(gè)項(xiàng)目中的 Gruntfile.js 中定義的 task 。但是要注意,Grunt-cli 只是一個(gè)命令行工具,用來執(zhí)行,而不是 Grunt 這個(gè)工具本身。

安裝 Grunt-cli 需要使用 NPM,使用下面一行即可在全局范圍安裝 Grunt-cli ,換句話說,就是你可以在任何地方執(zhí)行 grunt 命令:

npm install -g grunt-cli

需要注意,因?yàn)槭褂?-g 命令會(huì)安裝到全局,可能會(huì)涉及到系統(tǒng)敏感目錄,如果用 Windows 的話,可能需要你用管理員權(quán)限,如果用 OS X / Linux 的話,你可能需要加上 sudo 命令。

下面我們新建一個(gè)項(xiàng)目目錄,并新建一些文件,這里我準(zhǔn)備了一份很簡單的項(xiàng)目,放在了 Github 上,下面操作將以此來操作,你可以下載或者 clone 下來: https://github.com/yujiangshui/gruntxx

生成 package.json 文件

這個(gè) package.json 文件其實(shí)是 Node.js 來描述一個(gè)項(xiàng)目的文件,JSON 格式。生成這個(gè)文件超級(jí)簡單,推薦用命令行交互式的生成一下:

打開命令行,cd gruntxx 文件夾下面,輸入指令 npm init 之后,就出來很多信息,然后開始填寫項(xiàng)目名稱,填寫好了之后回車即可。其實(shí)這里你一路回車下去也無妨,但是建議你細(xì)細(xì)的填一下,不明白的跳過好了。

npm init 填寫項(xiàng)目信息

填寫好了之后,查看目錄就會(huì)發(fā)現(xiàn)生成 package.json 文件了,這樣就算生成好了。

其實(shí)就是一個(gè)文件而已,你覺得這種方式麻煩,完全可以新建一個(gè)文件,然后將類似下面的代碼復(fù)制進(jìn)去,改一下對(duì)應(yīng)選項(xiàng),保存成 package.json 文件就可以:

{ 'name': 'my-project-name', 'version': '0.1.0', 'devDependencies': { } }

最后我生成的代碼如下:

{ 'name': 'gruntxx', 'version': '0.0.1', 'description': '學(xué)習(xí) grunt', 'repository': { 'type': 'git', 'url': 'https://github.com/yujiangshui/gruntxx.git' }, 'author': 'Jiangshui', 'license': 'MIT', 'bugs': { 'url': 'https://github.com/yujiangshui/gruntxx/issues' }, 'homepage': 'https://github.com/yujiangshui/gruntxx' }

但這時(shí)我們還沒有在項(xiàng)目文件中安裝 Grunt 以及相關(guān)任務(wù)插件。

安裝 Grunt 和所需要的插件

就現(xiàn)在的這個(gè)示例項(xiàng)目而言,我打算讓 Grunt 幫忙實(shí)現(xiàn)下面幾個(gè)功能:檢查每個(gè) JS 文件語法、合并兩個(gè) JS 文件、將合并后的 JS 文件壓縮、將 SCSS 文件編譯、新建一個(gè)本地服務(wù)器監(jiān)聽文件變動(dòng)自動(dòng)刷新 HTML 文件。

差不多就是這些,根據(jù)這些任務(wù)需求,需要用到:

它們的命名和文檔都很規(guī)范,因?yàn)檫@些是官方提供的比較常用的插件。這些插件同時(shí)都是 NPM 管理的包,比如 grunt-contrib-concat - npm 你也可以在這上面看到用法等。

下面我們就要在這個(gè)項(xiàng)目中安裝這些插件,執(zhí)行命令:

npm install grunt --save-dev

表示通過 npm 安裝了 grunt 到當(dāng)前項(xiàng)目,同時(shí)加上了 –save-dev 參數(shù),表示會(huì)把剛安裝的東西添加到 package.json 文件中。不信你打開 package.json 文件看下,是不是多了

'devDependencies': { 'grunt': '^0.4.5' }

沒錯(cuò),這個(gè)的意思就是當(dāng)前項(xiàng)目依賴 grunt,后面是它的版本,咱們不用管。如果安裝的時(shí)候沒有添加 –save-dev 參數(shù),這里就不會(huì)出現(xiàn)了,你需要自行添加上去。

下面我們來安裝 Grunt 的插件,當(dāng)然,不需要一個(gè)個(gè)的安裝,太麻煩了,我們可以:

npm install --save-dev grunt-contrib-concat grunt-contrib-jshint grunt-contrib-sass grunt-contrib-uglify grunt-contrib-watch grunt-contrib-connect

等待一大串亂七八糟的下載狀態(tài),我們把 grunt 和相關(guān)插件都安裝好了,不信看下是不是多了一個(gè) node_modules 文件夾?打開看下,里面就是咱們剛安裝的插件。

配置 Gruntfile.js 的語法

插件也裝好了,開始寫任務(wù)吧!既然是要程序來讀取執(zhí)行,必要要有一定的語法規(guī)范,下面來簡單的說一下:

首先要明白,這是一個(gè) JS 文件,你可以寫任意的 JS 代碼,比如聲明一個(gè) 對(duì)象 來存儲(chǔ)一會(huì)要寫任務(wù)的參數(shù),或者是一個(gè)變量當(dāng)作開關(guān)等等。

然后,所有的代碼要包裹在

module.exports = function(grunt) { ... };

里面。沒有為什么。

在這里面的代碼,除去你自己寫的亂七八糟的 JS,與 Grunt 有關(guān)的主要有三塊代碼:任務(wù)配置代碼插件加載代碼、任務(wù)注冊(cè)代碼

顧名思義,這三塊代碼,任務(wù)配置代碼就是調(diào)用插件配置一下要執(zhí)行的任務(wù)和實(shí)現(xiàn)的功能,插件加載代碼就是把需要用到的插件加載進(jìn)來,任務(wù)注冊(cè)代碼就是注冊(cè)一個(gè) task,里面包含剛在前面編寫的任務(wù)配置代碼。

這樣,就可以用 grunt 來執(zhí)行注冊(cè)的一個(gè) task 從而根據(jù)任務(wù)配置代碼調(diào)用需要的插件來執(zhí)行相應(yīng)的操作。

下面來分別看一下這三塊代碼的寫法。

任務(wù)配置代碼

例如下面代碼:

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' } } });

可以看出,具體的任務(wù)配置代碼以對(duì)象格式放在 grunt.initConfig 函數(shù)里面,其中先寫了一句 pkg: grunt.file.readJSON('package.json') 功能是讀取 package.json 文件,并把里面的信息獲取出來,方便在后面任務(wù)中應(yīng)用(例如下面就用了 <%= pkg.name %> 來輸出項(xiàng)目名稱),這樣可以提高靈活性。之后就是 uglify 對(duì)象,這個(gè)名字是固定的,表示下面任務(wù)是調(diào)用 uglify 插件的,首先先配置了一些全局的 options 然后新建了一個(gè) build 任務(wù)。

也就是說,在 Uglify 插件下面,有一個(gè) build 任務(wù),內(nèi)容是把 XX.js 壓縮輸出到 xx.min.js 里面。如果你需要更多壓縮任務(wù),也可以參照 build 多寫幾個(gè)任務(wù)。

至于怎么寫出來 options 里面的參數(shù)和 build 里面的參數(shù)內(nèi)容,這才是 grunt 學(xué)習(xí)的難點(diǎn),你需要查看每個(gè)插件的用法,根據(jù)用法來編寫任務(wù),可以看下 grunt-contrib-uglify 的官方文檔,往下面拉你就可以看到參數(shù)和使用方法了。

這樣,我們就新建了一個(gè)基于 uglify 的任務(wù) build,功能是把 src/<%= pkg.name %>.js 壓縮輸出 build/<%= pkg.name %>.min.js。

插件加載代碼

這個(gè)就超級(jí)簡單了,由于上面任務(wù)需要用到 grunt-contrib-uglify,當(dāng) grunt-contrib-uglify 安裝到我們的項(xiàng)目之后,寫下下面代碼即可加載:

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

任務(wù)注冊(cè)代碼

插件也加載了,任務(wù)也布置了,下面我們得注冊(cè)一下任務(wù),使用

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

來注冊(cè)一個(gè)任務(wù)。上面代碼意思是,你在 default 上面注冊(cè)了一個(gè) Uglify 任務(wù),default 就是別名,它是默認(rèn)的 task,當(dāng)你在項(xiàng)目目錄執(zhí)行 grunt 的時(shí)候,它會(huì)執(zhí)行注冊(cè)到 default 上面的任務(wù)。

也就是說,當(dāng)我們執(zhí)行 grunt 命令的時(shí)候,uglify 的所有代碼將會(huì)執(zhí)行。我們也可以注冊(cè)別的 task,例如:

grunt.registerTask('compress', ['uglify:build']);

如果想要執(zhí)行這個(gè) task,我們就不能只輸入 grunt 命令了,我們需要輸入 grunt compress 命令來執(zhí)行這條 task,而這條 task 的任務(wù)是 uglify 下面的 build 任務(wù),也就是說,我們只會(huì)執(zhí)行 uglify 里面 build 定義的任務(wù),而不會(huì)執(zhí)行 uglify 里面定義的其他任務(wù)。

這里需要注意的是,task 的命名不能與后面的任務(wù)配置同名,也就是說這里的 compress 不能命名成 uglify,這樣會(huì)報(bào)錯(cuò)或者產(chǎn)生意外情況

OK,加上這三塊代碼,我們的示例 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']); };

這就是官方那個(gè)坑爹示例,貌似 uglify 的參數(shù)好像不對(duì),反正我之前學(xué)習(xí)的時(shí)候,沒法運(yùn)行這個(gè)配置,下面我們來根據(jù)示例項(xiàng)目和我們的需求配置一下。

配置 Gruntfile.js

先從簡單的入手,我們先來配置一下編譯 Scss 文件的 task。先新建一個(gè) Gruntfile.js 文件,把大體的配置結(jié)構(gòu)復(fù)制進(jìn)去:

module.exports = function(grunt) { var sassStyle = 'expanded'; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { } }); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.registerTask('outputcss',['sass']); grunt.registerTask('default'); };

應(yīng)該可以看懂把?這里不再贅述了,我們來根據(jù) Sass 文檔,編寫一個(gè) Sass 任務(wù) output :

module.exports = function(grunt) { var sassStyle = 'expanded'; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { output : { options: { style: sassStyle }, files: { './style.css': './scss/style.scss' } } } }); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.registerTask('outputcss',['sass']); grunt.registerTask('default'); };

意思就是將 ./scss/style.scss 這個(gè)文件以 sassStyle 變量存儲(chǔ)的方式編譯成 根目錄下面的 style.css 文件。

下面拿起命令行,cd 到當(dāng)前文檔目錄,執(zhí)行一下 grunt 命令,結(jié)果報(bào)錯(cuò) undefined,沒錯(cuò),因?yàn)槲覀兊?default task 里面沒有定義任何任務(wù),然后執(zhí)行 grunt outputcss 命令,提示編譯 Scss 文件成功,當(dāng)然前提是你的 Scss 語法正確,如果有問題就不會(huì)成功。

grunt 執(zhí)行任務(wù)

下面我們打算先把 src 目錄下面的兩個(gè) JS 文件合并起來,然后再用 jshint 檢測一下是否有語法問題,如果正確,再用 uglify 對(duì)合并起來的文件進(jìn)行壓縮。

參照 grunt-contrib-concat 的官方文檔,我們可以寫出下面的任務(wù):

module.exports = function(grunt) { var sassStyle = 'expanded'; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { output : { options: { style: sassStyle }, files: { './style.css': './scss/style.scss' } } }, concat: { options: { separator: ';', }, dist: { src: ['./src/plugin.js', './src/plugin2.js'], dest: './global.js', }, } }); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.registerTask('outputcss',['sass']); grunt.registerTask('concatjs',['concat']); grunt.registerTask('default'); };

執(zhí)行 grunt concatjs 之后,就會(huì)發(fā)現(xiàn)根目錄多了一個(gè) global.js 文件,里面是兩個(gè)文件合并起來的。然后類似的繼續(xù)看 uglify 和 jshint 的文檔,我們就可以根據(jù)需求寫出下面任務(wù):

module.exports = function(grunt) { var sassStyle = 'expanded'; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { output : { options: { style: sassStyle }, files: { './style.css': './scss/style.scss' } } }, concat: { options: { separator: ';', }, dist: { src: ['./src/plugin.js', './src/plugin2.js'], dest: './global.js', }, }, uglify: { compressjs: { files: { './global.min.js': ['./global.js'] } } }, jshint: { all: ['./global.js'] } }); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('outputcss',['sass']); grunt.registerTask('concatjs',['concat']); grunt.registerTask('compressjs',['concat','jshint','uglify']); grunt.registerTask('default'); };

其中注冊(cè)了一個(gè) compressjs 任務(wù) grunt.registerTask('compressjs',['concat','jshint','uglify']); 意思就是依次執(zhí)行 合并、檢查、壓縮 任務(wù)。我們把剛生成的 global.js 文件刪掉,在命令行執(zhí)行 grunt compressjs 任務(wù),結(jié)果 jshint 報(bào)錯(cuò)了:

grunt jshint 報(bào)錯(cuò)

grunt 遇到錯(cuò)誤就退出了,就沒法繼續(xù)執(zhí)行下面的任務(wù)。通過錯(cuò)誤提示可以發(fā)現(xiàn),是因?yàn)?concat 里面設(shè)置的參數(shù)——在兩個(gè)文件合并間插入一個(gè)“;”——這本來是為了防止兩個(gè)文件之間相互干擾設(shè)置的,結(jié)果無法被 jshint 驗(yàn)證通過,我們可以刪掉這個(gè)參數(shù),或者設(shè)置 jshint 驗(yàn)證這兩個(gè)文件,然后再進(jìn)行合并。

為了方便,我刪掉了這個(gè)參數(shù)。再執(zhí)行一下,成功了,項(xiàng)目目錄里面多了 global.js 和 global.min.js 文件。

小明看到這里,痛哭流淚,自己每次打開好幾個(gè)網(wǎng)站,辛苦挨個(gè)粘貼復(fù)制新建,沒想到輸入一條命令就可以了。不過讓他更傷心的還在后面,連這些命令都不用重復(fù)輸入。

我們可以通過 watch 來監(jiān)聽文件變動(dòng),當(dāng)文件變化了(我們編寫保存了),自動(dòng)執(zhí)行某些任務(wù)。此處為了節(jié)約版面,我連自動(dòng)刷新的任務(wù)一塊寫上去。根據(jù) grunt-contrib-watchgrunt-contrib-connect 這倆文檔,我們可以寫出下面的任務(wù):

module.exports = function(grunt) { var sassStyle = 'expanded'; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { output : { options: { style: sassStyle }, files: { './style.css': './scss/style.scss' } } }, concat: { dist: { src: ['./src/plugin.js', './src/plugin2.js'], dest: './global.js', }, }, uglify: { compressjs: { files: { './global.min.js': ['./global.js'] } } }, jshint: { all: ['./global.js'] }, watch: { scripts: { files: ['./src/plugin.js','./src/plugin2.js'], tasks: ['concat','jshint','uglify'] }, sass: { files: ['./scss/style.scss'], tasks: ['sass'] }, livereload: { options: { livereload: '<%= connect.options.livereload %>' }, files: [ 'index.html', 'style.css', 'js/global.min.js' ] } }, connect: { options: { port: 9000, open: true, livereload: 35729, // Change this to '0.0.0.0' to access the server from outside hostname: 'localhost' }, server: { options: { port: 9001, base: './' } } } }); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-connect'); grunt.registerTask('outputcss',['sass']); grunt.registerTask('concatjs',['concat']); grunt.registerTask('compressjs',['concat','jshint','uglify']); grunt.registerTask('watchit',['sass','concat','jshint','uglify','connect','watch']); grunt.registerTask('default'); };

添加了 connect 任務(wù),用來新建一個(gè)本地服務(wù)器,以當(dāng)前目錄作為服務(wù)器根目錄,然后添加 watch 任務(wù),監(jiān)聽 Scss 文件變動(dòng),如果變了,執(zhí)行一下 sass 任務(wù),監(jiān)聽那倆 JS,如果變了,執(zhí)行 合并、檢查、壓縮 任務(wù),監(jiān)聽 html、css、js 文件,如果變動(dòng),livereload 自動(dòng)刷新打開的頁面。

而注冊(cè)的 watchit task 就是我們的終極 task,第一次執(zhí)行,先編譯 sass、再合并、檢查、壓縮、開啟服務(wù)器、監(jiān)聽文件變動(dòng)。我們執(zhí)行一下 grunt watchit 就可以看到效果了,你可以修改一下 scss 文件,把字體設(shè)置大一點(diǎn),切換到瀏覽器的時(shí)候,就看到了實(shí)時(shí)刷新效果。也可以修改一下 JS,故意改錯(cuò)一下,會(huì)發(fā)現(xiàn) jshint 會(huì)提示你出錯(cuò)了。

grunt watch task

看到這里,小明和小紅相擁而泣。。。。

項(xiàng)目文件傳輸與協(xié)作

項(xiàng)目開發(fā)完成之后,往往需要 push 到 Github 或者上傳 FTP 等?;蛟S其他人會(huì)接手你的項(xiàng)目繼續(xù)開發(fā),或者你會(huì)換臺(tái)電腦進(jìn)行開發(fā)。

當(dāng)小明用 git 上傳 Github 的時(shí)候,傻了眼,項(xiàng)目里 node_modules 文件夾下面的東西要十幾M呢,這比我項(xiàng)目本身還大,上傳下載都不方便。

其實(shí)這些插件和 grunt 不需要上傳,因?yàn)橛?package.json 這個(gè)文件記錄了你這個(gè)項(xiàng)目中依賴的 grunt 插件,你只需要上傳這個(gè)文件即可。下載下來之后,只需要在這個(gè)項(xiàng)目文件夾下面,輸入命令 npm install,NPM 會(huì)自動(dòng)讀取 package.json 文件,將 grunt 和有關(guān)插件給你下載下來,很方便的。

也不需要在本地上傳的時(shí)候刪除,用 git 的話,可以使用 .gitignore 文件來過濾掉這個(gè)文件夾,禁止 git 追蹤。

總結(jié)與擴(kuò)展閱讀

Grunt 就是這樣一種任務(wù)自動(dòng)運(yùn)行器,應(yīng)用好它可以減輕很多不必要的人工操作,只需要專注 coding 就可以。甚至還有Grunt 插件幫你自動(dòng)完成 CSS Sprite,更多功能還需要你自己去摸索。

新手看完本文,再看一下 Grunt 官方文檔 應(yīng)該沒有太多疑問了,那就再看一遍把。當(dāng)然也有中文版。

除了 Grunt 之外,同類型比較火的還有 Gulp 這個(gè)工具。其實(shí)兩個(gè)東西的功能是一樣的,只不過是任務(wù)配置 JS 的語法不同,Gulp 的 Gulpfile.js 的寫法更加通俗易懂,上手更快。但是 Gulp 的插件等感覺不如 Grunt,Grunt 官方提供了一些常見的插件,滿足大部分日常工作,而且可靠值得信賴,而 Gulp 好像沒有太多官方出品,各種插件不太規(guī)范。簡單的說,Grunt 和 Gulp 就像 iPhone 與 Android 一樣,一個(gè)質(zhì)量高學(xué)習(xí)難一點(diǎn),一個(gè)學(xué)起來簡單但是有點(diǎn)那個(gè),你懂得。

此外,可以看一些高手的項(xiàng)目,你會(huì)發(fā)現(xiàn)更好的 Grunt 用法,比如 Yeoman 生成的項(xiàng)目,就有很完善的 Grunt 任務(wù)和插件,此外,jQuery 等也用 Grunt 進(jìn)行打包,這些 Grunt 文件你都可以查看研究一下他們的寫法和用法,受益匪淺。

最后,如果你懶得跟著文章一點(diǎn)點(diǎn)的配置示例項(xiàng)目,你也可以跳轉(zhuǎn)到示例項(xiàng)目的 grunt 分支,這里面是我配置好的,你需要先 npm install 然后就可以直接執(zhí)行那些命令。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美精品亚洲精品一区| 国产精品熟女在线视频| 亚洲最新中文字幕在线视频| 婷婷开心五月亚洲综合| 人妻人妻人人妻人人澡| 69精品一区二区蜜桃视频| 国产av天堂一区二区三区粉嫩| 国产大屁股喷水在线观看视频 | 自拍偷拍福利视频在线观看| 91一区国产中文字幕| 午夜精品久久久免费视频| 成年午夜在线免费视频| 男女激情视频在线免费观看| 欧美日韩乱一区二区三区| 91麻豆精品欧美一区| 欧美日韩成人在线一区| 国产精品免费不卡视频| 国产成人免费高潮激情电| 亚洲日本韩国一区二区三区| 国产亚洲成av人在线观看| 欧洲偷拍视频中文字幕| 国产高清精品福利私拍| 亚洲国产精品国自产拍社区| 午夜国产成人福利视频| 中文字幕熟女人妻视频| 草草夜色精品国产噜噜竹菊| 欧洲偷拍视频中文字幕| 91人妻人人澡人人人人精品| 亚洲一区二区三区国产| 久久三级国外久久久三级| 亚洲午夜福利视频在线| 人妻久久一区二区三区精品99| 国产又猛又黄又粗又爽无遮挡| 好吊色欧美一区二区三区顽频| 亚洲伊人久久精品国产| 亚洲国产香蕉视频在线观看| 久久精品国产亚洲熟女| 国产日韩中文视频一区| 久久精品亚洲精品国产欧美| 粉嫩国产美女国产av| 91人妻人人精品人人爽|