Black Lives Matter

タスクの設定

このガイドでは、Gruntfileを使用してプロジェクトのタスクを設定する方法について説明します。Gruntfileが何かご存知ない場合は、「はじめに」ガイドを読み、「サンプル Gruntfile」を確認してください。

Gruntの設定

タスクの設定は、Gruntfile内でgrunt.initConfigメソッドを使って指定します。この設定は、ほとんどがタスク名付きのプロパティの下に配置されますが、任意のデータを含めることができます。プロパティがタスクに必要なプロパティと競合しない限り、それらは無視されます。

また、これはJavaScriptであるため、JSONに限定されません。ここでは任意の有効なJavaScriptを使用できます。必要に応じて、プログラムで設定を生成することもできます。

grunt.initConfig({
  concat: {
    // concat task configuration goes here.
  },
  uglify: {
    // uglify task configuration goes here.
  },
  // Arbitrary non-task-specific properties.
  my_property: 'whatever',
  my_src_files: ['foo/*.js', 'bar/*.js'],
});

タスク設定とターゲット

タスクが実行されると、Gruntは同じ名前のプロパティの下にあるその設定を探します。マルチタスクは、任意に名前を付けられた「ターゲット」を使用して定義された複数の設定を持つことができます。以下の例では、concatタスクにはfoobarのターゲットがあり、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.
    },
  },
});

grunt concat:foogrunt concat:barのようにタスクとターゲットの両方を指定すると、指定されたターゲットの設定のみが処理されます。grunt concatを実行すると、すべてのターゲットが順に処理されます。タスクがgrunt.task.renameTaskで名前変更された場合、Gruntは設定オブジェクトで新しいタスク名のプロパティを探します。

オプション

タスク設定内で、組み込みのデフォルトを上書きするためにoptionsプロパティを指定できます。さらに、各ターゲットには、そのターゲットに固有のoptionsプロパティを設定できます。ターゲットレベルのオプションは、タスクレベルのオプションを上書きします。

optionsオブジェクトはオプションであり、不要な場合は省略できます。

grunt.initConfig({
  concat: {
    options: {
      // Task-level options may go here, overriding task defaults.
    },
    foo: {
      options: {
        // "foo" target options may go here, overriding task-level options.
      },
    },
    bar: {
      // No options specified; this target will use task-level options.
    },
  },
});

ファイル

ほとんどのタスクはファイル操作を実行するため、Gruntにはタスクが操作するファイルを宣言するための強力な抽象化があります。src-dest(ソース-宛先)ファイルマッピングを定義する方法はいくつかあり、さまざまな程度の冗長性と制御を提供します。すべてのマルチタスクは、以下のすべての形式を理解するため、ニーズに最適な形式を選択してください。

すべてのファイル形式はsrcdestをサポートしていますが、コンパクト形式とファイル配列形式では、いくつかの追加プロパティがサポートされています。

  • filter 有効なfs.Statsメソッド名または、一致したsrcファイルパスを渡され、trueまたはfalseを返す関数。 例を参照
  • nonull trueに設定すると、操作は一致しないパターンを含めます。Gruntの--verboseフラグと組み合わせると、このオプションはファイルパスの問題をデバッグするのに役立ちます。
  • dot パターンにその場所に明示的にピリオドが含まれていなくても、ピリオドで始まるファイル名にパターンを一致させることができます。
  • matchBase 設定した場合、スラッシュのないパターンは、スラッシュが含まれている場合はパスのベース名と照合されます。たとえば、a?bはパス/xyz/123/acbには一致しますが、/xyz/acb/123には一致しません。
  • expand 動的なsrc-destファイルマッピングを処理します。詳細については、「ファイルオブジェクトを動的に構築する」を参照してください。
  • その他のプロパティは、マッチングオプションとして基になるライブラリに渡されます。詳細については、node-globminimatchのドキュメントを参照してください。

Gruntオプションとタスクオプションの違い

ほとんどのタスクはファイル操作を実行するため、Gruntはタスクが処理する必要があるファイルを取得するための組み込みインフラストラクチャを提供します。利点は、このロジックをタスク作成者が再度実装する必要がないことです。ユーザーがこれらのファイルを指定できるようにするために、Gruntはnonullfilterなどのオプションを提供します。

作業するファイルに加えて、各タスクには固有のニーズがあります。タスク作成者は、ユーザーがデフォルトの動作を上書きするためのオプションを設定できるようにすることができます。これらのタスク固有のオプションは、前述のGruntオプションと混同しないでください。

この違いをさらに明確にするために、grunt-contrib-jshintを使用する例を見てみましょう。

grunt.initConfig({
  jshint: {
    ignore_warning: {
      options: {
        '-W015': true,
      },
      src: 'js/**',
      filter: 'isFile'
    }
  }
});

