黑人生命也是命

範例 Gruntfile

在本頁中,我們將引導您建立一個涵蓋簡單專案常見需求的 Gruntfile。如果您已經知道如何設定 Gruntfile,並且正在尋找一個快速範例,這裡有一個

module.exports = function(grunt) {

  grunt.initConfig({
    jshint: {
      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
      options: {
        globals: {
          jQuery: true
        }
      }
    },
    watch: {
      files: ['<%= jshint.files %>'],
      tasks: ['jshint']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

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

};

需求

每個專案都有其需求,但大多數專案有一些共同點。在本指南中,我們將介紹一些 Grunt 外掛,以自動化基本需求。最終目標是教您如何設定這些 Grunt 外掛,以便您可以在專案中使用它們。

為了範例起見,假設您正在建立一個 JavaScript 函式庫。典型的資料夾結構具有以下資料夾:srcdisttestsrc 資料夾(有時稱為 app)包含您撰寫的函式庫原始碼。dist 資料夾(有時稱為 build)包含原始碼的縮小版本,即發行版。縮小的檔案是一個移除所有不必要的字元(例如空格、換行、註解)的檔案,而不會影響原始碼的功能。縮小的原始碼對於專案使用者特別有用,因為它減少了需要傳輸的資料量。最後,test 資料夾包含測試專案的程式碼。此設定將在建立 Gruntfile 設定的後續章節中使用。

在開發函式庫和釋出新版本時,有一些任務需要定期執行。例如,您可能希望確保您編寫的程式碼符合最佳實務,或者您編寫的程式碼不會導致意外行為。為此,您可以使用一個稱為 JSHint 的工具。Grunt 有個官方外掛稱為 grunt-contrib-jshint,我們將在這個範例中採用它。特別是,您可能希望確保在修改程式碼時,不會違反任何規則或最佳實務。因此,一個好的策略是在每次執行變更時檢查程式碼。為此,我們將介紹一個稱為 grunt-contrib-watch 的 Grunt 外掛。後者會在新增、變更或刪除檔案時執行預先定義的任務,例如 grunt-contrib-jshint

檢查原始碼是否遵循最佳實務還不足以保證原始碼穩定且不包含錯誤。要建立一個穩健的專案,您需要測試它。您可以採用多個函式庫,例如 QUnitJasmine。在本指南中,我們說明如何設定 QUnit,特別是 grunt-contrib-qunit,來測試您的程式碼。

在分發您的工作時,您希望提供一個大小盡可能小的版本。若要建立一個縮小的版本,您需要一個 Grunt 外掛程式,例如 grunt-contrib-uglify。此外,除非您正在開發的專案非常小,否則您可能會將程式碼拆分為多個檔案。雖然這對開發人員來說是一個好習慣,但您希望使用者只包含一個檔案。因此,在縮小程式碼之前,您應該串接原始檔以建立一個單一檔案。若要達成這個目標,您需要一個 Grunt 外掛程式,例如 grunt-contrib-concat

總而言之,在本指南中,我們將使用以下五個 Grunt 外掛程式

如果您好奇最終結果是什麼樣子,可以在本頁底部找到整個 Gruntfile

設定 Gruntfile

第一部分是「包裝器」函式,它封裝了您的 Grunt 設定。

module.exports = function(grunt) {
};

在該函式中,我們可以初始化我們的設定物件

grunt.initConfig({
});

接下來,我們可以將 package.json 檔案中的專案設定儲存在 pkg 屬性中。這讓我們可以參照 package.json 檔案中屬性的值,正如我們稍後將看到的。

pkg: grunt.file.readJSON('package.json')

到目前為止,我們有了這個

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json')
  });
};

現在,我們可以為我們提到的每個任務定義一個設定。外掛程式的設定物件存在於設定物件上的屬性中,該屬性通常與其外掛程式同名。grunt-contrib-concat 的設定位於 concat 鍵下的設定物件中,如下所示

concat: {
  options: {
    // define a string to put between each file in the concatenated output
    separator: ';'
  },
  dist: {
    // the files to concatenate
    src: ['src/**/*.js'],
    // the location of the resulting JS file
    dest: 'dist/<%= pkg.name %>.js'
  }
}

