en / ru

Grunt

На самом деле, я сам еще только начал разбираться с Grunt (апрель 2015). Так что где-то могу делать неоптимально, либо избыточно или с подводными камнями. Есть предложения - пишите.

Думаю, как и у многих, подобные средства изучаются только с появлением реальной необходимости в них. Без применения изучение теории пройдет впустую.
Но, начать - дело непростое. Инструкций вроде бы и много в сети, но как-то не всё хорошо. Буду рад, если мои объяснения кому-то помогут.

Первые шаги

Для начала, у Вас должен быть установлен Node.js для возможности выполнения npm инструкций.

Следующим шагом ставим глобальный Grunt, что позволит вызывать команду grunt в командной строке.

npm install -g grunt-cli

Заходим в папку с проектом. Вообще, это любое место, выше по уровню тех файлов, которые вы собираетесь обрабатывать с помощью Grunt.
Здесь будет размещаться папка node_modules с используемыми модулями (создается автоматически, когда Вы будете добавлять необходивые Grunt модули) и сам Gruntfile.js, где описывается вся логика.

Открываем командную строку (терминал, cmd). Убедитесь, что вы находитесь в нужной дериктории. Ставим локальный Grunt:

npm install grunt

Эта команда создала node_modules папку и поместила туда первый модуль - сам Grunt. В дальнейшем вы будете добавлять модули вызовом строки вида:

npm install grunt-*** --save-dev

Теперь можно создать и сам Gruntfile.js стандартной структуры:

module.exports = function(grunt) {
	grunt.initConfig({

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

Добавим первую задачу

В качестве примера используем один из наиболее популярных модулей - UglifyJS. Он используется для минификации JS файлов (ну и объединения, как побочный эффект).

Сами модули можно, например, искать с помощью поисковиков.

А вот и наш UglifyJS - https://github.com/gruntjs/grunt-contrib-uglify.

Эта страничка на GitHub - отличный пример правильного описания модуля.

Установка:

npm install grunt-contrib-uglify --save-dev

Подключение в Gruntfile.js:

grunt.loadNpmTasks('grunt-contrib-uglify');

Пример настроек для использования:

uglify: {
	my_target: {
		files: {
			'dest/output.min.js': ['src/input1.js', 'src/input2.js']
		}
	}
}

А теперь соберем всё, что должно получиться в Gruntfile.js:

module.exports = function(grunt) {
	grunt.initConfig({
      uglify: {
          my_target: {
              files: {
                  'dest/output.min.js': ['src/input1.js', 'src/input2.js']
              }
          }
      }
	});

    grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.registerTask('default', ['uglify']);
};

Что же здесь происходит

В initConfig передаются объекты с настройками задач. В нашем случае - описание одной задачи uglify.

grunt.loadNpmTasks говорит Grunt, как обрабатывать задачу uglify. Он подключает обработчик задачи из node_modules.

grunt.registerTask создает последовательность задач для выполнения. 'default' - имя последовательности. За ней идет массив непосредственно задач.

Кратко о том, что сейчас прописано для uglify

Имя my_target - совершенно произвольное. Это имя подзадачи (см. примеры запуска Grunt, чтобы понять, для чего оно). Подзадач может быть несколько, с разными именами.

У задач/подзадач есть 2 вида настроек: options и files. Первый задает настройки (причем в зависимости от того, находится он в задаче или подзадаче, options является глобальным для всех подзадач или локальным для каждой подзадачи), а второе - способ указать, какие файлы где взять и куда поместить после обработки.

В нашем примере Grunt возьмет файлы 'src/input1.js' и 'src/input2.js', склеит их, минифицирует и положит в 'dest/output.min.js'

Выполнение из командной строки

Список задач, прописанных в 'default' можно запустить просто вызвав:

grunt

Предположим, у Вы вынесли несколько задач отдельно, т.к. их не надо запускать каждый раз. Регистрация задач:

grunt.registerTask('css', ['autoprefixer','cssmin']);

Запускаем:

grunt css

Подобная инструкция может запускать не только списки задач, но и отдельно описанную задачу, т.е. даже без непосредственного использования grunt.registerTask. Так можно запустить uglify напрямую:

grunt uglify

А теперь вернемся к подзадачам. В описании grunt.initConfig не может быть, например, несколько uglify, да и имя это не произвольное, а диктуется разработчиком модуля. Но нам может понадобиться независимо обрабатывать этим же модулем другие файлы, с другими настройками для модуля. Здесь и нужны подзадачи. Напомню, в нашем примере подзадача с именем my_target. Непосредственно её можно вызвать так:

grunt uglify:my_target

Вызов без указания подзадачи запускает на выполнение все подзадачи.