Статьи

Как передать параметры командной строки в задачи Gulp

Я большой поклонник Gulp.js, и последние опросы показывают, что почти 44% разработчиков переднего плана используют задачи Gulp сегодня .

Простота Gulp — одна из самых привлекательных его черт. Вы пишете функцию задачи в вашем gulpfile.js :

 gulp.task('doSomething', () => { // do something }); 

затем выполните эту задачу из командной строки с помощью gulp doSomething . Задачи могут быть как базовыми, так и сложными, как вам нравится, и включать дополнительные подзадачи

Однако невозможно передать аргументы в командной строке, которые могут использоваться этой задачей, например

 gulp doSomething --option1 "my string" --option2 123 --option3 

(где option3 будет равно true )

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

Нужны ли аргументы Gulp Tasks?

Обычно нет — в противном случае возможность передавать аргументы задачам была бы добавлена ​​много лет назад! Задачи Gulp написаны на JavaScript, так что вы можете установить значения по умолчанию в вашем коде.

Вы также можете анализировать переменные среды, такие как NODE_ENV . Например, вы можете проверить, установлено ли значение для production или аналогичной на реальном сервере. Затем этот параметр можно использовать для определения, минимизируются ли исходные файлы JavaScript при запуске задачи, например,

 // is this a development build? const devBuild = ((process.env.NODE_ENV || 'development').trim().toLowerCase() === 'development'); // Gulp plugins const stripdebug = require('gulp-strip-debug'), // remove debugging code uglify = require('gulp-uglify'); // minify // build JavaScript gulp.task('js', () => { let jsbuild = gulp.src('src/js/*') .pipe(some-plugin1()) .pipe(some-plugin2()); // production server tasks if (!devBuild) { jsbuild = jsbuild .pipe(stripdebug()) .pipe(uglify()); } return jsbuild.pipe(gulp.dest('build/js/')); }); 

Теперь вы можете установить export NODE_ENV=production в Linux / Mac или set NODE_ENV=production в Windows до запуска задачи set NODE_ENV=production gulp js . Затем он удалит console.log и операторы debugger прежде чем свернуть ваши файлы JavaScript.

Наконец, если вы хотите, чтобы задача выполняла что-то немного другое, вы можете создать новую задачу. Задачи могут быть объединены в цепочку для запуска по мере необходимости, например:

 gulp.task('doSomething1', () => { return gulp.src('src/*') .pipe(some-plugin1()) .pipe(gulp.dest('build/')); }); // run doSomething1 first gulp.task('doSomething2', [doSomething1], () => { // do something else return gulp.src('src/*') .pipe(some-plugin2()) .pipe(gulp.dest('build/')); }); 

Запуск gulp doSomething1 выполнит первую задачу. Запуск gulp doSomething2 выполнит обе задачи по порядку, поскольку doSomething1 определяется как зависимость в необязательном массиве после имени задачи.

Должны ли мы когда-либо рассматривать аргументы?

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

Тем не менее, всегда есть крайние случаи …

1. Пароли и безопасность

Обычно вы должны избегать жесткого кодирования учетных данных, таких как идентификаторы и пароли, в gulpfile.js . Рассмотрим следующую задачу, которая развертывает файлы на сервере через FTP с помощью плагина vinyl-ftp :

 gulp.task('deploy', () => { let ftp = require('vinyl-ftp'), conn = ftp.create({ host : 'mysite.com', user : 'myuserid', password : 'mypassword', parallel : 5 }), glob = [ 'build/**/*' ], src = { base : 'build/', buffer : false }, remotePath = '/public_html/'; return gulp.src(glob, src) .pipe(conn.newerOrDifferentSize(remotePath)) .pipe(conn.dest(remotePath)); }); 

(Следует признать, что FTP не является хорошим методом развертывания, но он по-прежнему используется многими разработчиками и может быть единственным вариантом на некоторых хостах.)

Есть несколько проблем с этим подходом:

  1. Хост FTP, идентификатор пользователя, пароль и путь жестко запрограммированы в файле. Это может привести к проблемам с безопасностью, если код будет храниться в общедоступном репозитории GitHub и может быть просмотрен, клонирован и запущен любым пользователем.
  2. Любой разработчик может запустить gulp deploy в любое время с любого устройства. Это вряд ли будет желательно для больших групп, которые хотят контролировать, когда развертывания происходят.
  3. Если учетные данные изменяются, вы должны вручную обновить gulpfile.js чтобы убедиться, что задача развертывания все еще работает.

2. Различия в расположении источника, сборки или задачи

Gulp можно использовать не только для типичных задач сайта. Например, у вас могут быть общие задачи по очистке папок, созданию баз данных, передаче файлов и т. Д. Жесткое кодирование чего-то вроде базы данных или имени папки сделает эти задачи менее полезными.

3. Сложные задачи

Представьте себе сложную задачу, включающую десятки плагинов. Если нецелесообразно разбивать его на несколько подзадач, может оказаться сложным добавить параметры конфигурации без редактирования gulpfile.js непосредственно перед запуском задачи.

Вы можете подумать о дальнейших крайних случаях (комментарии приветствуются!)

Как передать аргументы в ваши задачи Gulp.js

Свойство process.argv в Node.js возвращает массив, содержащий процесс, скрипт и все аргументы командной строки. Например, gulp task1 --a 123 --b "my string" --c возвращает следующий массив (значения могут различаться в зависимости от вашей ОС и настроек) :

 [ '/usr/bin/nodejs', '/home/user/.node_modules_global/bin/gulp', 'task1', '--a', '123', '--b', 'my string', '--c' ] 

Этот массив может быть проанализирован в gulpfile.js . Следующий код создает объект с именем arg содержащий значения аргументов:

 // fetch command line arguments const arg = (argList => { let arg = {}, a, opt, thisOpt, curOpt; for (a = 0; a < argList.length; a++) { thisOpt = argList[a].trim(); opt = thisOpt.replace(/^\-+/, ''); if (opt === thisOpt) { // argument value if (curOpt) arg[curOpt] = opt; curOpt = null; } else { // argument name curOpt = opt; arg[curOpt] = true; } } return arg; })(process.argv); 

Функция проходит через массив process.argv . Когда он встречает значение, которому предшествует одна или несколько черточек, он создает новое именованное значение в объекте arg которого установлено значение true . Когда он встречает значение без черточек, он устанавливает предыдущее именованное значение (если доступно) для этой строки.

Когда мы запускаем gulp task1 --a 123 --b "my string" --c , объект arg устанавливается в:

 { "a": "123", "b": "my string", "c": true } 

Поэтому мы можем исследовать и использовать эти значения по мере необходимости.

Предполагая, что arg установлен в верхней части gulpfile.js , мы можем переписать нашу задачу развертывания FTP, чтобы мы могли передать:

  • идентификатор пользователя в качестве аргумента --user или --u
  • пароль в качестве аргумента --p или --p
 gulp.task('deploy', () => { let ftp = require('vinyl-ftp'), conn = ftp.create({ host : 'mysite.com', user : arg.user || arg.u, // command line option password : arg.password || arg.p, // command line option parallel : 5 }), glob = [ 'build/**/*' ], src = { base : 'build/', buffer : false }, remotePath = '/public_html/'; return gulp.src(glob, src) .pipe(conn.newerOrDifferentSize(remotePath)) .pipe(conn.dest(remotePath)); }); 

Развертывание произойдет только в том случае, если мы запустим задачу с соответствующими учетными данными FTP, например

 gulp deploy --u myuserid --p mypassword 

Завершение

Как мы уже видели, с небольшим количеством нестандартного кода можно передавать параметры в задачи Gulp. Хотя для ваших задач часто нет необходимости получать аргументы, мы видели, что в некоторых случаях это полезно. Это определенно хорошая техника для использования в вашем наборе инструментов.

Код разбора аргумента можно использовать для любого процесса командной строки Node.js. Тем не менее, модуль commander предлагает значительно большую сложность, если вам это требуется в не-Gulp проектах.

Я надеюсь, что вы найдете это полезным. Конечно, просто потому, что вы можете передавать аргументы задачам Gulp, это не значит, что вы должны это делать ! Если вы найдете более удачные варианты использования, дайте мне знать в комментариях.

Эта статья была рецензирована Тимом Севериеном . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!