Gulp開發教程

來源:互聯網
上載者:User

標籤:

Building With Gulp

===================

原文地址翻譯出處

對網站資源進行最佳化,並使用不同瀏覽器測試並不是網站設計過程中最有意思的部分,但是這個過程中的很多重複的任務能夠使用正確的工具自動完成,從而使效率大大提高,這是讓很多開發人員覺得有趣的地方。

Gulp是一個構建系統,它能通過自動執行常見任務,比如編譯預先處理CSS,壓縮JavaScript和重新整理瀏覽器,來改進網站開發的過程。通過本文,我們將知道如何使用Gulp來改變開發流程,從而使開發更加快速高效。

What Is Gulp?

Gulp是一個構建系統,開發人員可以使用它在網站開發過程中自動執行常見任務。Gulp是基於Node.js構建的,因此Gulp源檔案和你用來定義任務的Gulp檔案都被寫進了JavaScript(或者CoffeeScript)裡。前端開發工程師還可以用自己熟悉的語言來編寫任務去lint JavaScript和CSS、解析模板以及在檔案變動時編譯LESS檔案(當然這些只是一小部分例子)。

Gulp本身雖然不能完成很多任務,但它有大量外掛程式可用,開發人員可以訪問外掛程式頁面或者在npm搜尋gulpplugin就能看到。例如,有些外掛程式可以用來執行JSHint、編譯CoffeeScript,執行Mocha測試,甚至更新版本號碼。

對比其他構建工具,比如Grunt,以及最近流行的Broccoli,我相信Gulp會更勝一籌(請看後面的”Why Gulp?”部分),同時我匯總了一個使用Javascript編寫的構建工具清單,可供大家參考。

Gulp是一個可以在GitHub上找到的開源項目。

Installing Gulp

安裝Gulp的過程十分簡單。首先,需要在全域安裝Gulp包:

npm install -g gulp

 

然後,在項目裡面安裝Gulp:

npm install --save-dev gulp

 

Using Gulp

現在我們建立一個Gulp任務來壓縮JavaScript檔案。首先建立一個名為gulpfile.js的檔案,這是定義Gulp任務的地方,它可以通過gulp命令來運行,接著把下面的代碼放到gulpfile.js檔案裡面。

var gulp = require(‘gulp‘),   uglify = require(‘gulp-uglify‘);gulp.task(‘minify‘, function () {   gulp.src(‘js/app.js‘)      .pipe(uglify())      .pipe(gulp.dest(‘build‘))});

 

然後在npm裡面運行npm install -–save-dev gulp-uglify來安裝gulp-uglify,最後通過運行gulp minify來執行任務。假設js目錄下有個app.js檔案,那麼一個新的app.js將被建立在編譯目錄下,它包含了js/app.js的壓縮內容。想一想,到底發生了什嗎?

我們只在gulpfile.js裡做了一點事情。首先,我們載入gulp和gulp-uglify模組:

var gulp = require(‘gulp‘),    uglify = require(‘gulp-uglify‘);

 

然後,我們定義了一個叫minify的任務,它執行時會調用函數,這個函數會作為第二個參數:

gulp.task(‘minify‘, function () {});

 

最後,也是痛點所在,我們需要定義任務應該做什麼:

gulp.src(‘js/app.js‘)   .pipe(uglify())   .pipe(gulp.dest(‘build‘))

 

如果你對資料流非常熟悉(其實大多數前端開發人員並不熟悉),上面所提供的代碼對你來說就沒有太大意義了。

STREAMS

資料流能夠通過一系列的小函數來傳遞資料,這些函數會對資料進行修改,然後把修改後的資料傳遞給下一個函數。

在上面的例子中,gulp.src()函數用字串匹配一個檔案或者檔案的編號(被稱為“glob”),然後建立一個物件流程來代表這些檔案,接著傳遞給uglify()函數,它接受檔案對象之後返回有新壓縮源檔案的檔案對象,最後那些輸出的檔案被輸入gulp.dest()函數,並儲存下來。

整個資料流動過程如所示: 

當只有一個任務的時候,函數並不會起太大的作用。然而,仔細思考下面的代碼:

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-jshint,gulp-uglify和gulp-concat。

