サンプル 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ライブラリを作成しているとしましょう。一般的なフォルダ構成は、src
、dist
、およびtest
というフォルダで構成されています。src
フォルダ(app
と呼ばれることもあります)には、ライブラリのソースコードが作成者のように含まれています。dist
フォルダ(build
と呼ばれることもあります)には、配布物であるソースコードの最小化バージョンが含まれています。最小化されたファイルとは、ソースコードの機能を損なうことなく、スペース、改行、コメントなどの不要な文字がすべて削除されたものです。最小化されたソースコードは、転送する必要があるデータ量を削減するため、プロジェクトのユーザーにとって特に役立ちます。最後に、test
フォルダには、プロジェクトをテストするためのコードが含まれています。この設定は、Gruntfile
構成を作成する次のセクションで使用されます。
ライブラリを開発し、新しいバージョンをリリースする際には、定期的に実行する必要があるタスクがいくつかあります。たとえば、記述したコードがベストプラクティスに準拠していること、または記述したコードが予期しない動作を引き起こさないことを確認したい場合があります。そのためには、JSHintと呼ばれるツールを使用できます。Gruntには、grunt-contrib-jshintという公式プラグインがあり、この例ではそれを使用します。特に、コードを変更する際に、ルールやベストプラクティスを破らないようにする必要があります。したがって、変更を行うたびにコードをチェックするのが良い戦略です。そのため、grunt-contrib-watchというGruntプラグインを紹介します。後者は、ファイルの追加、変更、削除が行われるたびに、grunt-contrib-jshint
などの定義済みのタスクを実行します。
ソースコードがベストプラクティスに従っていることを確認するだけでは、安定しておりバグが含まれていないことを保証するには不十分です。堅牢なプロジェクトを作成するには、テストする必要があります。QUnitやJasmineなど、採用できるライブラリがいくつかあります。このガイドでは、QUnit、特にgrunt-contrib-qunitを構成してコードをテストする方法を説明します。
作品を配布する場合、できるだけ小さいサイズのバージョンを提供したいものです。最小化されたバージョンを作成するには、grunt-contrib-uglifyのようなGruntプラグインが必要です。さらに、開発しているプロジェクトが非常に小さいものでない限り、コードを複数のファイルに分割している可能性が高くなります。これは開発者にとっては良い習慣ですが、ユーザーには1つのファイルのみを含めることをお勧めします。したがって、コードを最小化する前に、ソースファイルを連結して1つのファイルを作成する必要があります。この目標を達成するには、grunt-contrib-concatのようなGruntプラグインが必要です。
要約すると、このガイドでは次の5つのGruntプラグインを使用します。
- grunt-contrib-uglify
- grunt-contrib-qunit
- grunt-contrib-concat
- grunt-contrib-jshint
- grunt-contrib-watch
最終結果がどのように見えるか気になる場合は、ページの下部に完全な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
プロパティをpackage.json
ファイルのロード結果として定義し、それがJavaScriptオブジェクトに解析されたため、pkg.name
を使用してアクセスします。Gruntには、構成オブジェクト内のプロパティの値を出力するための簡単なテンプレートエンジンがあります。ここでは、concat
タスクに、src/
内にあり、.js
で終わるすべてのファイルを連結するように指示します。
次に、JavaScriptコードを最小化するgrunt-contrib-uglify
プラグインを構成しましょう。
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-uglify
にJavaScriptファイルを最小化した結果を含むファイルをdist/
内に作成するように指示します。ここでは、<%= concat.dist.dest %>
を使用しているため、uglifyはconcatタスクが生成するファイルを最小化します。
ここまでで、ライブラリの配布バージョンを作成するためのプラグインを構成しました。次に、grunt-contrib-qunit
を使用して、コードのテストを自動化します。そのためには、テストランナーファイル(QUnitが実行するHTMLファイル)の場所を指定する必要があります。結果として得られるコードを以下に示します。
qunit: {
files: ['test/**/*.html']
},
完了したら、プロジェクトのコードがベストプラクティスに準拠していることを確認するための構成を設定します。JSHintは、高い循環的複雑さ、厳密な等価演算子の代わりに等価演算子の使用、未使用の変数と関数の定義など、問題または潜在的な問題を検出できるツールです。
Gruntfile
やテストファイルを含む、プロジェクトのすべてのJavaScriptファイルをgrunt-contrib-jshint
で分析することをお勧めします。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
です。JavaScriptファイルが追加、削除、または変更されるとすぐに、jshint
タスクとqunit
タスクを実行するために使用します。指定されたファイルのいずれかが変更されたことを検出すると(ここでは、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']);
};