この設定では、Gruntオプションのsrcfilterを使用して、処理するファイルを指定します。また、grunt-contrib-jshintのタスク固有のオプション-W015を使用して、特定の警告(コードW015を持つ警告)を無視します。

コンパクト形式

この形式では、ターゲットごとに1つのsrc-dest(ソース-宛先)ファイルマッピングが可能です。これは、単一のsrcプロパティが必要で、destキーが関係ないgrunt-contrib-jshintのような読み取り専用タスクで最も一般的に使用されます。この形式では、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',
    },
  },
});

ファイルオブジェクト形式

この形式は、ターゲットごとに複数の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'],
      },
    },
  },
});

ファイル配列形式

この形式は、ターゲットごとに複数の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'},
      ],
    },
  },
});

以前の形式

dest-as-targetファイル形式は、マルチタスクとターゲットが存在する前のなごりであり、宛先ファイルパスが実際にはターゲット名です。残念ながら、ターゲット名がファイルパスであるため、grunt task:targetの実行は面倒になる可能性があります。また、ターゲットレベルのオプションや、src-destファイルマッピングごとに追加のプロパティを指定することもできません。

この形式は非推奨と見なし、可能な限り避けてください。

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

カスタムフィルター関数

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);
      },
    },
  },
});

別の例では、グロビングおよびexpand: true機能を利用して、宛先に既に存在するファイルの上書きを回避できます。

grunt.initConfig({
  copy: {
    templates: {
      files: [{
        expand: true,
        cwd: ['templates/css/'],     // Parent folder of original CSS templates
        src: '**/*.css',             // Collects all `*.css` files within the parent folder (and its subfolders)
        dest: 'src/css/',            // Stores the collected `*.css` files in your `src/css/` folder
        filter: function (dest) {    // `dest`, in this instance, is the filepath of each matched `src`
          var cwd = this.cwd,        // Configures variables (these are documented for your convenience only)
              src = dest.replace(new RegExp('^' + cwd), '');
              dest = grunt.task.current.data.files[0].dest;
          return (!grunt.file.exists(dest + src));    // Copies `src` files ONLY if their destinations are unoccupied
        }
      }]
    }
  }
});

上記のテクニックでは、宛先が存在するかどうかを確認するときにrenameプロパティは考慮されないことに注意してください。

グロビングパターン

すべてのソースファイルパスを個別に指定するのは非現実的なことが多いため、Gruntは組み込みのnode-globおよびminimatchライブラリを介してファイル名展開(グロビングとも呼ばれます)をサポートしています。

これはグロビングパターンの包括的なチュートリアルではありませんが、ファイルパスでは次の点を知っておいてください。

  • *は任意の数の文字に一致しますが、/には一致しません。
  • ?は単一の文字に一致しますが、/には一致しません。
  • **はパスの一部にある限り、/を含め、任意の数の文字に一致します。
  • {}は、コンマ区切りの「or」式のリストを許可します。
  • パターンの先頭にある!は、一致を否定します。

ほとんどの人が知っておく必要があるのは、foo/*.jsfoo/サブディレクトリ内の.jsで終わるすべてのファイルに一致しますが、foo/**/*.jsfoo/サブディレクトリおよびすべてのサブディレクトリ内の.jsで終わるすべてのファイルに一致するということです。

また、複雑なグロビングパターンを簡略化するために、Gruntではファイルパスまたはグロビングパターンの配列を指定できます。パターンは順番に処理され、!で始まる一致は、一致したファイルを結果セットから除外します。結果セットは一意になります。

例:

// You can specify single files:
{src: 'foo/this.js', dest: ...}
// Or arrays of files:
{src: ['foo/this.js', 'foo/that.js', 'foo/the-other.js'], dest: ...}
// Or you can generalize with a glob pattern:
{src: 'foo/th*.js', dest: ...}

// This single node-glob pattern:
{src: 'foo/{a,b}*.js', dest: ...}
// Could also be written like this:
{src: ['foo/a*.js', 'foo/b*.js'], dest: ...}

// All .js files, in foo/, in alpha order:
{src: ['foo/*.js'], dest: ...}
// Here, bar.js is first, followed by the remaining files, in alpha order:
{src: ['foo/bar.js', 'foo/*.js'], dest: ...}

// All files except for bar.js, in alpha order:
{src: ['foo/*.js', '!foo/bar.js'], dest: ...}
// All files in alpha order, but with bar.js at the end.
{src: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], dest: ...}

// Templates may be used in filepaths or glob patterns:
{src: ['src/<%= basename %>.js'], dest: 'build/<%= basename %>.min.js'}
// But they may also reference file lists defined elsewhere in the config:
{src: ['foo/*.js', '<%= jshint.all.src %>'], dest: ...}

