Grunt入門學習之(2) -- Gruntfile的編寫

Gruntfile由如下幾部分構成:html

  • "wrapper" 函數
  • 項目與任務,目標配置
  • 加載grunt插件和任務
  • 自定義任務

一、wrapper函數(包裝函數)

  每個 Gruntfile (和grunt插件)都遵循一樣的格式,編寫的Grunt代碼都必須放在此包裝函數內:至關因而gruntfile的入口;node

  module.exports = function(grunt) {
    // Do grunt-related things in here
  };

二、項目和任務,目標配置

   大部分的Grunt任務(task)都依賴某些配置數據,這些數據被封裝在一個object配置對象內,並做爲參數傳入grunt.initConfig 方法。git

  grunt.initConfig({  Configuration data  })

  object配置對象首先 須要將存儲在package.json文件中的grunt 版本信息和各個插件的數據信息引入到grunt config中,即在配置對象中 加入下列語句:github

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

  將package.json中的數據信息引入後,就能夠編寫任務配置了。下面以一個任務配置說明。npm

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),   //數據信息引入
    uglify: {     //插件任務屬性配置
      build: {  //創建任務目標
        src: 'src/<%= pkg.name %>.js',
        dest: 'build/<%= pkg.name %>.min.js'
      }
    }
  });

   上述代碼新建了一個以「uglify」爲屬性名的grunt-contrib-uglify任務, 在任務中創建一個名爲"build"的uglify任務目標,用於將一個pkg.name.js文件壓縮爲一個目標文件pkg.name.min.js。因爲<% %>模板字符串能夠引用任意的配置屬性,所以能夠經過這種方式來指定諸如文件路徑和文件列表類型的配置數據,從而減小一些重複的工做。能夠在這個配置對象中(傳遞給initConfig()方法的對象)存儲任意的數據,只要它不與任務配置所需的屬性相沖突就行,不然會被忽略。此外,因爲這自己就是JavaScript,不只限於使用JSON;還能夠在這裏使用任意的有效的JS代碼。若是有必要,甚至能夠以編程的方式生成配置。編程

  下面是grunt任務配置的具體說明:json

  2.1 - Grunt任務配置具體說明api

  Grunt的task配置都寫在grunt.initConfig方法的配置對象中。任務配置主要是以 "任務名稱" 命名的「屬性」,這些屬性名稱是"固定"的,好比grunt-contrib-uglify對應的任務名稱是」 uglify」,固然也能夠包含其餘任意數據。可是這些表明任意數據的屬性與任務所須要的屬性相沖突時,這些任意數據的屬性就會被覆蓋。如如下的」 concat」和」 uglify」都是」任務名稱」 屬性數組

    grunt.initConfig({
      concat: { // 這裏是concat任務的配置信息。
         },
      uglify: {// 這裏是uglify任務的配置信息
          },
      my_property: 'whatever', // 任意數據。
      my_src_files: ['foo/*.js', 'bar/*.js'],
    });

  2.1.1 - options屬性app

  在一個任務配置中,options屬性能夠用來指定覆蓋內置屬性的默認值。此外,每個目標(target)中還能夠擁有一個專門針對此目標(target)的options屬性。目標(target)級的options將會覆蓋任務級的options。 options對象是可選的,若是不須要,能夠忽略。

    grunt.initConfig({
    concat: {
      options: {  // 這裏是任務級的Options,覆蓋默認值
      },
      foo: {    // 這裏是目標級的Options,覆蓋任務級的Options
        options: {    
            //"foo" target options may go here, overriding task-level options.
        },
      },
      bar: {  //No options specified; this target will use task-level options.
      },
   },  });

  2.1.2 - 任務的多目標配置

  當運行一個任務時,Grunt會自動去查找配置對象中的同名任務名稱屬性。多任務(multi-task)能夠經過任意命名的「目標(target)」來定義多個目標配置。以下所示concat任務有名爲foo和bar兩個目標,而uglify任務只有一個名爲bar目標。

  grunt.initConfig({
    concat: {
      foo: {// concat task "foo" target options and files go here.
      },
      bar: {// concat task "bar" target options and files go here.
      },
    },
    uglify: {
      bar: { // uglify task "bar" target options and files go here.
      },
    },
  });

  同時指定任務(task)和目標(target),如grunt concat:foo或者grunt concat:bar,將只會處理指定目標(target)的配置,而運行grunt concat將遍歷全部目標(target)並依次處理。注意,若是一個任務使用grunt.task.renameTask重命名過,Grunt將在配置對象中查找以新的任務名命名的屬性。

 

  2.2 - 文件

  因爲大多的任務都是對文件進行操做,Grunt有一個強大的抽象層用於聲明任務應該操做哪些文件(即指明可操做文件)。下面有好幾種定義src-dest(源文件-目標文件)文件映射的方式,均提供了不一樣程度的描述和控制操做方式。任何一種多任務(multi-task)模式都能理解這些格式,因此只須要選擇知足需求的格式就行。全部的文件格式都支持src和dest屬性,此外"Compact"[簡潔]和"Files Array"[文件數組]格式還支持如下一些額外的屬性:

  • filter 它經過接受任意一個有效的fs.Stats方法名或者一個函數來匹配src文件路徑並根據匹配結果返回true或者false。
  • nonull 若是被設置爲 true,未匹配的模式也將執行。結合Grunt的--verbore標誌, 這個選項能夠幫助用來調試文件路徑的問題。
  • dot 它容許模式模式匹配句點開頭的文件名,即便模式並不明確文件名開頭部分是否有句點。
  • matchBase若是設置這個屬性,缺乏斜線的模式(意味着模式中不能使用斜線進行文件路徑的匹配)將不會匹配包含在斜線中的文件名。 例如,a?b將匹配/xyz/123/acb但不匹配/xyz/acb/123。
  • expand 處理動態的src-dest文件映射,更多的信息請查看動態構建文件對象
  • 其餘的屬性將做爲匹配項傳遞給底層的庫。 請查看node-glob 和minimatch 文檔以獲取更多信息。

    2.2.1 - 簡潔格式

    這種形式容許每一個目標對應一個src-dest文件映射。一般狀況下它用於只讀任務,好比grunt-contrib-jshint,它就只須要一個單一的src屬性,而不須要關聯的dest選項. 這種格式還支給每一個src-dest文件映射指定額外的屬性。   

      grunt.initConfig({
        jshint: {
          foo: {
            src: ['src/aa.js', 'src/aaa.js']
          },
        },
        concat: {
          bar: {
            src: ['src/bb.js', 'src/bbb.js'],
            dest: 'dest/b.js',
          },
        },
      });

    2.2.2 - 文件對象格式

    這種形式支持每一個目標對應多個src-dest形式的文件映射,屬性名就是目標文件,源文件就是它的值(源文件列表則使用數組格式聲明)。可使用這種方式指定數個src-dest文件映射, 可是不可以給每一個映射指定附加的屬性。 

    grunt.initConfig({
      concat: {
        foo: {
          files: {
          'dest/a.js': ['src/aa.js', 'src/aaa.js'],
          'dest/a1.js': ['src/aa1.js', 'src/aaa1.js'],
          },
        },
        bar: {
          files: {
            'dest/b.js': ['src/bb.js', 'src/bbb.js'],
            'dest/b1.js': ['src/bb1.js', 'src/bbb1.js'],
          },
        },
      },
    });

    2.2.3 - 文件數組格式

    這種形式支持每一個目標對應多個src-dest文件映射,同時也容許每一個映射擁有額外屬性:

    grunt.initConfig({
      concat: {
        foo: {
          files: [
            {src: ['src/aa.js', 'src/aaa.js'], dest: 'dest/a.js'},
            {src: ['src/aa1.js', 'src/aaa1.js'], dest: 'dest/a1.js'},
          ],
        },
        bar: {
          files: [
            {src: ['src/bb.js', 'src/bbb.js'], dest: 'dest/b/', nonull: true},
            {src: ['src/bb1.js', 'src/bbb1.js'], dest: 'dest/b1/', filter: 'isFile'},
          ],
        },
     },
  });

    2.2.4 - 較老的格式

    dest-as-target文件格式在多任務和目標出現以前是一個過渡形式,目標文件路徑實際上就是目標名稱。遺憾的是, 因爲目標名稱是文件路徑,那麼運行grunt task:target可能不合適。此外,你也不能指定一個目標級的options或者給每一個src-dest文件映射指定額外屬性。此種格式已經不同意使用,請儘可能不要使用。

        grunt.initConfig({
          concat: {
            'dest/a.js': ['src/aa.js', 'src/aaa.js'],
            'dest/b.js': ['src/bb.js', 'src/bbb.js'],
          },
        });            

    2.2.5 - 自定義過濾函數

    filter屬性能夠給你的目標文件提供一個更高級的詳細幫助信息。只須要使用一個有效的fs.Stats 方法名。下面的配置僅僅清理一個與模式匹配的真實的文件:

    grunt.initConfig({
      clean: {
        foo: {
          src: ['tmp/**/*'],
          filter: 'isFile',
        },
      },
    });
    或者建立你本身的filter函數,根據文件是否匹配來返回true或者false。下面的例子將僅僅清理一個空目錄:     grunt.initConfig({     clean: {     foo: {     src: [
'tmp/**/*'],     filter: function(filepath) {    return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);   },   },   },   });

    2.2.6 - 通配符模式

    一般分別指定全部源文件路徑是不切實際的,所以Grunt經過內置支持node-glob 和 minimatch 庫來匹配文件名(又叫做globbing)。通常只須要知道如何在文件路徑匹配過程當中使用它們便可:

  •   * 匹配任意數量的字符,但不匹配 /
  •   ? 匹配單個字符,但不匹配 /
  •   ** 匹配任意數量的字符,包括 /,只要它是路徑中惟一的一部分
  •   {} 容許使用一個逗號分割的「或」表達式列表
  •   ! 在模式的開頭用於排除一個匹配模式所匹配的任何文件

    foo/*.js將匹配位於foo/目錄下的全部的.js結尾的文件;而foo/**/*js將匹配foo/目錄以及其子目錄中全部以.js結尾的文件。此外, 爲了簡化本來複雜的通配符模式,Grunt容許指定一個數組形式的文件路徑或者一個通配符模式。全部模式按順序處理,模式處理的過程當中,帶有!前綴的模式所匹配的文件將不包含在結果集中。 並且其結果集中的每一項也是惟一的。

