小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Gulp挑戰(zhàn)Grunt,背后的哲學

 看見就非常 2015-04-23

[按:網(wǎng)上介紹Gulp和Grunt安裝使用的文章很多,甚少比較二者的思路,連官方文檔都語焉不詳。我在此做一個粗陋的對比,希望能提綱挈領,加深讀者對這兩個工具的理解。]

做過點兒正經開發(fā)的同學都知道,構建工具必不可少。C時代的Make、Java的Ant、Ruby的Rake……沒有這些工具,一遍遍地點選輸入,準煩死你。

在前端和Node JS的開發(fā)中,最普及的構建工具就是Grunt。它的功能說來簡單,就是管理一系列的Task。大部分的Task都是第三方的插件,安裝好對應的NPM包,再loadNpmTasks就可以用了。

Grunt的配置文件Gruntfile,主要包含兩部分:

  • 配置每個Task,包括文件從哪里,到哪里去,還有一些處理的選項

  • 自己寫一些簡單的Task,把第三方插件提供的Task組合起來

別看這兩個事兒,輕輕松松幾百行出來了。每個Task的配置,各有各的規(guī)矩,還牽扯到插件間的配合。反正我從seed庫開始做新項目的時候,基本不敢改原來的Gruntfile,很多用不上的功能也擱那兒。留意了一下很多開源項目的Gruntfile,也都臃腫雜亂,好不到哪兒去。

Gruntfile維護起來那么困難,有幾個原因:

  • 配置和運行分離
    程序員都知道,變量的聲明和使用挨在一起,最方便理解和修改。但Gruntfile里,配置Task和調用它們的地方離得很遠,極大地增加了心智負擔。

  • 每個插件做的事太多
    每個Task的結果必須寫到磁盤文件,另一個Task再讀,損害性能倒是小事,更麻煩的是讓整個過程變復雜了。
    就像一個個小作坊,來料加工又返回給客戶,這中間的溝通成本、出錯機會都大大增加。

  • 配置項過多
    做事多了,配置項自然也多。至少輸入和輸出的位置得配吧。每個插件的配置規(guī)則還不盡相同。用每個插件,都得去學習一番。

Gulp應運而生。

恐怕沒幾個IT人不知道Unix管道的概念。前一級的輸出,直接變成后一級的輸入。把簡單的工具組合起來,優(yōu)雅地解決復雜的問題。聽起來那么熟悉呢?是的,Gulp就把這種思維用在構建過程中。

Gulp基于Node JS的一個機制,叫做stream,有點類似C++中的stream。在Node中,文件訪問、輸入輸出、HTTP連接,都是stream。Gulp的每個插件從stream中讀取輸入,做一些處理,再輸出到stream中。

每個插件不是拿來獨立使用的。相反,它專注于完成單一職責。只有把合適的插件組合起來,才能完成具體的Task。引用官方的例子,看看一個典型的Task長什么樣(略有刪減):

var paths = {
  scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee']
};

gulp.task('scripts', ['clean'], function() { // 可以依賴于其它task
  return gulp.src(paths.scripts) // 指定輸入
      .pipe(coffee()) // 環(huán)節(jié)一
      .pipe(uglify()) // 環(huán)節(jié)二
      .pipe(concat('all.min.js')) // 環(huán)節(jié)三
      .pipe(gulp.dest('build/js')); // 指定輸出
});

配置呢?不需要了。是不是行云流水,一氣呵成?

那我們再回頭來看看前面Grunt的幾個問題,Gulp是怎么解決的:

  • 配置和運行分離
    code over configuration,直接就在調用的地方配置。

  • 每個插件做的事太多
    單一職責,依靠組合來發(fā)揮作用。就像一條自動化生產線,上一道工序的產出直接交給下一步,效率不要太高。

  • 配置項過多
    既然大家都遵循同一個協(xié)議,很多配置就不需要了。

放大了看,Gulp像是一個非常貼近領域模型的DSL,而Grunt更像萬能的XML。哪個好用,無需多說。在我們制作DSL時,也有參考意義。

最后,舉一個Grunt很別扭,Gulp卻能優(yōu)雅解決的例子。

做前端開發(fā)會用到一個功能叫usemin。我們HTML中會引用到很多css和js文件。發(fā)布時,這些文件要合并、壓縮、混淆,最后生成一兩個文件。為了讓修改過的代碼繞過瀏覽器的緩存機制,要根據(jù)文件內容hash出文件名。html文件里就要引用這些新的文件名。

比較一下grunt-usemingulp-usemin各自README的長度,就能看出區(qū)別。

grunt.registerTask('build', [
  'useminPrepare', // 準備
  'concat',
  'cssmin',
  'uglify',
  'filerev',
  'usemin' // 執(zhí)行
]);

grunt-usemin分成兩步:

  • 先從html文件中收集需要處理的js和css,傳給后續(xù)的一堆任務
    它本身并不知道在實際中會調用哪些其它Task,只能用一些hack,支持固定的幾個Task。而上面的每個Task,都有自己的配置項。要把這些配置項都列出來,實在太長了。

  • 真正執(zhí)行,更新html文件里的js和css引用。

gulp-usemin就干凈得多,沒有絲毫多余的東西:

gulp.task('usemin', function() {
  gulp.src('./*.html')
    .pipe(usemin({
      css: [minifyCss(), 'concat'],
      html: [minifyHtml({empty: true})],
      js: [uglify(), rev()]
    }))
    .pipe(gulp.dest('build/'));
});

usemin不需要有minifyCss、minifyHtmluglifyrev這幾個插件的任何知識,只要把對應的內容從stream丟出去就好。在用這些插件組裝task時才需要關心。

當前,Gulp的社區(qū)還遠不如Grunt成熟,有些功能的插件,Gulp可能就沒有。這其實不算很大的劣勢,只要足夠好用,追上來很快。而且,寫一個Gulp插件要比相應的Grunt插件短小得多!

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多