グロブパターン構文の詳細については、node-globおよびminimatchのドキュメントを参照してください。

ファイルオブジェクトを動的に構築する

多数の個々のファイルを処理する場合は、ファイルリストを動的に構築するために、いくつかの追加プロパティを使用できます。これらのプロパティは、コンパクトおよびファイル配列マッピング形式の両方で指定できます。

expand trueに設定すると、次のプロパティが有効になります。

  • cwd すべてのsrc一致はこのパスを基準にします(ただし、含みません)。
  • src cwdを基準とした一致するパターン。
  • dest 宛先パスのプレフィックス。
  • ext 生成されたdestパスで既存の拡張子をこの値に置き換えます。
  • extDot 拡張子を示すピリオドの位置を示すために使用します。'first'(拡張子はファイル名の最初のピリオドの後に開始)または'last'(拡張子は最後のピリオドの後に開始)のいずれかを使用できます。デフォルトでは'first'に設定されています。[0.4.3で追加]
  • flatten 生成されたdestパスからすべてのパス部分を削除します。
  • rename 新しい宛先とファイル名を含む文字列を返すカスタマイズされた関数を埋め込みます。この関数は、一致した各srcファイルに対して(拡張子の名前変更とフラット化の後)呼び出されます。詳細情報

次の例では、uglifyタスクは、static_mappingsdynamic_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: '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: [
        {
          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
        },
      ],
    },
  },
});

renameプロパティ

renameプロパティは、有効な値がJavaScript関数のみであるため、固有です。関数は文字列を返しますが、renameの値として文字列を単に使用することはできません(そうすると、エラーが発生します。オブジェクト#のプロパティ「rename」は関数ではありません)。次の例では、copyタスクはREADME.mdのバックアップを作成します。

grunt.initConfig({
  copy: {
    backup: {
      files: [{
        expand: true,
        src: ['docs/README.md'],    // The README.md file has been specified for backup
        rename: function () {       // The value for rename must be a function
          return 'docs/BACKUP.txt'; // The function must return a string with the complete destination
        }
      }]
    }
  }
});

関数が呼び出されると、destと一致したsrcパスが渡され、出力文字列を返すために使用できます。次の例では、ファイルがdevフォルダからdistフォルダにコピーされ、「beta」という単語を削除するように名前が変更されます。

grunt.initConfig({
  copy: {
    production: {
      files: [{
        expand: true,
        cwd: 'dev/',
        src: ['*'],
        dest: 'dist/',
        rename: function (dest, src) {          // The `dest` and `src` values can be passed into the function
          return dest + src.replace('beta',''); // The `src` is being renamed; the `dest` remains the same
        }
      }]
    }
  }
});

複数のsrcパスが同じ宛先に名前変更された場合(つまり、2つの異なるファイルが同じファイルに名前変更された場合)、各出力はソースの配列に追加されます。

テンプレート

<% %>デリミタを使って指定されたテンプレートは、タスクが設定ファイルから読み込む際に自動的に展開されます。テンプレートは、それ以上展開するものがない状態になるまで再帰的に展開されます。

設定オブジェクト全体が、プロパティが解決される際のコンテキストとなります。さらに、gruntとそのメソッドもテンプレート内で利用できます。例えば、<%= grunt.template.today('yyyy-mm-dd') %>のように使用できます。

  • <%= prop.subprop %> は、型に関係なく、設定ファイル内の prop.subprop の値に展開されます。このようなテンプレートは、文字列の値だけでなく、配列や他のオブジェクトを参照するためにも使用できます。
  • <% %> は、任意のインラインJavaScriptコードを実行します。これは、制御フローやループで役立ちます。

以下のconcatタスクの設定例では、grunt concat:sampleを実行すると、foo/*.js + bar/*.js + baz/*.jsにマッチするすべてのファイルと、バナー /* abcde */ を連結することで、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'
    },
  },
  // Arbitrary properties used in task configuration templates.
  foo: 'c',
  bar: 'b<%= foo %>d', // 'bcd'
  baz: 'a<%= bar %>e', // 'abcde'
  qux: ['foo/*.js', 'bar/*.js'],
});

外部データのインポート

次のGruntfileでは、プロジェクトのメタデータがpackage.jsonファイルからGrunt設定にインポートされ、grunt-contrib-uglifyプラグインuglifyタスクは、ソースファイルをminifyし、そのメタデータを使って動的にバナーコメントを生成するように設定されています。

Gruntには、JSONおよびYAMLデータをインポートするためのgrunt.file.readJSONおよびgrunt.file.readYAMLメソッドがあります。

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'
    }
  }
});