如:

  // 指定單個文件:
  {src: 'foo/this.js', dest: ...}
  // 指定一個文件數組:
  {src: ['foo/this.js', 'foo/that.js', 'foo/the-other.js'], dest: ...}
  // 使用一個匹配模式:
  {src: 'foo/th*.js', dest: ...}
  // 一個獨立的node-glob模式:
  {src: 'foo/{a,b}*.js', dest: ...}
  // 也能夠這樣編寫:
  {src: ['foo/a*.js', 'foo/b*.js'], dest: ...}
  // foo目錄中全部的.js文件,按字母順序排序:
  {src: ['foo/*.js'], dest: ...}
  // 首先是bar.js,接着是剩下的.js文件,並按字母順序排序:
  {src: ['foo/bar.js', 'foo/*.js'], dest: ...}
  // 除bar.js以外的全部的.js文件,按字母順序排序:
  {src: ['foo/*.js', '!foo/bar.js'], dest: ...}
  // 按字母順序排序的全部.js文件,可是bar.js在最後。
  {src: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], dest: ...}
  // 模板也能夠用於文件路徑或者匹配模式中:
  {src: ['src/<%= basename %>.js'], dest: 'build/<%= basename %>.min.js'}
  // 它們也能夠引用在配置中定義的其餘文件列表:
  {src: ['foo/*.js', '<%= jshint.all.src %>'], dest: ...}

    更多關於通配符模式的語法,請查看node-glob 和 minimatch 的文檔。

    2.2.7 - 動態構建文件對象 (經常使用)

    當但願處理大量的單個文件時,這裏有一些附加的屬性能夠用來動態的構建一個文件列表。這些屬性均可以用於Compact和Files Array文件映射格式。

    expand 設置爲true用於啓用下面的選項:

  •   cwd 全部src指定的匹配都將相對於此處指定的路徑(即該路徑是基礎路徑,但不包括此路徑) 。
  •   src 相對於cwd路徑的匹配模式
  •   dest 目標文件路徑前綴。
  •   ext 對於生成的dest路徑中全部實際存在文件,均使用這個屬性值替換擴展名
  •   extDot 用於指定標記擴展名的英文點號的所在位置。能夠賦值 'first' (擴展名從文件名中的第一個英文點號開始) 或 'last' (擴展名從最後一個英文點號開始),默認值爲 'first' [添加於 0.4.3 版本]
  •   flatten 從生成的dest路徑中移除全部的路徑部分。
  •   rename 對每一個匹配的src文件調用這個函數(在重命名後綴和移除路徑以後)。dest和匹配的src路徑將被做爲參數傳入,此函數應該返回一個新的dest值。 若是相同的dest返回不止一次,那麼,每一個返回此值的src來源都將被添加到一個數組中做爲源列表。

    在下面的例子中,uglify 任務中的static_mappings和dynamic_mappings兩個目標具備相同的src-dest文件映射列表, 由於任務運行時Grunt會自動展開dynamic_mappings文件對象爲4個單獨的靜態src-dest文件映射--假設這4個文件可以找到。

    能夠指定任意靜態src-dest和動態的src-dest文件映射相互結合。

