Я знаю, о чем ты думаешь. WAT?! Разве Глоток не убил Гранта? Почему мы не можем просто остановиться на несколько минут здесь, в стране JavaScript? Я слышу тебя, но ...

Я обнаружил, что Gulp и Grunt - ненужные абстракции. Скрипты npm очень мощные, и зачастую с ними проще жить.

Начнем с примера…

Я был большим поклонником Gulp. Но в моем последнем проекте у меня было 100 строк в моем gulpfile и около дюжины плагинов Gulp. Я изо всех сил пытался интегрировать Webpack, Browsersync, горячую перезагрузку, Mocha и многое другое с помощью Gulp. Почему? Что ж, у некоторых плагинов было недостаточно документации для моего варианта использования. Некоторые плагины предоставляют только часть необходимого мне API. У одного была странная ошибка, при которой просматривалось только небольшое количество файлов. Еще лишены цвета при выводе в командную строку.

Это решаемые проблемы, но ни одна из этих проблем не возникла, когда я вызвал инструменты напрямую.

В последнее время я заметил, что многие проекты с открытым исходным кодом просто используют сценарии npm. Я решил отступить и пересмотреть. Мне действительно нужен был Gulp? Оказывается, нет.

Я решил попробовать использовать только сценарии npm в моем новом проекте с открытым исходным кодом. Я создал богатую среду разработки и процесс сборки приложений React, используя только сценарии npm. Любопытно, как это выглядит? Обратите внимание на React Slingshot. Я расскажу, как создать этот процесс сборки с помощью сценариев npm, в Создание среды разработки JavaScript на Pluralsight.

Удивительно, но теперь я предпочитаю работать со сценариями npm, а не с Gulp. Вот почему.

Что не так с Gulp и Grunt?

Со временем я заметил три основных проблемы с такими средствами запуска задач, как Gulp и Grunt:

  1. Зависимость от авторов плагинов
  2. Разочаровывающая отладка
  3. Несвязная документация

Давайте рассмотрим каждый из этих вопросов.

Проблема №1: Зависимость от авторов плагина

Когда вы работаете с новыми или непопулярными технологиями, плагин может вообще отсутствовать. А когда плагин существует, он может быть устаревшим. Например, недавно был выпущен Babel 6. API значительно изменился, поэтому многие плагины Gulp были несовместимы с последней версией. При использовании Gulp я застревал, потому что необходимый мне плагин Gulp еще не был обновлен.

При использовании Gulp или Grunt вы должны дождаться, пока разработчики плагина предоставят обновления, или исправить это самостоятельно. Это задерживает вашу способность использовать новые версии современных инструментов. Напротив, когда я использую сценарии npm, я использую инструменты напрямую, без дополнительного уровня абстракции. Это означает, что когда будут выпущены новые версии Mocha, Istanbul, Babel, Webpack, Browserify и т. Д., Я сразу смогу использовать новые версии.

Что касается выбора, ничто не сравнится с npm:

Когда вы используете скрипты npm, вы не ищите подключаемые модули Grunt или Gulp. Вы выбираете из более чем 227 000 пакетов npm.

Честно говоря, если нужный вам плагин Grunt или Gulp недоступен, вы, безусловно, можете использовать пакеты npm напрямую. Но тогда вы больше не используете Gulp или Grunt для этой конкретной задачи.

Проблема №2: разочаровывающая отладка

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

  1. Базовый инструмент сломан?
  2. Плагин Grunt / Gulp сломан?
  3. Моя конфигурация нарушена?
  4. Я использую несовместимые версии?

Использование сценариев npm устраняет # 2. И я считаю, что №3 встречается гораздо реже, поскольку я обычно вызываю интерфейс командной строки напрямую. Наконец, №4 встречается реже, так как я сократил количество пакетов в своем проекте, используя npm напрямую, а не используя абстракцию исполнителя задач.

Проблема № 3: разрозненная документация

Документация по основным инструментам, которые мне нужны, почти всегда лучше, чем связанные с ними плагины Grunt и Gulp. Например, если я использую gulp-eslint, я делю свое время между документами gulp-eslint и сайтом ESLint. Мне нужно переключать контекст между плагином и инструментом, который он абстрагирует. Основная проблема трения в Gulp and Grunt заключается в следующем:

Понимания этого инструмента недостаточно. Gulp и Grunt требуют от вас понимания абстракции плагина.

Большинство инструментов, связанных со сборкой, предлагают понятные, мощные и хорошо документированные интерфейсы командной строки. См. Документацию по интерфейсу командной строки ESLint в качестве хорошего примера. Я считаю, что чтение и реализация короткого вызова командной строки в сценариях npm более понятны, меньше трений и легче отлаживать (поскольку здесь удален слой абстракции).

