Статьи

Meet Grunt: инструмент для сборки JavaScript

Если вы работаете над большим проектом, у вас, без сомнения, будет сценарий сборки или набор сценариев задач, которые помогут в некоторых повторяющихся частях процесса. Вы можете использовать Ant или Rake, в зависимости от языка, на котором написан проект.

Но что вы используете, если проект в основном JavaScript? Это проблема, которую Бен Алман решил решить, когда создал Гранта .


Что именно Grunt? Хорошо, README на Github говорит

Grunt — это инструмент для построения командной строки на основе задач для проектов JavaScript.

Идея в том, что при работе над проектом JavaScript есть множество вещей, которые вы хотите делать регулярно. Как что, спросите вы? Ну, как конкатенация заданных файлов, запуск JSHint для вашего кода, запуск тестов или минимизация ваших скриптов. Если вы вставляете свой JavaScript в JSHint онлайн, вы, вероятно, понимаете, что есть лучший способ сделать это; даже если вы используете cat для объединения файлов или минификатора командной строки, было бы неплохо иметь единый унифицированный набор команд для всех этих дополнительных задач, который работал бы для каждого отдельного проекта JavaScript, верно?

Это то, к чему стремится Грант. Он имеет множество встроенных задач, которые позволят вам продвинуться далеко вперед, с возможностью создавать свои собственные плагины и скрипты, которые расширяют базовую функциональность.

Чтобы узнать больше о Grunt intro, смотрите пост Бена в его личном блоге и блоге Bocoup .


Grunt построен на Node.js и доступен как пакет через менеджер пакетов Node (npm). Вы хотите установить его глобально, поэтому используйте эту команду:

1
npm install -g grunt

Вы заметите, что он устанавливает довольно много зависимостей; Есть и другие пакеты npm, которые использует Grunt. Как только это будет сделано, вы готовы!


Как вы знаете, Grunt — это инструмент командной строки; поэтому я предполагаю, что у вас открыто окно терминала для оставшейся части этого урока.

Давайте начнем с создания примера каталога проекта; на самом деле мы не собираемся строить проект здесь, но посмотрим, как работает Grunt в этом каталоге. Как только вы окажетесь в этом каталоге, запустите команду grunt (согласно документации, если вы работаете в Windows, вам может потребоваться запустить grunt.cmd ). Вы, вероятно, увидите что-то вроде этого:

1
<FATAL> Unable to find ‘grunt.js’ config file.

Прежде чем вы сможете использовать Grunt в полной мере, вам понадобится файл grunt.js в каталоге проекта. К счастью, Grunt может автоматически сгенерировать файл grunt.js — и некоторые другие материалы скелета проекта — с помощью задачи init , которая может выполняться без установленного файла grunt.js . Но grunt init прежнему недостаточно для запуска вашего проекта, как вы увидите, запустите ли вы его. Вам нужно выбрать тип проекта для генерации. Запустив grunt init , вы получите список типов проектов на выбор:

  • jquery : плагин JQuery
  • node : модуль узла
  • commonjs : модуль CommonJS
  • gruntplugin : плагин Grunt
  • gruntfile : Gruntfile ( grunt.js )

Если ваш проект не соответствует ни одному из первых четырех типов проектов, вы можете использовать последний: gruntfile : он просто создает базовый grunt.js который вы можете заполнить. Итак, давайте попробуем это с jQuery. Шаблон плагина. Запустите grunt init:jquery в своем терминале.

Вы заметите много начального вывода. Если вы потратите время на чтение примечаний к шаблону, вы увидите, что нам нужно будет заполнить несколько значений, таких как название проекта и название проекта. На самом деле, после этой заметки вы увидите что-то вроде этого:

1
2
Please answer the following:
[?] Project name (jquery.demo)

Всякий раз, когда вы инициализируете проект, Grunt будет задавать вам ряд вопросов, чтобы он мог заполнить несколько вариантов. Это значение в скобках? Это предложение по умолчанию, основанное на типе проекта и имени каталога проекта. Если вы хотите изменить его, напишите свое собственное имя проекта в конце строки и нажмите «enter»; в противном случае просто нажмите «Enter», чтобы использовать имя по умолчанию.