grunt.initConfig({
  uglify: {
    static_mappings: {
      // Because these src-dest file mappings are manually specified, every
      // time a new file is added or removed, the Gruntfile has to be updated.
      files: [
        {src: 'lib/a.js', dest: 'build/a.min.js'},  //靜態src-dest,即文件路徑和生成的文件路徑是一對一的匹配
        {src: 'lib/b.js', dest: 'build/b.min.js'},
        {src: 'lib/subdir/c.js', dest: 'build/subdir/c.min.js'},
        {src: 'lib/subdir/d.js', dest: 'build/subdir/d.min.js'},
      ],
    },
    dynamic_mappings: {
      // Grunt will search for "**/*.js" under "lib/" when the "uglify" task
      // runs and build the appropriate src-dest file mappings then, so you
      // don't need to update the Gruntfile when files are added or removed.
      files: [
        {  //動態的src-dest,文件路徑和生成的文件路徑是動態連接生成
          expand: true,     // Enable dynamic expansion.
          cwd: 'lib/',      // Src matches are relative to this path.
          src: ['**/*.js'], // Actual pattern(s) to match.
          dest: 'build/',   // Destination path prefix.
          ext: '.min.js',   // Dest filepaths will have this extension.
          extDot: 'first'   // Extensions in filenames begin after the first dot
        },
      ],
    },
  },
});  //兩種文件映射方式效果相同,可是 動態的src-dest 效果更好,不用一個個進行匹配。

    2.2.8 - 模板

    使用<% %>分隔符指定的模板會在任務從它們的配置中讀取相應的數據時將自動擴展掃描。模板會被遞歸的展開,直到配置中再也不存在遺留的模板相關的信息(與模板匹配的)。整個配置對象決定了屬性上下文(模板中的屬性)。此外,在模板中使用grunt以及它的方法都是有效的,如: <%= grunt.template.today('yyyy-mm-dd') %>。

    • <%= prop.subprop %> 將會自動展開配置信息中的prop.subprop的值,不論是什麼類型。像這樣的模板不只能夠用來引用字符串值,還能夠引用數組或者其餘對象類型的值。
    • <% %> 執行任意內聯的JavaScript代碼。對於控制流或者循環來講是很是有用的。

    下面以concat任務配置爲例,運行grunt concat:sample時將經過banner中的/* abcde */連同foo/*.js+bar/*.js+bar/*.js匹配的全部文件來生成一個名爲build/abcde.js的文件。

grunt.initConfig({
  concat: {
    sample: {
      options: {
        banner: '/* <%= baz %> */\n',   // '/* abcde */\n'
      },
      src: ['<%= qux %>', 'baz/*.js'],  // [['foo/*.js', 'bar/*.js'], 'baz/*.js']
      dest: 'build/<%= baz %>.js',      // 'build/abcde.js'
    },
  },
  //用於任務配置模板的任意屬性
  foo: 'c',
  bar: 'b<%= foo %>d', // 'bcd'
  baz: 'a<%= bar %>e', // 'abcde'
  qux: ['foo/*.js', 'bar/*.js'],
});

    2.2.9 - 導入外部數據

    在下面的Gruntfile中,項目的元數據是從package.json文件中導入到Grunt配置中的,而且grunt-contrib-uglify 插件中的 uglify 任務被配置用於壓縮一個源文件以及使用該元數據動態的生成一個banner註釋。Grunt有grunt.file.readJSON和grunt.file.readYAML兩個方法分別用於引入JSON和YAML數據。

