タスクの設定
このガイドでは、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
タスクには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.
},
},
});
grunt concat:foo
やgrunt 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(ソース-宛先)ファイルマッピングを定義する方法はいくつかあり、さまざまな程度の冗長性と制御を提供します。すべてのマルチタスクは、以下のすべての形式を理解するため、ニーズに最適な形式を選択してください。
すべてのファイル形式はsrc
とdest
をサポートしていますが、コンパクト形式とファイル配列形式では、いくつかの追加プロパティがサポートされています。
filter
有効なfs.Statsメソッド名または、一致したsrc
ファイルパスを渡され、true
またはfalse
を返す関数。 例を参照nonull
true
に設定すると、操作は一致しないパターンを含めます。Gruntの--verbose
フラグと組み合わせると、このオプションはファイルパスの問題をデバッグするのに役立ちます。dot
パターンにその場所に明示的にピリオドが含まれていなくても、ピリオドで始まるファイル名にパターンを一致させることができます。matchBase
設定した場合、スラッシュのないパターンは、スラッシュが含まれている場合はパスのベース名と照合されます。たとえば、a?b
はパス/xyz/123/acb
には一致しますが、/xyz/acb/123
には一致しません。expand
動的なsrc-destファイルマッピングを処理します。詳細については、「ファイルオブジェクトを動的に構築する」を参照してください。- その他のプロパティは、マッチングオプションとして基になるライブラリに渡されます。詳細については、node-globとminimatchのドキュメントを参照してください。
Gruntオプションとタスクオプションの違い
ほとんどのタスクはファイル操作を実行するため、Gruntはタスクが処理する必要があるファイルを取得するための組み込みインフラストラクチャを提供します。利点は、このロジックをタスク作成者が再度実装する必要がないことです。ユーザーがこれらのファイルを指定できるようにするために、Gruntはnonull
やfilter
などのオプションを提供します。
作業するファイルに加えて、各タスクには固有のニーズがあります。タスク作成者は、ユーザーがデフォルトの動作を上書きするためのオプションを設定できるようにすることができます。これらのタスク固有のオプションは、前述のGruntオプションと混同しないでください。
この違いをさらに明確にするために、grunt-contrib-jshintを使用する例を見てみましょう。
grunt.initConfig({
jshint: {
ignore_warning: {
options: {
'-W015': true,
},
src: 'js/**',
filter: 'isFile'
}
}
});
この設定では、Gruntオプションのsrc
とfilter
を使用して、処理するファイルを指定します。また、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/*.js
はfoo/
サブディレクトリ内の.js
で終わるすべてのファイルに一致しますが、foo/**/*.js
はfoo/
サブディレクトリおよびすべてのサブディレクトリ内の.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_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: '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'
}
}
});