Продолжайте и заполните остальные поля. Для проекта плагина jQuery, вот что еще вам нужно дать:

  • Название Проекта
  • Описание
  • Версия
  • Репозиторий проекта git
  • Домашняя страница проекта
  • Отслеживание проблем проекта
  • Лицензии
  • Имя автора
  • Email автора
  • URL автора
  • Требуемая версия jQuery

Многие из них имеют значения по умолчанию; если вы хотите использовать значение по умолчанию, просто нажмите Enter для этой строки; чтобы оставить поле пустым, вы можете просто напечатать «none». После того, как вы пройдете через все опции, вы увидите, что Grunt создает некоторые базовые файлы проекта. Как что? Как это:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
LICENSE-GPL
LICENSE-MIT
README.md
grunt.js
libs
|— jquery
|
|— qunit
     |— qunit.css
     |— qunit.js
package.json
src
|— jquery.demo.js
test
|— jquery.demo.html
|— jquery.demo_test.js

Как видите, это дает нам хорошее начало: у нас есть не только файл плагина ( src/jquery.demo.js ), но и тесты Qunit ( test/jquery.demo_test.js ). И это тоже не пустые файлы. У них есть некоторый начальный контент, с таким базовым плагином jQuery и юнит-тестами. Идите дальше и проверьте содержимое этих файлов, вы поймете, что я имею в виду.

Grunt делает больше, чем просто настраивает проект для вас.

Конечно, Grunt делает больше, чем просто настраивает проект для вас. В частности, наш проект теперь имеет grunt.js : файл конфигурации для конкретного проекта; благодаря опциям, которые он устанавливает, мы теперь можем использовать другие встроенные задачи Grunt. Вскоре мы раскроем его и внесем некоторые коррективы, но сейчас давайте выполним некоторые задачи.

Если вы сейчас запустите grunt без параметров, мы запустим задачу по умолчанию, если она была установлена. В случае проекта плагина jQuery это эквивалентно выполнению этих четырех команд:

  • Grunt Lint: проверяет ваш JavaScript с JSHint
  • grunt qunit : запускает ваши тесты Qunit
  • grunt concat : объединяет ваши файлы проекта вместе и помещает новый файл в папку dist
  • grunt min : минимизирует выход файла concat .

Я должен отметить кое-что о тестах Qunit здесь: тесты Qunit предназначены для запуска в браузере по умолчанию; просто откройте tests/jquery.demo.html (или ваш аналог) в браузере. Тем не менее, тест grunt qunit хочет запустить их на терминале, а это значит, что вам нужно установить PhantomJS. Это не сложно: просто зайдите на phantomjs.org и скачайте и установите последнюю версию. Если Grunt сможет найти это на вашем пути, он сможет запускать тесты Qunit из терминала.

Итак, запуск grunt должен дать вам вывод, похожий на этот:

Грунт выход

Как видите, каждое из наших четырех заданий выполнено. Если какой-либо из них потерпит неудачу, остальные задачи будут отменены (если вы не вызовете Grunt с флагом --force ).


Мы уже получили много замечательных функциональных возможностей от Grunt, используя их как есть. Однако давайте откроем этот файл grunt.js и сделаем некоторые настройки.

Внутри grunt.js вы увидите, что вся настройка выполняется путем передачи литерала объекта в grunt.initConfig() . Давайте посмотрим на некоторые свойства нашего объекта конфигурации.

Это свойство указывает на файл package.json , созданный Grunt в каталоге нашего проекта. Наличие файла package.json является частью спецификации CommonJS Packages ; это единственное место, где может храниться большая часть метаданных о проекте (имя, версия, домашняя страница, ссылка на репозиторий … многие значения, которые вы задали при инициализации проекта). Однако это свойство pkg не только указывает на файл пакета: обратите внимание на синтаксис: '<json:package.json>' . Это одна из встроенных директив Grunt: она фактически загружает файл JSON, поэтому Grunt (или вы) можете получить доступ ко всем свойствам файла package.json из свойства pkg .

meta свойство — это объект с единственным свойством: баннер. Этот баннер является комментарием, который идет вверху сцепленных или свернутых файлов проекта. Как видите, это строка с некоторыми шаблонными тегами ( <%= %> ); в большинстве случаев теги окружают вызов свойства в свойстве pkg , такого как pkg.title . Однако вы также можете выполнять функции внутри этих тегов: использование grunt.template.today() и _.pluck() показывает нам это.