grunt.initConfig({
  pkg: grunt.file.readJSON('package.json'),
  uglify: {
    options: {
      banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
    },
    dist: {
      src: 'src/<%= pkg.name %>.js',
      dest: 'dist/<%= pkg.name %>.min.js'
    }
  }
});

 

三、加載Grunt插件和任務

  像 concatenation、[minification]、grunt-contrib-uglify 和 linting這些經常使用的任務(task)都已經以grunt插件的形式被開發出來了。經過npm install安裝之後,在 package.json 文件內會自動在dependency(依賴)添加這些插件的版本和鏈接信息,而後就能夠在Gruntfile中經過grunt.loadNpmTasks()函數加載這些插件:

  grunt.loadNpmTasks('grunt-contrib-uglify');  //加載可以提供"uglify"任務的插件。加載其餘插件和此方法相同

   注意: grunt --help 命令將列出全部可用的任務。

四、自定義任務

  經過定義 default 任務,可讓Grunt默認執行一個或多個任務。如如下代碼,執行 grunt 命令時若是不指定具體任務的話,將會執行uglify任務。這和執行grunt uglify 或者 grunt default的效果同樣。default任務列表數組中能夠指定任意數目的任務(能夠帶參數;如['uglify:my_target'],則指明在執行uglify任務時執行my_target目標,其餘目標不予執行)。

  grunt.registerTask('default', ['uglify']);  // Default task(s).

  若是Grunt插件中的任務(task)不能知足項目需求,則能夠在Gruntfile中自定義任務(task)。例如,如下的 Gruntfile 中自定義了一個default 任務,能夠不須要任務配置:

  module.exports = function(grunt) {
    // A very basic default task.
    grunt.registerTask('default', 'Log some stuff.', function() {
      grunt.log.write('Logging some stuff...').ok();
    });
  };

  特定於項目的任務沒必要在 Gruntfile 中定義。他們能夠定義在外部.js 文件中,並經過grunt.loadTasks方法加載。

相關文章
相關標籤/搜索