Gulp探究折騰之路(I)2

文/晚晴幽草(簡書做者)
原文連接:http://www.jianshu.com/p/9768a4dc7cf7
著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。

前言: gulp是前端開發過程當中對代碼進行構建的工具,是自動化項目的構建利器;她不只能對網站資源進行優化,並且在開發過程當中不少重複的任務可以使用正確的工具自動完成;使用她,咱們不只能夠很愉快的編寫代碼,並且大大提升咱們的工做效率。相比於grunt的頻繁 IO 操做,gulp的流操做,能更快地更便捷地完成構建工做。此處僅記錄初步折騰中所遇點滴以及待解決的點。javascript

文章首鏈-晚晴幽草軒php

Gulp折騰之初探

折騰之戰略上的藐視

回過頭看Gulp的折騰歷程,使用仍是很是簡易的。因此戰略上必定要藐視"她";固然戰術上要給予足夠的重視。畢竟要依賴她以及其餘各類插件and編輯器等實現前端工程化,組件化,模塊化,便捷化是一個蠻複雜的過程。總之,折騰伊始須要自信就好,折騰過程帶着耐心就好。譬如,想借助gulp壓縮美化下js代碼,寫以下代碼於gulpfile.js便可:css

var gulp = require('gulp'), uglify = require('gulp-uglify'); var gNeedDealJsFile = './js/*.js'; //javascrip代碼存放路徑 var outPut = "./build/"; //指定輸出文件存放目錄 gulp.task('scripts', function() { return gulp.src(gNeedDealJsFile) .pipe(uglify()) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest(outPut)); });

在gulpfile.js同級目錄運行gulp scripts便可;PS:固然前提是您已經安裝了nodejs,而且使用npm安裝了代碼中須要的插件gulpgulp-uglify與本地。html

摒棄了gulp.run()

gulp的API很簡單,經常使用的也就幾個:watch, task, dest, src;目前已經摒棄了run方法。前端

//建立Default Task:註冊缺省任務 gulp.task('default', function() { gulp.run('jshint', 'scripts'); gulp.watch(workSpace, function() { gulp.run('jshint', 'scripts'); }) });

gulp.run() has been deprecated. Use task dependencies or gulp.watch task triggering instead.java

能夠根據gulp.task(name[, deps], fn)特性寫法替代之。deps:(Array)一個包含任務列表的數組,這些任務會在你當前任務運行以前完成。node

注意: 你的任務是否在這些前置依賴的任務完成以前運行了?請必定要確保你所依賴的任務列表中的任務都使用了正確的異步執行方式:使用一個 callback,或者返回一個 promise 或 stream。linux

//建立Default Task:註冊缺省任務 gulp.task('default', ['jshint' , 'scripts', 'watch']);

折騰gulp.src()

Gulp使用node-glob來從你指定的glob裏面獲取文件,這裏列舉下面的例子來闡述,方便你們理解:git

js/app.js 精確匹配文件
js/.js 僅匹配js目錄下的全部後綴爲.js的文件
js/
/.js 匹配js目錄及其子目錄下全部後綴爲.js的文件
!js/app.js 從匹配結果中排除js/app.js,這種方法在你想要匹配除了特殊文件以外的全部文件時很是管用
*.+(js|css) 匹配根目錄下全部後綴爲.js或者.css的文件
此外,Gulp也有不少其餘的特徵,但並不經常使用。若是你想了解更多的特徵,請查看Minimatch文檔。github

js目錄下包含了壓縮和未壓縮的JavaScript文件,如今咱們想要建立一個任務來壓縮尚未被壓縮的文件,咱們須要先匹配目錄下全部的JavaScript文件,而後排除後綴爲.min.js的文件:

gulp.src(['js/**/*.js', '!js/**/*.min.js'])

使用gulp-jshint()

好吧,不一樣幫派,不一樣俠士,對於代碼的輸出是不一致的。而這JS又沒像Py那般天生帶有美麗的基因。即使出了jshint這樣的好利器,然,也得考慮下兼顧團隊已有的Style。因此,這裏配置得糾結下,微說Gulp之gulp-jshint

gulp.task('lint', function(){ return gulp.src(workSpace) .pipe(jshint()) .pipe(jshint.reporter('YOUR_REPOTER_HERE')); });

這reporter使用"default"的話,就會採用默認蠻嚴格的檢查手段。爲了可以規範而不失靈活的擼起JS,在使用JShint之時,過濾掉哪些不合時宜的寫法(以下寫法就能夠不留情的規避之),就得斟酌下咯。列舉些常見不推薦的寫法,運行時提醒以下:

Missing semicolon. (W033) //丟失分號
['lack'] is better written in dot notation //推薦xx.lack寫法,而不是xx['lack']
You might be leaking a variable (disX) here. (W120) //不推薦連等寫法:好比posX = disX = 0;
'status' is defined but never used. (W098) //不推薦:定義之而不用之
Use '!==' to compare with ''. (W041) //不推薦 "!="或者"=="作變量是否相等判斷。

只對發生更改的 js 文件進行語法檢測

更現實的開發場景是, 項目代碼已存在好久,代碼中有大量的不符合 jshint 規範的代碼。 而根據當前的 gulp 配置,每次發生修改,都會全量檢測一遍全部的文件的語法問題,實際上已存在的問題我並不想在本次提交中修復(同時也是其餘同事寫的,例如不加分號問題,改動量太大)。

結果就是,一啓動 gulp,嘩嘩的語法錯誤提示,根本找不到本身想看的文件檢測結果。這時修改一個文件,又對全部文件作了一次全量檢測,又是嘩嘩的滿屏錯誤提示。而我只關心當前修改的文件檢測結果。

gulp 項目首頁推薦了一個gulp-cached插件,正好解決了這個問題。

npm install gulp-cached --save-dev

配置以下

var gulp = require('gulp'), cache = require('gulp-cached'), jshint = require('gulp-jshint'); gulp.task('jshint', function () { gulp.src('./src/**/*.js') .pipe(cache('jshint')) .pipe(jshint()) .pipe(jshint.reporter('default')); }); gulp.task('watch', function () { gulp.watch('./src/**/*.js', ['jshint']); }); gulp.task('default', ['jshint', 'watch']);

這樣就能清晰的看到剛纔發生修改文件的語法檢測結果了,歐耶。

壓縮-合併-重命名-輸出~JS代碼

壓縮gulp-uglify,挺好;
Ps: 有一款gulp-minify(Desc: Minify JavaScript with UglifyJS2),默認壓縮完畢以後會生成一個帶-min的文件,略煩。

合併gulp-concat;指定合併生成名字便可:

.pipe(concat('all.js'))

重命名: gulp-rename;能夠僅僅爲名字指定後綴(不改變文件後綴)Like This:

.pipe(rename({suffix: '.min'}))

輸出: gulp自帶方法gulp.dest

//outPutPathName: String .pipe(gulp.dest(outPutPathName));

壓縮~CSS代碼(合併-重命名-輸出同上)

壓縮gulp-minify-css;嗯,這個直接將原文件壓縮了,默認沒有改其名字。若是直接輸出到該目錄下,會覆蓋原文件;若要輸出同目錄之下,可改更名字再輸出,Like this:

.pipe(minifycss()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest(outPut));

PS:這個插件(默認)也會幫着幹掉註釋,過濾掉空類(沒有內容的描述)等等。

gulp-load-plugins模塊

通常狀況下,gulpfile.js中的模塊須要一個個加載。

var gulp = require('gulp'), jshint = require('gulp-jshint'), uglify = require('gulp-uglify'), concat = require('gulp-concat'); gulp.task('js', function () { return gulp.src('js/*.js') .pipe(jshint()) .pipe(jshint.reporter('default')) .pipe(uglify()) .pipe(concat('app.js')) .pipe(gulp.dest('build')); });

上面代碼中,除了gulp模塊之外,還加載另外三個模塊。

這種一一加載的寫法,比較麻煩。使用gulp-load-plugins模塊,能夠加載package.json文件中全部的gulp模塊。上面的代碼用gulp-load-plugins模塊改寫,就是下面這樣。

var gulp = require('gulp'), gulpLoadPlugins = require('gulp-load-plugins'), plugins = gulpLoadPlugins(); gulp.task('js', function () { return gulp.src('js/*.js') .pipe(plugins.jshint()) .pipe(plugins.jshint.reporter('default')) .pipe(plugins.uglify()) .pipe(plugins.concat('app.js')) .pipe(gulp.dest('build')); });

上面代碼假設package.json文件包含如下內容。

{
   "devDependencies": { "gulp-concat": "~2.2.0", "gulp-uglify": "~0.2.1", "gulp-jshint": "~1.5.1", "gulp": "~3.5.6" } }

gulp插件的快速安裝

談及了基本應用以後,不得不談下如何快速安裝插件(畢竟,合做開發,彼此都能便捷使用,纔是王道)。對於所使用的插件能夠一個個安裝,同時也能夠批量安裝Like This:

npm install gulp-concat gulp-uglify gulp-jshint [...] gulp-rename --save-dev

--save:將保存配置信息至package.json(package.json是nodejs項目配置文件);
-dev:保存至package.json的devDependencies節點,不指定-dev將保存至dependencies節點;

爲何要保存至package.json?由於node插件包相對來講很是龐大,因此不加入版本管理,將配置信息寫入package.json並將其加入版本管理,其餘開發者對應下載便可(命令提示符執行npm install,則會根據package.json下載全部須要的包)。

對於這塊細節能夠參看gulp詳細入門教程;大概來說就是能夠藉助npm init命令,按照其一步步提示,輸入項目相關信息。完畢以後,加入須要依賴的插件以及版本信息便可(注意:這是一個普通json文件,必定得符合json格式;同時須要安裝的插件版本也得是 <= 線上最新版本)。PS:前文涉及到的插件下載,便可如此配置予以完成:在生成的package.json中加入以下json(2015-10-26日情形):

"devDependencies": { "gulp-concat": "~2.6.0", "gulp-uglify": "~1.4.2", "gulp-jshint": "~1.11.2", "gulp-rename": "~1.2.2", "gulp-minify-css": "~1.2.1", "gulp-cached": "~1.1.0", "gulp": "~3.9.0" }

如此,其餘開發者只需更新gulpfile.js以及這個package.json,運行npm install便可下載gulp所依賴插件於本地,(@ο@) 哇~So Cool。

gulp多項目管理(npm link)

要談下多項目管理了;好比這種場景:對於項目很是多而小,並且彼此間相互獨立;伊始,採用在項目根目錄之下gulpfile.js和package.json(畢竟每一個單獨小項目都來一發單獨配置,豈不是要瘋掉了),會將須要的插件down於根目錄下;而在gulpfile.js中控制所要操做的單個小項目路徑。這樣每次切換項目,都要更改下gulpfile.js,即使將這個分離出來寫一個config.js,也得手動去更改,略略有點蛋疼。幸虧,gulp有npm link,哇哦,體貼如你,夫復何求?

對於npm link的介紹,能夠參見@阮一峯npm模塊管理器一文;咱們能夠將所需的插件,全局環境下載,在單獨項目中link全局環境下插件。如此,不只能夠不用每次都down,並且,依賴的插件須要update,只需一地更新,所link之處都會受益。

具體作法,首先將須要的插件全局環境下Down下來:

npm install gulp gulp-concat gulp-rename gulp-uglify gulp-minify-css gulp-jshint gulp-cached -g

接下來,(若是咱們要使用gulp-concat這個模塊)咱們進入單獨小項目(eg: gulpTest),使用npm link gulp-concat命令會去【mac/linux】/usr/local/lib/node_modules/, 【window】D:\UserProfiles\username\AppData\Roaming\npm\node_modules,目錄下查找名叫gulp-concat的模塊,找到這個模塊後把該的目錄連接到 ~/work/**/gulpTest/node_modules/gulp-concat 這個目錄上來。如此,在此項目小項目中的gulpfile.js中也能夠加以使用了。固然,npm link也支持多個參數:

npm link gulp gulp-concat gulp-rename gulp-uglify gulp-minify-css gulp-jshint gulp-cached

PS:這樣使用時,須要注意忽略掉node_modules目錄下的js/css代碼,gulp.src參數數組中能夠加入'!node_modules/**/*.+(js|css)'以過濾之。


注:即使使用npm link感受也不是一個特別簡潔的方案。而且在使用的時候還遇到了些許問題: 有提問在@segmentFaultgulp如何管理多項目? 以及@V2EX gulp如何管理多項目;熱心碼友也提出了一些可行的建議,好比:配置多個task,或者乾脆使用npm run(畢竟項目過小),或者採用 fbi Node.js庫nodejs-fbi,或者採用nodejs 中的 NODE_PATH@nodejs 中的 NODE_PATH等等;此處有待進一步學習&折騰&擇決; (若有簡潔方案,歡求指點,拜謝)。


gulp-util幸之助

幸好有gulp-util之協助:在折騰的過程當中,不免不會出現奇奇怪怪的問題;然而gulp自己的報錯提示機制真心讓新手的我蛋蛋的憂傷:好比在折騰的過程當中壓縮JS代碼就出現Uglify throws Parse error;但是提示卻...幸虧@stackoverflowUglify throws Parse error一個問答中,大牛給予了明燈般的指導:引入gulp-util;原話以下:

uglify will parse the script content before minifying it. I suspect that one of the browserify source maps are being included in the stream down to uglify. Anyway to find the problem you can use gulp-util's log method to handle uglify's exceptions. Example:
```js
...
var gulpUtil = require('gulp-util');

gulp.task('scripts', function() {
...
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(uglify().on('error', gulpUtil.log)) // notice the error event here
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./web/js'));
});

###**實時刷新頁面** ####**gulp-livereload模塊** `gulp-livereload`模塊用於自動刷新瀏覽器,反映出源碼的最新變化。它除了模塊之外,還須要在瀏覽器中安裝插件,用來配合源碼變化。 [LiveReload](http://livereload.com/)結合了瀏覽器擴展(包括Chrome extension),在發現文件被修改時會實時更新網頁。它能夠和gulp-watch插件或者前面描述的gulp-watch()函數一塊兒使用。下面有一個`gulp-livereload`倉庫中的README文件提到的例子: ```js var gulp = require('gulp'), less = require('gulp-less'), livereload = require('gulp-livereload'), watch = require('gulp-watch'); gulp.task('less', function() { gulp.src('less/*.less') .pipe(watch()) .pipe(less()) .pipe(gulp.dest('css')) .pipe(livereload()); });

這會監聽到全部與less/*.less相匹配的文件的變化。一旦監測到變化,就會生成css並保存,而後從新加載網頁.

BrowserSync

安裝 BrowserSync
您能夠選擇從Node.js的包管理(NPM)庫中 安裝BrowserSync。打開一個終端窗口,運行如下命令:

npm install -g browser-sync

您告訴包管理器下載BrowserSync文件,並在全局下安裝它們,您能夠在全部項目(任何目錄)中使用。

固然您也能夠結合gulpjs或gruntjs構建工具來使用,在您須要構建的項目裏運行下面的命令:

npm install --save-dev browser-sync

啓動 BrowserSync
靜態網站
若是您想要監聽.css文件, 您須要使用服務器模式。 BrowserSync 將啓動一個小型服務器,並提供一個URL來查看您的網站。

// --files 路徑是相對於運行該命令的項目(目錄)
browser-sync start --server --files "css/*.css"

若是您須要監聽多個類型的文件,您只須要用逗號隔開。例如咱們再加入一個.html文件

// --files 路徑是相對於運行該命令的項目(目錄) browser-sync start --server --files "css/*.css, *.html" // 若是你的文件層級比較深,您能夠考慮使用 "**"(表示任意目錄)匹配,任意目錄下任意.css 或 .html文件。 browser-sync start --server --files "**/*.css, **/*.html"

注:在該文件下運行命令,默認須要啓動網站文件:index.html。

動態網站
若是您已經有其餘本地服務器環境PHP或相似的,您須要使用代理模式。 BrowserSync將經過代理URL(localhost:3000)來查看您的網站。

// 主機名能夠是ip或域名 browser-sync start --proxy "主機名" "css/*.css"

在本地建立了一個PHP服務器環境,並經過綁定Browsersync.cn來訪問本地服務器,使用如下命令方式,Browsersync將提供一個新的地址localhost:3000來訪問Browsersync.cn,並監聽其css目錄下的全部css文件。

browser-sync start --proxy "Browsersync.cn" "css/*.css"

參考博文:BrowserSync,迅捷從免F5開始


:使用的時候純路徑好比"Browsersync.cn"尚好着,然而地址後面帶一堆參數時候,就會遇到些問題;暫時還未搞明白以解決之,特注之,待弄懂!!


前端組件html模板化(gulp-tlp2mod)

參考博文:component-html-engine-demo有敘述有Demo,幫了大忙。

爲了前端代碼的模塊化,必要將JS邏輯代碼於佈局模板代碼分離開來(固然還有CSS以及靜態資源也都當分離);初來乍到,遇到問題了,如何把tpl轉變成js呢?,OK既然用了構建工具,那麼天然也有對應的插件吧,果真 gulp-tpl2mod~模板文件轉js插件;再借助require.js, 先使用gulp-tpl2mod把模板轉換成js字符串,而後包裝成一個模塊,再main.js中引用這個模塊就好了,大功告成;如此,項目工程化又前進一步。

折騰之入門所參考文章資料

gulp API 文檔
Gulp入門教程
Gulp開發教程(翻譯)
Gulp:任務自動管理工具
前端構建工具gulp入門教程
gulp plugins 插件介紹
gulp詳細入門教程

相關文章
相關標籤/搜索