Как использовать машины: быть продуктивным с помощью Task Runners
Опубликовано: 2022-03-10Таскраннеры — это герои (или злодеи, в зависимости от вашей точки зрения), которые тихо трудятся за большинством веб-приложений и мобильных приложений. Исполнители задач обеспечивают ценность за счет автоматизации многочисленных задач разработки, таких как объединение файлов, запуск серверов разработки и компиляция кода. В этой статье мы рассмотрим скрипты Grunt, Gulp, Webpack и npm. Мы также предоставим несколько примеров каждого из них, чтобы вы могли начать. Ближе к концу я дам несколько простых советов по интеграции идей из этого поста в ваше приложение.
Существует мнение, что средства выполнения задач и достижения JavaScript в целом чрезмерно усложняют внешний интерфейс. Я согласен с тем, что тратить весь день на настройку сценариев сборки — не всегда лучшее использование вашего времени, но таск-раннеры имеют некоторые преимущества при правильном и умеренном использовании. Наша цель в этой статье — быстро охватить основы самых популярных средств выполнения задач и предоставить убедительные примеры, чтобы дать толчок вашему воображению относительно того, как эти инструменты могут вписаться в ваш рабочий процесс.
Дальнейшее чтение на SmashingMag:
- Станьте опытным пользователем командной строки с помощью Oh-My-ZSH и Z
- Введение в PostCSS
- Вставай и беги с ворчанием
- Строительство с глотком
Примечание о командной строке
Средства запуска задач и инструменты сборки в основном являются инструментами командной строки. В этой статье я буду исходить из того, что имею достаточный опыт и компетентность в работе с командной строкой. Если вы понимаете, как использовать общие команды, такие как cd
, ls
, cp
и mv
, тогда вы должны быть в порядке, когда мы рассмотрим различные примеры. Если вам неудобно использовать эти команды, в Smashing Magazine есть отличный вводный пост. Давайте начнем с их всех дедушки: Grunt.
ворчание
Grunt был первым популярным средством запуска задач на основе JavaScript. Я использую Grunt в той или иной форме с 2012 года. Основная идея Grunt заключается в том, что вы используете специальный файл JavaScript, Gruntfile.js
, для настройки различных плагинов для выполнения задач. Он имеет обширную экосистему плагинов и является очень зрелым и стабильным инструментом. У Grunt есть фантастический веб-каталог, который индексирует большинство плагинов (около 5500 в настоящее время). Простой гений Grunt заключается в сочетании JavaScript и идеи общего файла конфигурации (например, make-файла), что позволило многим разработчикам вносить свой вклад в Grunt и использовать его в своих проектах. Это также означает, что Grunt можно поместить в ту же систему контроля версий, что и остальную часть проекта.
Grunt проверен в боях и стабилен. Примерно во время написания была выпущена версия 1.0.0, что является огромным достижением для команды Grunt. Поскольку Grunt в значительной степени настраивает различные плагины для совместной работы, он может довольно быстро запутаться (т.е. запутаться и сбить с толку при изменении). Однако, приложив немного осторожности и организации (разбивая задачи на логические файлы!), вы можете заставить его творить чудеса для любого проекта.
В редком случае, когда плагин недоступен для выполнения нужной вам задачи, Grunt предоставляет документацию о том, как написать свой собственный плагин. Все, что вам нужно знать для создания собственного плагина, — это JavaScript и Grunt API. Вам почти никогда не придется создавать собственный плагин, поэтому давайте посмотрим, как использовать Grunt с довольно популярным и полезным плагином!
Пример