Теперь, когда я определил болевые точки, возникает вопрос: зачем нам нужны средства выполнения задач, такие как Gulp и Grunt?

Почему мы проигнорировали npm для сборок?

Я считаю, что есть четыре основных заблуждения, которые привели к тому, что Gulp и Grunt стали настолько популярными:

  1. Люди думают, что сценарии npm требуют сильных навыков командной строки
  2. Люди думают, что скрипты npm недостаточно мощные
  3. Люди думают, что потоки Gulp необходимы для быстрой сборки
  4. Люди думают, что скрипты npm не работают на разных платформах

Давайте рассмотрим эти заблуждения по порядку.

Заблуждение №1 : скрипты npm требуют сильных навыков работы с командной строкой

Вам не нужно много знать о командной строке своей операционной системы, чтобы пользоваться мощью сценариев npm. Конечно, grep, sed, awk и pipe - это навыки, которые нужно изучать на протяжении всей жизни, но вам не обязательно быть мастером командной строки Unix или Windows, чтобы использовать сценарии npm. Вместо этого вы можете использовать тысячи пакетов в npm, чтобы выполнить свою работу.

Например, вы могли не знать, что в Unix это принудительно удаляет каталог: rm -rf. Это нормально. Вы можете использовать rimraf, который делает то же самое (и при загрузке он работает кроссплатформенно). Большинство пакетов npm предлагают интерфейсы, которые предполагают очень мало знаний о командной строке вашей ОС. Просто ищите в npm пакеты, которые делают то, что вам нужно, читайте документацию, учитесь на ходу. Раньше я искал плагины Gulp. Вместо этого я ищу пакеты npm. Отличный ресурс: libraries.io.

Заблуждение №2: скриптов npm недостаточно

Скрипты npm сами по себе удивительно мощны. Существуют условные пре и пост хуки:

Все, что вы делаете, это следуете соглашению. Приведенные выше скрипты будут запускаться по порядку в зависимости от их префикса. Сценарий предварительной сборки будет запускаться перед сценарием сборки, потому что у него такое же имя, но с префиксом «pre». Сценарий postbuild будет запускаться после сценария сборки, потому что он имеет префикс «post». Поэтому, если я создам сценарии с именами prebuild, build и postbuild, они будут запускаться автоматически в том порядке, когда я набираю `npm run build`.

Вы также можете разложить большие проблемы, вызвав один скрипт из другого:

В этом примере задача предварительной сборки вызывает задачу очистки. Это позволяет вам разложить ваши скрипты на небольшие однострочники с понятными названиями и единственной ответственностью.

Вы можете вызывать несколько скриптов последовательно в одной строке с помощью &&. Сценарии на шаге очистки выше будут запускаться один за другим. Эта простота действительно вызовет у вас улыбку, если вы столкнетесь с трудностями при составлении списка задач для выполнения в Gulp по порядку.

А если команда становится слишком сложной, всегда можно вызвать отдельный файл:

Я вызываю отдельный скрипт в задаче сборки выше. Этот сценарий будет запускаться Node и, таким образом, может использовать любые пакеты npm, которые мне нужны, и использовать всю мощь JavaScript внутри.

Я мог бы продолжить, но основные функции описаны здесь. Также есть небольшой курс Pluralsight по использованию npm в качестве инструмента сборки. Или посмотрите React Slingshot, чтобы увидеть все это в действии.

Заблуждение № 3: потоки Gulp необходимы для быстрых сборок

Gulp быстро завоевал популярность по сравнению с Grunt, потому что потоки в памяти Gulp быстрее, чем файловый подход Grunt. Но вам не нужен Gulp, чтобы насладиться мощью потоковой передачи. Фактически, потоковая передача всегда была встроена в командные строки как Unix, так и Windows. Оператор вертикальной черты (|) передает вывод одной команды на ввод другой команды. А оператор перенаправления (›) перенаправляет вывод в файл.

Так, например, в Unix я могу использовать grep для содержимого файла и перенаправить вывод в новый файл:

grep ‘Cory House’ bigFile.txt > linesThatHaveMyName.txt

Работа, описанная выше, транслируется. Никакие промежуточные файлы не пишутся. (Хотите знать, как выполнить приведенную выше команду в кросс-платформенном режиме? Читайте дальше…)

Вы также можете использовать оператор `&` для одновременного запуска двух команд в Unix:

npm run script1.js & npm run script2.js

Два приведенных выше сценария будут выполняться одновременно. Для одновременного запуска скриптов на разных платформах используйте npm-run-all. Это приводит к следующему заблуждению ...

Заблуждение №4: скрипты npm не работают на разных платформах

Многие проекты привязаны к определенной операционной системе, поэтому кроссплатформенность не имеет значения. Но если вам нужно запустить кросс-платформенный, скрипты npm все равно могут отлично работать. Бесчисленные проекты с открытым исходным кодом тому подтверждение. Вот как.