這個任務會讓所有的檔案匹配js/*.js(比如js目錄下的所有JavaScript檔案),並且執行JSHint,然後列印輸出結果,取消檔案縮排,最後把他們合并起來,儲存為build/app.js,整個過程如所示: 

如果你對Grunt 足夠熟悉,就會注意到,Gulp和Grunt的工作方式很不一樣。Grunt不使用資料流,而是使用檔案,對檔案執行單個任務然後儲存到新的檔案中,每個任務都會重複執行所有進程,檔案系統頻繁的處理任務會導致Grunt的運行速度比Gulp慢。

如果想要擷取更加全面的資料流知識,請查看“Stream Handbook”.

GULP.SRC()

gulp.src()方法輸入一個glob(比如匹配一個或多個檔案的字串)或者glob數組,然後返回一個可以傳遞給外掛程式的資料流。

Gulp使用node-glob來從你指定的glob裡面擷取檔案,這裡列舉下面的例子來闡述,方便大家理解:

  • js/app.js 精確匹配檔案
  • js/*.js 僅匹配js目錄下的所有尾碼為.js的檔案
  • js/*/.js 匹配js目錄及其子目錄下所有尾碼為.js的檔案
  • !js/app.js 從匹配結果中排除js/app.js,這種方法在你想要匹配除了特殊檔案之外的所有檔案時非常管用
  • *.+(js|css) 匹配根目錄下所有尾碼為.js或者.css的檔案

此外,Gulp也有很多其他的特徵,但並不常用。如果你想瞭解更多的特徵,請查看Minimatch文檔。

js目錄下包含了壓縮和未壓縮的JavaScript檔案,現在我們想要建立一個任務來壓縮還沒有被壓縮的檔案,我們需要先匹配目錄下所有的JavaScript檔案,然後排除尾碼為.min.js的檔案:

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

 

DEFINING TASKS

gulp.task()函數通常會被用來定義任務。當你定義一個簡單的任務時,需要傳入任務名字和執行函數兩個屬性。

gulp.task(‘greet‘, function () {   console.log(‘Hello world!‘);});

 

執行gulp greet的結果就是在控制台上列印出“Hello world”.

一個任務有時也可以是一系列任務。假設要定義一個任務build來執行css、js、imgs這三個任務,我們可以通過指定一個任務數組而不是函數來完成。

gulp.task(‘build‘, [‘css‘, ‘js‘, ‘imgs‘]);

 

這些任務不是同時進行的,所以你不能認為在js任務開始的時候css任務已經結束了,也可能還沒有結束。為了確保一個任務在另一個任務執行前已經結束,可以將函數和任務數組結合起來指定其依賴關係。例如,定義一個css任務,在執行前需要檢查greet任務是否已經執行完畢,這樣做就是可行的:

gulp.task(‘css‘, [‘greet‘], function () {   // Deal with CSS here});

 

現在,當執行css任務時,Gulp會先執行greet任務,然後在它結束後再調用你定義的函數。

DEFAULT TASKS

你可以定義一個在gulp開始運行時候預設執行的任務,並將這個任務命名為“default”:

gulp.task(‘default‘, function () {   // Your default task});

 

PLUGINS

Gulp上有超過600種外掛程式供你選擇,你可以在外掛程式頁面或者npm上搜尋gulpplugin來瀏覽外掛程式列表。有些擁有“gulpfriendly”標籤的外掛程式,他們不能算外掛程式,但是能在Gulp上正常運行。 需要注意的是,當直接在npm裡搜尋時,你無法知道某一外掛程式是否在黑名單上(你需要滾動到外掛程式頁面底部才能看到)。

大多數外掛程式的使用都很方便,它們都配有詳細的文檔,而且調用方法也相同(通過傳遞檔案物件流程給它),它們通常會對這些檔案進行修改(但是有一些外掛程式例外,比如validators),最後返回新的檔案給下一個外掛程式。

讓我們用前面的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-jshint,gulp-uglify和gulp-concat。開發人員可以參考外掛程式的README文檔,外掛程式有很多配置選項,而且給定的初始值通常能滿足需求。細心的讀者可能會發現,程式中JSHint外掛程式執行了2次,這是因為第一次執行JSHint只是給檔案對象附加了jshint屬性,並沒有輸出。你可以自己讀取jshint的屬性或者傳遞給預設的JSHint的接收函數或者其他的接收函數,比如jshint-stylish.

其他兩個外掛程式的作用很清楚:uglify()函數壓縮代碼,concat(‘app.js’)函數將所有檔案合并到一個叫app.js的檔案中。

GULP-LOAD-PLUGINS

我發現gulp-load-plugin模組十分有用,它能夠自動地從package.json中載入任意Gulp外掛程式然後把它們附加到一個對象上。它的基本用法如下所示:

var gulpLoadPlugins = require(‘gulp-load-plugins‘),    plugins = gulpLoadPlugins();

 

你可以把所有代碼寫到一行,但是我並不推薦這樣做。

在執行那些代碼之後,外掛程式對象就已經包含了外掛程式,並使用“駝峰式”的方式進行命名(例如,gulp-ruby-sass將被載入成plugins.rubySass),這樣就可以很方便地使用了。例如,前面的js任務簡化為如下:

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檔案會把它們簡化成一兩行代碼。

三月初發布的Gulp-load-plugins0.4.0版本添加了消極式載入功能,提高了外掛程式的效能,因為外掛程式在使用的時候才會被載入進來,你不用擔心package.json裡未被使用的外掛程式影響效能(但是你需要把他們清理掉)。換句話說,如果你在執行任務時只需要兩個外掛程式,那麼其他不相關的外掛程式就不會被載入。

WATCHING FILES

Gulp可以監聽檔案的修改動態,然後在檔案被改動的時候執行一個或多個任務。這個特性十分有用(對我來說,這可能是Gulp中最有用的一個功能)。你可以儲存LESS檔案,接著Gulp會自動把它轉換為CSS檔案並更新瀏覽器。

使用gulp.watch()方法可以監聽檔案,它接受一個glob或者glob數組(和gulp.src()一樣)以及一個任務數組來執行回調。

讓我們看看下面,build任務可以將模板轉換成html格式,然後我們希望定義一個watch任務來監聽模板檔案的變化,並將這些模板轉換成html格式。watch函數的使用方法如下所示:

gulp.task(‘watch‘, function () {   gulp.watch(‘templates/*.tmpl.html‘, [‘build‘]);});

 

現在,當改變一個模板檔案時,build任務會被執行並產生HTML檔案,也可以給watch函數一個回呼函數,而不是一個任務數組。在這個樣本中,回呼函數有一個包含觸發回呼函數資訊的event對象:

gulp.watch(‘templates/*.tmpl.html‘, function (event) {   console.log(‘Event type: ‘ + event.type); // added, changed, or deleted   console.log(‘Event path: ‘ + event.path); // The path of the modified file});

 

Gulp.watch()的另一個非常好的特性是返回我們熟知的watcher。利用watcher來監聽額外的事件或者向watch中添加檔案。例如,在執行一系列任務和調用一個函數時,你就可以在返回的watcher中添加監聽change事件:

var watcher = gulp.watch(‘templates/*.tmpl.html‘, [‘build‘]);watcher.on(‘change‘, function (event) {   console.log(‘Event type: ‘ + event.type); // added, changed, or deleted   console.log(‘Event path: ‘ + event.path); // The path of the modified file});

 

除了change事件,還可以監聽很多其他的事件:

  • end 在watcher結束時觸發(這意味著,在檔案改變的時候,任務或者回調不會執行)
  • error 在出現error時觸發
  • ready 在檔案被找到並正被監聽時觸發
  • nomatch 在glob沒有匹配到任何檔案時觸發

Watcher對象也包含了一些可以調用的方法:

  • watcher.end() 停止watcher(以便停止執行後面的任務或者回呼函數)
  • watcher.files() 返回watcher監聽的檔案清單
  • watcher.add(glob) 將與指定glob相匹配的檔案添加到watcher(也接受可選的回調當第二個參數)
  • watcher.remove(filepath) 從watcher中移除個別檔案
Reloading Changes In The Browser

當一個檔案被修改或者Gulp任務被執行時可以用Gulp來載入或者更新網頁。LiveReload和BrowserSync外掛程式就可以用來實現在遊覽器中載入更新的內容。

LIVERELOAD

LiveReload結合了瀏覽器延伸(包括Chrome extension),在發現檔案被修改時會即時更新網頁。它可以和gulp-watch外掛程式或者前面描述的gulp-watch()函數一起使用。下面有一個gulp-livereload倉庫中的README檔案提到的例子:

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

BroserSync在瀏覽器中展示變化的功能與LiveReload非常相似,但是它有更多的功能。

當你改變代碼的時候,BrowserSync會重新載入頁面,或者如果是css檔案,會直接添加進css中,頁面並不需要再次重新整理。這項功能在網站是禁止重新整理的時候是很有用的。假設你正在開發單頁應用的第4頁,重新整理頁面就會導致你回到開始頁。使用LiveReload的話,你就需要在每次改變代碼之後還需要點擊四次,而當你修改CSS時,插入一些變化時,BrowserSync會直接將需要修改的地方添加進CSS,就不用再點擊回退。

BrowserSync提供了一種在多個瀏覽器裡測試網頁的很好方式(查看大圖)。

BrowserSync也可以在不同瀏覽器之間同步點擊翻頁、表單操作、滾動位置。你可以在電腦和iPhone上開啟不同的瀏覽器然後進行操作。所有裝置上的連結將會隨之變化,當你向下滾動頁面時,所有裝置上頁面都會向下滾動(通常還很流暢!)。當你在表單中輸入文本時,每個視窗都會有輸入。當你不想要這種行為時,也可以把這個功能關閉。

BrowserSync不需要使用瀏覽器外掛程式,因為它本身就可以給你提供檔案。(查看大圖)

BrowserSync不需要使用瀏覽器外掛程式,因為它本身就可以為你提供檔案服務(如果檔案是動態,則為他們提供代理服務)和用來開啟瀏覽器和伺服器之間的socket的指令碼服務。到目前為止這個功能的使用都十分順暢。

實際上BrowserSync對於Gulp並不算一種外掛程式,因為BrowserSync並不像一個外掛程式一樣操作檔案。然而,npm上的BrowserSync模組能在Gulp上被直接調用。

首先,需要通過npm安裝一下:

npm install --save-dev browser-sync

然後gulpfile.js會啟動BrowserSync並監聽檔案:

var gulp = require(‘gulp‘),    browserSync = require(‘browser-sync‘);gulp.task(‘browser-sync‘, function () {   var files = [      ‘app/**/*.html‘,      ‘app/assets/css/**/*.css‘,      ‘app/assets/imgs/**/*.png‘,      ‘app/assets/js/**/*.js‘   ];   browserSync.init(files, {      server: {         baseDir: ‘./app‘      }   });});

 

執行gulp browser-sync後會監聽匹配檔案的變化,同時為app目錄提供檔案服務。

此外BrowserSync的開發人員還寫了很多關於BrowserSync+Gulp倉庫的其他用途。

Why Gulp?

前面提到過,Gulp是為數不多的使用JavaScript開發的構建工具之一,也有其他不是用JavaScript開發的構建工具,比如Rake,那麼我們為什麼要選擇Gulp呢?

目前最流行的兩種使用JavaScript開發的構建工具是Grunt和Gulp。Grunt在2013年非常流行,因為它徹底改變了許多人開發網站的方式,它有上千種外掛程式可供使用者使用,從linting、壓縮、合并代碼到使用Bower安裝程式包,啟動Express服務都能辦到。這些和Gulp的很不一樣,Gulp只有執行單個小任務來處理檔案的外掛程式,因為任務都是JavaScript(和Grunt使用的大型物件不同),根本不需要外掛程式,你只需用傳統方法啟動一個Express服務就可以了。

Grunt任務擁有大量的配置,會引用大量你實際上並不需要的對象屬性,但是Gulp裡同樣的任務也許只有幾行。讓我們看個簡單的Gruntfile.js,它規定一個將LESS轉換為CSS的任務,然後執行Autoprefixer:

grunt.initConfig({   less: {      development: {         files: {            "build/tmp/app.css": "assets/app.less"         }      }   },   autoprefixer: {      options: {         browsers: [‘last 2 version‘, ‘ie 8‘, ‘ie 9‘]      },      multiple_files: {         expand: true,         flatten: true,         src: ‘build/tmp/app.css‘,         dest: ‘build/‘      }   }});grunt.loadNpmTasks(‘grunt-contrib-less‘);grunt.loadNpmTasks(‘grunt-autoprefixer‘);grunt.registerTask(‘css‘, [‘less‘, ‘autoprefixer‘]);

 

與Gulpfile.js檔案進行對比,它們執行的任務相同:

var gulp = require(‘gulp‘),   less = require(‘gulp-less‘),   autoprefix = require(‘gulp-autoprefixer‘);gulp.task(‘css‘, function () {   gulp.src(‘assets/app.less‘)      .pipe(less())      .pipe(autoprefix(‘last 2 version‘, ‘ie 8‘, ‘ie 9‘))      .pipe(gulp.dest(‘build‘));});

 

因為Grunt比Gulp更加頻繁地操作檔案系統,所以使用資料流的Gulp總是比Grunt快。對於一個小的LESS檔案,gulpfile.js通常需要6ms,而gruntfile.js則需要大概50ms——慢8倍多。這隻是個簡單的例子,對於長的檔案,這個數字會增加得更顯著。

    

Gulp開發教程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.