Потоковая передача данных в стиле gulp для Grunt, или для другого таск-менеджера
Новый инструмент, gulp, привлекает к себе довольно много внимания со стороны сообщества фронтенд-разработчиков, в качестве свежей альтернативы уже популярным таск-менеджерам. То, что делает этот инструмент по-настоящему изящным — это технология потоковой передачи данных для организации процесса сборки. Поскольку все данные передаются напрямую в буфер, пропадает необходимость в создании временных файлов.
На данный момент уже существует активное сообщество разработчиков, которое создаёт плагины под gulp. Однако, пока еще не все плагины портированы. Например, когда мне нужно провести тестирование, из-за отсутствия некоторых из необходимых в данном случае плагинов, мне приходится оставаться верным Grunt. Я мог бы, конечно, использовать gulp и Grunt вместе, но, честно говоря, мне бы не хотелось в работе над одним проектом использовать целых две системы сборки. Есть еще один момент, который мне не нравится в gulp — это модель параллельного выполнения задач. Все задачи в этом менеджере выполняются одновременно по умолчанию, и это довольно неудобно, когда вам нужно, чтобы перечень задач выполнялся по порядку, как это происходит в Grunt.
К счастью, один из авторов gulp переписал программный код ядра файловой
системы и вынес его в отдельный модуль — vinyl-fs
.
Методы модуля .src()
и .dest()
- это, по сути, всё, что нам нужно для
модификации возможностей существующих плагинов gulp. На момент написания
статьи этот модуль пока не включён в пакетный менеджер Node, однако, его можно
легко установить самостоятельно, воспользовавшись соответствующим сокращенным
адресом с github:
$ npm install wearefractal/vinyl-fs
Модуля vinyl-fs
делает возможным использование плагинов gulp в задачах Grunt:
var fs = require('vinyl-fs'),
gzip = require('gulp-gzip')
grunt.registerTask('zip', function () {
fs.src('./build/build.js')
.pipe(gzip())
.pipe(fs.dest('./build'))
.on('end', this.async())
})
Вы, возможно, заметили, что плагины gulp выполняют только одно простое
действие, например, переименование, добавление шапки, добавление подвала,
и так далее. Я не против таких мелких дополнительных зависимостей, однако,
меня раздражает тот факт, что почти у всех плагинов в зависимостях прописан
модуль event-stream, у которого, по сути, используется только одна
функция .map()
, доступная также в другом отдельном модуле map-stream.
А кроме того, что делать в ситуации, когда мне нужно что-то сделать с файлом,
но под это действие еще не существует необходимого мне плагина?
На самом деле, довольно просто запустить вручную необходимые мне действия с
файлами, используя только модуль map-stream
:
var fs = require('vinyl-fs'),
map = require('map-stream'),
zlib = require('zlib')
grunt.registerTask('zip', function () {
fs.src('./build/build.js')
.pipe(map(gzip))
.pipe(fs.dest('./build'))
.on('end', this.async())
})
// Нужно всего лишь изменить содержимое файла,
// а затем запустить соответствующую функцию обратного вызова.
// Просто держите в памяти, что всё сводится к
// добавлению и удалению информации из буфера.
function gzip (file, cb) {
zlib.gzip(file.contents, function (err, buffer) {
file.contents = buffer
file.path = file.path + '.gz'
cb(err, file)
})
}
Потоковая передача данных через map-stream
позволяет вам делать с файлом
всё что угодно: изменять его содержимое, название, и так далее.
Самое приятное во всем этом то, что можно использовать прямые зависимости
(например, uglify-js
для задачи uglify
) в пользовательском
скрипте, запуская его при помощи Grunt, make, npm run
или любого другого
инструмента, которым вы привыкли пользоваться. Отличная альтернатива ожиданию,
пока кто-то напишет необходимый вам плагин под gulp.