Командная строка вашей операционной системы запускает ваши сценарии npm. Итак, в Linux и OSX ваши сценарии npm запускаются из командной строки Unix. В Windows сценарии npm запускаются из командной строки Windows. Таким образом, если вы хотите, чтобы ваши сценарии сборки запускались на всех платформах, вам нужно сделать счастливыми и Unix, и Windows. Вот три подхода:

Подход 1. Используйте кроссплатформенные команды. Существует удивительное количество кроссплатформенных команд. Вот несколько:

&& chain tasks (Run one task after another)
< input file contents to a command
> redirect command output to a file
| redirect command output to another command

Подход 2. Используйте пакеты узлов. Вы можете использовать пакеты узлов вместо команд оболочки. Например, используйте rimraf вместо rm -rf. Используйте cross-env для кросс-платформенной установки переменных окружения. Найдите в Google, npm или libraries.io то, что вы хотите сделать, и почти наверняка найдется пакет узлов, который сделает это кроссплатформенным. И если ваши вызовы командной строки становятся слишком длинными, вы можете вызывать пакеты Node в отдельных сценариях, например так:

node scriptName.js

Приведенный выше сценарий представляет собой простой старый JavaScript, выполняемый Node. А поскольку вы просто вызываете сценарий из командной строки, вы не ограничены файлами .js. Вы можете запустить любой сценарий, который может выполнять ваша ОС, например Bash, Python, Ruby или Powershell.

Подход 3: используйте ShellJS. ShellJS - это пакет npm, который запускает команды Unix через Node. Таким образом, это дает вам возможность запускать команды Unix на всех платформах, включая Windows.

Я использовал комбинацию подходов №1 и №2 на React Slingshot.

Болевая точка

По общему признанию, есть некоторые недостатки: спецификация JSON не поддерживает комментарии, поэтому вы не можете добавлять комментарии в package.json. Есть несколько способов обойти это ограничение:

  1. Написание небольших одноцелевых сценариев с хорошо названными именами
  2. Документируйте скрипты отдельно (например, в README.md)
  3. Вызов отдельного файла .js

Я предпочитаю вариант №1. Если вы разбиваете каждый сценарий на единственную ответственность, комментарии редко нужны. Имя скрипта должно полностью описывать цель, как и любая небольшая функция с хорошо названным именем. Как я обсуждал в Чистый код: написание кода для людей, небольшие функции с единственной ответственностью редко требуют комментариев. Когда я чувствую, что комментарий необходим, я использую вариант №3 и перемещаю сценарий в отдельный файл. Это дает мне всю композиционную мощь JavaScript, когда мне это нужно.

Package.json также не поддерживает переменные. Звучит как большая проблема, но не по двум причинам. Во-первых, наиболее распространенная потребность в переменных связана с окружением, которое вы можете установить в командной строке. Во-вторых, если вам нужны переменные по другим причинам, вы можете вызвать отдельный файл .js. Посмотрите React-starter-kit, чтобы увидеть элегантный пример этого паттерна.

Наконец, существует риск создания длинных сложных аргументов командной строки, которые трудно понять. Анализ кода и тщательный рефакторинг - отличный способ убедиться, что сценарии npm разбиты на небольшие, хорошо названные, одноцелевые функции, понятные каждому. Если он достаточно сложен, чтобы потребовать комментария, вам, вероятно, следует реорганизовать один сценарий в несколько сценариев с хорошо названными именами или извлечь его в отдельный файл.

Абстракции должны быть обоснованы

Gulp и Grunt - это абстракции по сравнению с инструментами, которые я использую. Абстракции полезны, но за абстракции приходится платить. Они протекают. Они делают нас зависимыми от разработчиков плагинов и их документации. И они добавляют сложности, увеличивая количество зависимостей. Я решил, что такие средства выполнения задач, как Gulp и Grunt, - это абстракции, которые мне больше не нужны.

Ищете подробности? Я расскажу, как создать процесс сборки с помощью сценариев npm с нуля в Создание среды разработки JavaScript на Pluralsight.

Комментарии? Свяжитесь с нами ниже, на Reddit или Hacker News.

Наконец, я далеко не первый, кто это предлагает. Вот несколько отличных ссылок:

Кори Хаус - автор React and Redux in ES6, Clean Code: Writing Code for Humans и множества других курсов по Pluralsight. Он является архитектором программного обеспечения в VinSolutions и обучает разработчиков программного обеспечения на международном уровне таким методам разработки программного обеспечения, как интерфейсная разработка и чистое кодирование. Кори - Microsoft MVP, эксперт по разработке Telerik и основатель outlierdeveloper.com.