Давайте посмотрим, как на самом деле работает Grunt. Запуск grunt
в командной строке запустит программу командной строки Grunt, которая ищет Gruntfile.js
в корне каталога. Gruntfile.js
содержит конфигурацию, которая управляет тем, что будет делать Grunt. В этом смысле Gruntfile.js
можно рассматривать как своего рода поваренную книгу, которой следует повар (то есть Grunt, программа); и, как любая хорошая кулинарная книга, Gruntfile.js
будет содержать множество рецептов (т.е. задач).
Мы собираемся испытать Grunt, используя плагин Grunticon для создания иконок для гипотетического веб-приложения. Grunticon берет каталог SVG и выдает несколько ресурсов:
- файл CSS с SVG, закодированными в base-64, в качестве фоновых изображений;
- файл CSS с версиями SVG в формате PNG, закодированными в base-64, в качестве фоновых изображений;
- файл CSS, который ссылается на отдельный файл PNG для каждого значка.
Три разных файла представляют различные возможности браузеров и мобильных устройств. Современные устройства будут получать SVG высокого разрешения в виде одного запроса (т. е. одного файла CSS). Браузеры, которые не обрабатывают SVG, но обрабатывают активы в кодировке base-64, получат таблицу стилей PNG base-64. Наконец, любые браузеры, которые не могут обрабатывать эти два сценария, получат «традиционную» таблицу стилей, которая ссылается на PNG. Все это из одного каталога SVG!
Конфигурация этой задачи выглядит так:
module.exports = function(grunt) { grunt.config("grunticon", { icons: { files: [ { expand: true, cwd: 'grunticon/source', src: ["*.svg", ".png"], dest: 'dist/grunticon' } ], options: [ { colors: { "blue": "blue" } } ] } }); grunt.loadNpmTasks('grunt-grunticon'); };
Давайте пройдемся по различным шагам здесь:
- У вас должен быть установлен Grunt глобально.
- Создайте файл
Gruntfile.js
в корне проекта. Также лучше всего установить Grunt как зависимость от npm в файлеpackage.json
вместе с Grunticon черезnpm i grunt grunt-grunticon --save-dev
. - Создайте каталог SVG и каталог назначения (куда будут помещены созданные ресурсы).
- Поместите небольшой скрипт в
head
вашего HTML, который будет определять, какие значки загружать.
Вот как должен выглядеть ваш каталог перед запуском задачи Grunticon:
|-- Gruntfile.js |-- grunticon | `-- source | `-- logo.svg `-- package.json
|-- Gruntfile.js |-- grunticon | `-- source | `-- logo.svg `-- package.json
После того, как все это будет установлено и создано, вы можете скопировать приведенный выше фрагмент кода в Gruntfile.js
. После этого вы сможете запустить grunt grunticon
из командной строки и увидеть, как выполняется ваша задача.
Фрагмент выше делает несколько вещей:
- добавляет новый объект
config
в Grunt в строке 32 с именемgrunticon
; - заполняет различные опции и параметры для Grunticon в объекте
icons
; - наконец, загружает плагин Grunticon через
loadNPMTasks
.
Вот как должен выглядеть ваш каталог после Grunticon:
|-- Gruntfile.js |-- dist | `-- grunticon | |-- grunticon.loader.js | |-- icons.data.png.css | |-- icons.data.svg.css | |-- icons.fallback.css | |-- png | | `-- logo.png | `-- preview.html |-- grunticon | `-- source | `-- logo.svg `-- package.json
|-- Gruntfile.js |-- dist | `-- grunticon | |-- grunticon.loader.js | |-- icons.data.png.css | |-- icons.data.svg.css | |-- icons.fallback.css | |-- png | | `-- logo.png | `-- preview.html |-- grunticon | `-- source | `-- logo.svg `-- package.json
Вот и все — готово! Всего за несколько строк конфигурации и пару установок пакетов мы автоматизировали генерацию наших иконок! Надеюсь, это начинает иллюстрировать мощь средств выполнения задач: надежность, эффективность и мобильность.
Gulp: блоки LEGO для вашей системы сборки
Gulp появился через некоторое время после Grunt и стремился стать инструментом сборки, состоящим не только из конфигурации, но и из кода. Идея кода над конфигурацией заключается в том, что код гораздо более выразителен и гибок, чем модификация бесконечных файлов конфигурации. Проблема с Gulp в том, что он требует больше технических знаний, чем Grunt. Вам нужно быть знакомым с потоковым API Node.js и уметь писать базовый JavaScript.
Использование Gulp потоков Node.js является основной причиной того, что он быстрее, чем Grunt. Использование потоков означает, что вместо использования файловой системы в качестве «базы данных» для преобразования файлов Gulp использует преобразования в памяти. Дополнительные сведения о потоках см. в документации по API потоков Node.js, а также в руководстве по потокам.
Пример