請注意,在上面的片段中,我們如何參照 JSON 檔案中的 name 屬性。我們使用 pkg.name 存取它,因為我們之前將 pkg 屬性定義為載入 package.json 檔案的結果,然後將其解析為 JavaScript 物件。Grunt 有個簡單的範本引擎來輸出設定物件中屬性的值。在這裡,我們告訴 concat 任務串接存在於 src/ 中且以 .js 結尾的所有檔案。

現在,讓我們設定 grunt-contrib-uglify 外掛程式,它會縮小 JavaScript 程式碼

uglify: {
  options: {
    // the banner is inserted at the top of the output
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
  },
  dist: {
    files: {
      'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
    }
  }
}

此片段告訴 grunt-contrib-uglifydist/ 中建立一個檔案,其中包含縮小 JavaScript 檔案的結果。在這裡,我們使用 <%= concat.dist.dest %>,因此 uglify 會縮小 concat 任務產生的檔案。

到目前為止,我們已經設定外掛程式來建立程式庫的發行版本。現在是時候使用 grunt-contrib-qunit 來自動化程式碼測試。為此,我們需要給出測試執行器檔案的位置,這些檔案是 QUnit 執行的 HTML 檔案。產生的程式碼如下所示

qunit: {
  files: ['test/**/*.html']
},

完成後,現在是時候設定設定以確保專案的程式碼符合最佳實務。JSHint 是一個工具,它可以偵測問題或潛在問題,例如高循環複雜度、使用等號運算子而不是嚴格等號運算子,以及定義未使用的變數和函式。

我們建議您使用 grunt-contrib-jshint 分析專案中的所有 JavaScript 檔案,包括 Gruntfile 和測試檔案。以下為 grunt-contrib-jshint 設定範例

jshint: {
  // define the files to lint
  files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
  // configure JSHint (documented at http://www.jshint.com/docs/)
  options: {
    // more options here if you want to override JSHint defaults
    globals: {
      jQuery: true,
      console: true,
      module: true
    }
  }
}

此外掛程式會接收一個檔案陣列,然後接收一個選項物件。這些選項都記錄在 JSHint 網站上。如果您對外掛程式的預設值感到滿意,就不需要在 Gruntfile 中重新定義它們。

最後一個要設定的外掛程式是 grunt-contrib-watch。我們將使用它來執行 jshintqunit 任務,只要有 JavaScript 檔案新增、刪除或修改時。當它偵測到任何指定的檔案已變更(在此,我們使用與告知 JSHint 檢查的檔案相同的檔案),它會執行您指定的任務,並依序執行。這可以在命令列中使用 grunt watch 執行。

將先前的說明轉換為 grunt-contrib-watch 設定會產生以下程式片段

watch: {
  files: ['<%= jshint.files %>'],
  tasks: ['jshint', 'qunit']
}

有了這個程式片段,我們已經設定好引言中提到的所有外掛程式的設定。最後一個步驟是載入我們需要的 Grunt 外掛程式。所有這些都應該已經透過 npm 事先安裝好。

grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');

最後設定一些任務。這些任務中最重要的是預設任務

// this would be run by typing "grunt test" on the command line
grunt.registerTask('test', ['jshint', 'qunit']);

// the default task can be run just by typing "grunt" on the command line
grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

當您呼叫 Grunt 而未指定要執行的任務(grunt)時,會執行預設任務。

產生的 Gruntfile

如果您正確地遵循本指南,您應該會有以下 Gruntfile

module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['src/**/*.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
      },
      dist: {
        files: {
          'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
        }
      }
    },
    qunit: {
      files: ['test/**/*.html']
    },
    jshint: {
      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
      options: {
        // options here to override JSHint defaults
        globals: {
          jQuery: true,
          console: true,
          module: true,
          document: true
        }
      }
    },
    watch: {
      files: ['<%= jshint.files %>'],
      tasks: ['jshint', 'qunit']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.registerTask('test', ['jshint', 'qunit']);

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

};