Я сгруппировал следующие пять свойств вместе, потому что они очень похожи. Все они устанавливают параметры для конкретных задач, задач, которым они названы. При настройке этих задач важно отметить, что Grunt различает два типа задач: обычные задачи и многозадачные. В основном, разница в том, что обычные задачи имеют только один набор параметров конфигурации, в то время как многозадачность может иметь несколько наборов инструкций (называемых целями ). Из пяти задач, которые я перечислил в заголовке этого раздела, единственная, которая не является многозадачной, — это watch .

Обратите внимание, что в нашем объекте config свойства qunit и lint являются объектами со свойством files . files — единственная цель для этой задачи. В обоих случаях это массив файлов, которые будут использоваться при выполнении этой задачи. Допустим, я хочу иметь возможность собирать только файлы в подкаталоге src . Я мог бы добавить еще одну цель, чтобы свойство lint выглядело так:

1
2
3
4
lint: {
  files: [‘grunt.js’, ‘src/**/*.js’, ‘test/**/*.js’],
  src: [‘src/**/*.js’]
},

Теперь, чтобы lint только файлы в src , я запускаю grunt lint:src : я передаю имя цели после двоеточия. Если я бегу только grunt lint , обе цели будут запущены.

В случае задач concat и min цели более сложны: это объекты со свойствами source ( src ) и destination ( dest ). Конечно, это говорит Grunt, где взять файлы и где их разместить, когда они будут обработаны, соответственно. Если вы добавите другие файлы в свой проект, вы захотите добавить их в нужное место, чтобы убедиться, что они объединены и правильно свернуты. Итак, если бы я добавил файл src/utils.js , от которого зависел мой плагин jQuery, я бы изменил concat.dist.src на этот:

1
src: [‘<banner:meta.banner>’, ‘src/utils.js’, ‘<file_strip_banner:src/<%= pkg.name %>.js>’],

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

Говоря о задаче часов, что именно она делает? Очень просто: он запускает задачи в свойстве tasks при изменении файла в этом списке файлов. По умолчанию qunit задачи lint и qunit .

Это свойство просто настраивает, какие «плохие части» ищет JSHint в вашем JavaScript. Полный список опций можно найти на страницах опций сайта JSHint .


В самом низу нашего файла grunt.js вы увидите grunt.js строку:

1
grunt.registerTask(‘default’, ‘lint qunit concat min’);

Это то, что создает нашу задачу по умолчанию; Вы знаете, тот, который работает, когда мы бежим, просто grunt . Это фактически создает задачу псевдонима, и вы можете создать столько задач псевдонима, сколько захотите:

1
grunt.registerTask(‘src’, ‘lint:src qunit:src concat:src min:src’);

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


Хотя задачи, которые поставляются с Grunt, далеко уйдут, вы, вероятно, можете подумать о других вещах, которые вы хотели бы автоматизировать. Не беспокойтесь: Grunt поставляется с API, который позволяет любому создавать задачи и плагины Grunt. Хотя в этом руководстве мы не будем создавать задачи Grunt, если вы заинтересованы в этом, вам следует начать с шаблона плагина Grunt (запустить grunt init:gruntplugin ), а затем прочитать документы API . После того как вы написали свою задачу, вы можете загрузить ее в проект, добавив grunt.js файл grunt.js вашего проекта:

1
grunt.loadTasks(PATH_TO_TASKS_FOLDER);

Обратите внимание, что параметр — это не путь к самому файлу задачи, а путь к папке, в которой находится файл задачи.

Тем не менее, другие плагины Grunt начинают появляться, и некоторые доступны на NPM. После того, как вы установите их через npm install , вы загрузите их в свой проект с помощью следующей строки:

1
grunt.loadNpmTasks(PLUGIN_NAME);

Конечно, вы захотите проверить документацию плагина, чтобы увидеть, что вы должны добавить в свой объект конфигурации.

Какие плагины Grunt доступны? Ну, так как Грант такой новый (менее месяца, как я это пишу), их пока не так уж много. Я нашел два:

  • grunt-css : для линтинга и минимизации CSS
  • grunt-jasmine-task : для запуска спецификаций Jasmine

Если вы нашли других, я хотел бы услышать о них; разместите их в комментариях!


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

Я надеюсь, что Grunt станет стандартом сообщества, и в ближайшем будущем мы увидим множество задач, плагинов и шаблонов инициализации. Как вы к этому относитесь?