Как и в разделе Grunt, мы познакомим вас с Gulp на простом примере: объединение наших модулей JavaScript в один файл приложения.
Запуск Gulp аналогичен запуску Grunt. Программа командной строки gulp
будет искать кулинарную книгу рецептов (например Gulpfile.js
) в каталоге, в котором она запущена.
Ограничение количества запросов, которые делает каждая страница, считается лучшей практикой веб-производительности (особенно на мобильных устройствах). Тем не менее, сотрудничать с другими разработчиками намного проще, если функциональность разбита на несколько файлов. Введите бегунов задач. Мы можем использовать Gulp для объединения нескольких файлов JavaScript для нашего приложения, чтобы мобильным клиентам приходилось загружать один файл, а не несколько.
У Gulp такая же обширная экосистема плагинов, как и у Grunt. Итак, чтобы упростить эту задачу, мы будем использовать плагин gulp-concat. Допустим, структура нашего проекта выглядит так:
|-- dist | `-- app.js |-- gulpfile.js |-- package.json `-- src |-- bar.js `-- foo.js
Два файла JavaScript находятся в нашем каталоге src
, и мы хотим объединить их в один файл app.js
в нашем каталоге dist/
. Для этого мы можем использовать следующую задачу Gulp.
var gulp = require('gulp'); var concat = require('gulp-concat'); gulp.task('default', function() { return gulp.src('./src/*.js') .pipe(concat('app.js')) .pipe(gulp.dest('./dist/')); });
Важные биты находятся в gulp.task
. Там мы используем gulp.src
API, чтобы получить все файлы, которые заканчиваются на .js
в нашем каталоге src
. API gulp.src
возвращает поток этих файлов, которые мы затем можем передать (через API pipe
) плагину gulp-concat. Затем плагин объединяет все файлы в потоке и передает их функции gulp.dest
. Функция gulp-dest
просто записывает полученные данные на диск.
Вы можете видеть, как Gulp использует потоки, чтобы дать нам «строительные блоки» или «цепочки» для наших задач. Типичный рабочий процесс Gulp выглядит так:
- Получить все файлы определенного типа.
- Передайте эти файлы плагину (concat!), или сделайте какое-нибудь преобразование.
- Передайте эти преобразованные файлы в другой блок (в нашем случае в блок
dest
, который завершает нашу цепочку).
Как и в примере с Grunt, простой запуск gulp
из корня каталога нашего проекта вызовет задачу по default
, определенную в файле Gulpfile.js
. Эта задача объединяет наши файлы, и мы продолжим разработку нашего приложения или веб-сайта.
Вебпак
Новейшим дополнением к клубу исполнителей задач JavaScript является Webpack. Webpack позиционирует себя как «сборщик модулей», что означает, что он может динамически создавать пакеты кода JavaScript из нескольких отдельных файлов, используя шаблоны модулей, такие как шаблон CommonJS. В Webpack также есть плагины, которые он называет загрузчиками.

Webpack все еще довольно молод и имеет довольно плотную и запутанную документацию. Поэтому я бы порекомендовал репозиторий Webpack Пита Ханта в качестве отличной отправной точки перед погружением в официальную документацию. Я также не рекомендовал бы Webpack, если вы новичок в средствах выполнения задач или не чувствуете себя хорошо в JavaScript. Помимо этих проблем, это все еще более конкретный инструмент, чем общая широта Grunt и Gulp. Многие люди используют Webpack вместе с Grunt или Gulp именно по этой причине, позволяя Webpack преуспеть в объединении модулей и позволяя Grunt или Gulp выполнять более общие задачи.
В конечном итоге Webpack позволяет нам писать код в стиле Node.js для браузера, что значительно повышает производительность и обеспечивает четкое разделение задач в нашем коде с помощью модулей. Давайте воспользуемся Webpack, чтобы добиться того же результата, что и в примере с Gulp, объединив несколько файлов JavaScript в один файл приложения.
Пример

Webpack часто используется с Babel для переноса кода ES6 в ES5. Транспиляция кода из ES6 в ES5 позволяет разработчикам использовать развивающийся стандарт ES6, предоставляя ES5 для браузеров или сред, которые еще не полностью поддерживают ES6. Однако в этом примере мы сосредоточимся на создании простого пакета из двух наших файлов из примера Gulp. Для начала нам нужно установить Webpack и создать файл конфигурации webpack.config.js
. Вот как выглядит наш файл:
module.exports = { entry: "./src/foo.js", output: { filename: "app.js", path: "./dist" } };
В этом примере мы указываем Webpack на наш файл src/foo.js
, чтобы начать работу по обходу нашего графа зависимостей. Мы также обновили наш файл foo.js
, чтобы он выглядел следующим образом:
//foo.js var bar = require("./bar"); var foo = function() { console.log('foo'); bar(); }; module.exports = foo;
И мы обновили наш файл bar.js
, чтобы он выглядел так:
//bar.js var bar = function() { console.log('bar'); }; module.exports = bar;
Это очень простой пример CommonJS. Вы заметите, что эти файлы теперь «экспортируют» функцию. По сути, CommonJS и Webpack позволяют нам начать организовывать наш код в автономные модули, которые можно импортировать и экспортировать в нашем приложении. Webpack достаточно умен, чтобы следить за ключевыми словами импорта и экспорта и объединять все в один файл dist/app.js
. Нам больше не нужно поддерживать задачу конкатенации, вместо этого нам просто нужно придерживаться структуры нашего кода. Намного лучше!
Расширение
Webpack похож на Gulp тем, что «это просто JavaScript». Его можно расширить для выполнения других задач запуска через систему загрузчика. Например, вы можете использовать css-loader и sass-loader для компиляции Sass в CSS и даже для использования Sass в вашем JavaScript, перегружая требуемый шаблон require
! Однако я обычно выступаю за использование Webpack исключительно для создания модулей JavaScript и за использование другого более общего подхода для выполнения задач (например, сценариев Webpack и npm или Webpack и Gulp для обработки всего остального).
npm-скрипты
Скрипты npm — последнее увлечение хипстеров, и на то есть веские причины. Как мы видели со всеми этими инструментами, количество зависимостей, которые они могут ввести в проект, может в конечном итоге выйти из-под контроля. Первый пост, который я увидел в поддержку сценариев npm в качестве отправной точки для процесса сборки, был написан Джеймсом Холлидеем. Его пост прекрасно резюмирует игнорируемую силу скриптов npm (выделено мной):
Есть несколько причудливых инструментов для автоматизации сборки проектов JavaScript, в которых я никогда не чувствовал привлекательности, потому что менее известная команда npm run
вполне подходила для всего, что мне нужно было сделать, сохраняя при этом очень маленькую площадь конфигурации .
Вы уловили этот последний фрагмент в конце? Основная привлекательность скриптов npm заключается в том, что они имеют «очень маленький размер конфигурации». Это одна из основных причин, по которой скрипты npm начали завоевывать популярность (к сожалению, почти четыре года спустя). С Grunt, Gulp и даже Webpack в конечном итоге вы начинаете тонуть в плагинах, которые обертывают двоичные файлы и удваивают количество зависимостей в проекте.
У Кейта Циркеля есть руководство по использованию npm для замены Grunt или Gulp. Он дает план того, как в полной мере использовать возможности сценариев npm, и представил важный плагин Parallel Shell (и множество других подобных ему).
Пример
В нашем разделе о Grunt мы взяли популярный модуль Grunticon и создали иконки SVG (с запасными вариантами PNG) в задаче Grunt. Раньше это было для меня единственной проблемой со скриптами npm. Какое-то время я устанавливал Grunt для проектов только для того, чтобы использовать Grunticon. Я буквально «раскошеливался» на Grunt в моей npm-задаче, чтобы добиться начала выполнения задачи (или, как мы начали называть это на работе, turducken инструмента сборки). К счастью, The Filament Group, фантастическая группа разработчиков Grunticon, выпустила автономную (то есть без Grunt) версию своего инструмента Grunticon-Lib. Итак, давайте воспользуемся им для создания иконок с помощью npm-скриптов!
Этот пример немного сложнее, чем типичная задача скрипта npm. Типичная задача сценария npm — это вызов инструмента командной строки с соответствующими флагами или файлом конфигурации. Вот более типичная задача, которая компилирует наш Sass в CSS:
"sass": "node-sass src/scss/ -o dist/css",
Видите, это всего лишь одна строка с различными опциями? Не нужен файл задачи, не нужно запускать инструмент сборки — просто npm run sass
из командной строки, и теперь Sass — это CSS. Одна действительно приятная особенность скриптов npm заключается в том, что вы можете объединять задачи скриптов в цепочку. Например, предположим, что мы хотим запустить какую-то задачу до того, как запустится наша задача Sass. Мы бы создали новую запись сценария следующим образом:
"presass": "echo 'before sass',
Правильно: pre-
понимает префикс. Он также понимает post-
префикс. Любая запись сценария с тем же именем, что и другая запись сценария с pre-
или post-
-префиксом, будет выполняться до или после этой записи.
Для преобразования наших иконок потребуется реальный файл Node.js. Впрочем, это не слишком серьезно. Просто создайте каталог tasks
и создайте новый файл с именем grunticon.js
или icons.js
или с любым другим именем, которое имеет смысл для тех, кто работает над проектом. После создания файла мы можем написать код JavaScript, чтобы запустить наш процесс Grunticon.
Примечание. Во всех этих примерах используется ES6, поэтому мы будем использовать babel-node для выполнения нашей задачи. Вы можете легко использовать ES5 и Node.js, если вам так удобнее.
import icons from "grunticon-lib"; import globby from "globby"; let files = globby.sync('src/icons/*'); let options = { colors: { "blue": "blue" } }; let icon = new icons(files, 'dist/icons', options); icon.process();
Давайте заглянем в код и разберемся, что происходит.
- Мы
import
(т.е. требуем) две библиотеки,grunticon-lib
иglobby
. Globby — один из моих любимых инструментов, он упрощает работу с файлами и глобусами. Globby расширяет Node.js Glob (выбирает все файлы JavaScript через./*.js
) с поддержкой Promise. В данном случае мы используем его для получения всех файлов в каталогеsrc/icons
. - Как только мы это сделаем, мы установим несколько параметров в объекте
options
а затем вызовем Grunticon-Lib с тремя аргументами:- файлы значков,
- назначение,
- варианты. Библиотека берет на себя эти значки и в конечном итоге создает версии SVG и PNG в нужном нам каталоге.
- Мы почти закончили. Помните, что это в отдельном файле, и нам нужно добавить «хук» для вызова этого файла из нашего npm-скрипта, например:
"icons": "babel-node tasks/icons.js"
. - Теперь мы можем запустить
npm run icons
, и наши иконки будут создаваться каждый раз.
Скрипты npm предлагают такой же уровень мощности и гибкости, как и другие средства выполнения задач, без долга над плагинами.
Разбивка бегунов задач, описанных здесь
Инструмент | Плюсы | Минусы |
---|---|---|
ворчание | Не нужны реальные знания программирования | Самый многословный из описанных здесь исполнителей задач |
Глоток | Настройте задачи с реальным JavaScript и потоками | Требуется знание JavaScript |
Добавляет код в проект (потенциально больше ошибок) | ||
Вебпак | Лучший в своем классе по сборке модулей | Более сложный для более общих задач (например, Sass для CSS) |
npm-скрипты | Прямое взаимодействие с инструментами командной строки. | Некоторые задачи невозможно выполнить без средства запуска задач. |
Несколько легких побед
Все эти примеры и средства выполнения задач могут показаться слишком сложными, поэтому давайте разберем их. Во-первых, я надеюсь, что вы не уберете из этой статьи мысль о том, что любой таск-раннер или система сборки, которые вы сейчас используете, должны быть немедленно заменены упомянутыми здесь. Замена важных систем, подобных этой, не должна производиться без особого внимания. Вот мой совет по обновлению существующей системы: делайте это постепенно.
Скрипты обертки!
Один из дополнительных подходов заключается в написании нескольких «оберток» npm-скриптов вокруг ваших существующих средств запуска задач, чтобы обеспечить общий словарь для шагов сборки, который находится за пределами фактического используемого средства запуска задач. Сценарий оболочки может быть таким простым:
{ "scripts": { "start": "gulp" } }
Во многих проектах используются start
и test
блоки сценариев npm, чтобы помочь новым разработчикам быстро освоиться. Сценарий-оболочка вводит еще один уровень абстракции в цепочку сборки вашего средства запуска задач, но я думаю, что стоит иметь возможность стандартизировать примитивы npm (например test
). Команды npm более долговечны, чем отдельные инструменты.
Посыпьте небольшим веб-пакетом
Если вы или ваша команда чувствуете боль от поддержания хрупкого «порядка пакетов» для вашего JavaScript или вы хотите перейти на ES6, рассмотрите эту возможность представить Webpack в вашей существующей системе запуска задач. Webpack хорош тем, что вы можете использовать его столько, сколько хотите, и при этом получать от него пользу. Начните с того, что свяжите код вашего приложения, а затем добавьте к нему babel-loader. Webpack обладает такой глубиной функций, что в течение некоторого времени он сможет вместить практически любые дополнения или новые функции.
Простое использование PostCSS со скриптами npm
PostCSS — это отличная коллекция плагинов, которые преобразуют и улучшают CSS после его написания и предварительной обработки. Другими словами, это постпроцессор. Достаточно просто использовать PostCSS с помощью скриптов npm. Скажем, у нас есть скрипт Sass, как в нашем предыдущем примере:
"sass": "node-sass src/scss/ -o dist/css",
Мы можем использовать ключевые слова lifecycle
скрипта npm, чтобы добавить скрипт для автоматического запуска после задачи Sass:
"postsass": "postcss --use autoprefixer -c postcss.config.json dist/css/*.css -d dist/css",
Этот скрипт будет запускаться каждый раз, когда запускается скрипт Sass. Пакет postcss-cli великолепен, потому что вы можете указать конфигурацию в отдельном файле. Обратите внимание, что в этом примере мы добавляем еще одну запись сценария для выполнения новой задачи; это распространенный шаблон при использовании скриптов npm. Вы можете создать рабочий процесс, который выполняет все различные задачи, необходимые вашему приложению.
Заключение
Таскраннеры могут решать настоящие проблемы. Я использовал средства запуска задач для компиляции различных сборок приложения JavaScript в зависимости от того, была ли целью рабочая среда или локальная разработка. Я также использовал средства запуска задач для компиляции шаблонов Handlebars, для развертывания веб-сайта в рабочей среде и для автоматического добавления префиксов поставщиков, которые отсутствуют в моем Sass. Это не тривиальные задачи, но как только их заворачивают в средство запуска задач, они становятся легкими.
Таскраннеры постоянно развиваются и меняются. Я попытался охватить наиболее часто используемые в текущем духе времени. Однако есть и другие, о которых я даже не упомянул, например, Брокколи, Бранч и Арфа. Помните, что это всего лишь инструменты: используйте их только в том случае, если они решают конкретную проблему, а не потому, что их используют все остальные. Удачной работы!