Grunt — распространенный и популярный инструмент для выполнения задач на JavaScript. Его архитектура основана на плагинах, которые вы можете комбинировать и настраивать для создания мощной системы сборки для ваших веб-приложений. Экосистема Grunt огромна и предлагает сотни плагинов, которые помогут вам в утомительных и повторяющихся задачах, таких как линтинг, тестирование, минификация, обработка изображений и так далее.
У меня было взрывное устройство и публикация моего плагина Grunt, и я хотел бы поделиться с вами опытом, который я приобрел на этом пути. Я покажу вам, как создать свой собственный маленький плагин Grunt и опубликовать его через менеджер пакетов npm .
Плагин, который мы создадим в этой статье, послужит средством для так называемых типографских сирот — отдельных слов в последней строке абзаца или блочного элемента — заменив последний пробел неразрывным пробелом. Это довольно простая задача, но при ее реализации мы коснемся всех соответствующих тем, таких как настройка, лучшие практики, настройка, тестирование и публикация.
Если вы хотите получить глубокие знания о механике Grunt или внести свой вклад в существующий плагин, эта статья для вас. Перед тем, как начать, я советую вам взглянуть на официальное руководство «Приступая к работе» и статью Этьена Марграффа « Как ворчать и проглатывать свой путь к автоматизации рабочего процесса» .
Плагин, который мы создадим в этой статье, доступен на GitHub . Для вашего удобства я добавил теги (называемые step01
— step04
) в хранилище. Если вы хотите следовать вместе с кодом под рукой, просто проверьте соответствующий тег. Например, команда git checkout tags/step02
отражает состояние кода после раздела 2.
Настройка вашей детской площадки
Если у вас на компьютере установлен Node.js , мы можем сразу приступить к настройке скелета нашего плагина. К счастью, команда Grunt предоставляет хороший инструмент под названием grunt-init
который облегчает разработку плагинов. Мы установим этот инструмент глобально с помощью npm
и клонируем шаблон плагина Grunt из Git:
npm install -g grunt-init git clone git://github.com/gruntjs/grunt-init-gruntplugin.git .grunt-init/gruntplugin
Теперь мы готовы создать новый каталог для нашего плагина и запустить команду grunt-init
:
mkdir grunt-typographic-adoption cd grunt-typographic-adoption grunt-init gruntplugin
Нам будет предложено несколько вопросов относительно метаданных нашего плагина. При именовании вашего плагина Grunt помните, что пространство имен grunt-contrib зарезервировано для задач, которые поддерживаются командой Grunt. Итак, ваша первая работа — найти значимое имя, которое соответствует этому правилу. Поскольку мы имеем дело с типографскими сиротами, я подумал, что название « grunt-typographic-принятии» может быть уместным.
Если вы поставили новую папку плагинов под контроль версий и перед удаленным запуском grunt-init
установите пульт GitHub, вам повезло. Скрипт скаффолдинга будет использовать информацию, предоставленную Git и GitHub, чтобы заполнить множество пунктов, которые вы должны отметить. Придерживайтесь значений по умолчанию для версий Grunt и Node.js, если только некоторые из ваших зависимостей не требуют конкретной. Что касается управления версиями вашего собственного плагина, вы должны ознакомиться с Semantic Versioning . Я предлагаю вам взглянуть на официальную документацию для лесов проекта, где вы можете прочитать больше о других доступных шаблонах для grunt-init
и способах указания ответов на приглашения по умолчанию.
Теперь давайте посмотрим на структуру каталогов и файлов, которые у нас сейчас есть:
.gitignore .jshintrc Gruntfile.js LICENSE README.md package.json - tasks | - typographic_adoption.js - test | - expected | - custom_options | - default_options | - fixtures | - 123 | - testing | - typographic_adoption_test.js
Файл .gitignore
пригодится, когда вы поставите свой плагин под контроль версий (операция, которую вы должны сделать, и, надеюсь, вы уже выполнили!). Gruntfile.js
определяет, что нужно сделать, чтобы построить наш плагин, и, к счастью, он поставляется с некоторыми предопределенными задачами, а именно: linting JavaScript (настроенный в .jshintrc
) и простой набор тестов (мы подробно рассмотрим соответствующую папку test
в минуту). README.md
и README.md
сами за себя, предварительно заполнены стандартным контентом и важны, как только вы решите опубликовать свой плагин.
Наконец, package.json
содержит всю информацию о нашем плагине, включая все его зависимости. Давайте установим и запустим его:
npm install grunt
Если все прошло гладко, мы вознаграждены нашей задачей typographic_adoption
в действии и выводом « Done, without errors.
, Похлопайте себя по спине, так как у нас есть полнофункциональный плагин Grunt. Пока он не делает ничего особенно полезного, но мы доберемся до цели. Вся магия происходит в tasks/typographic_adoption.js
где мы реализуем наш код против вдов. Но прежде всего напишем несколько тестов.
Разработка через тестирование
Всегда полезно сначала выполнить тесты и, таким образом, указать, что вы хотите, чтобы ваша задача выполнила. Мы снова проведем тесты, что дает нам хороший намек на то, что мы все правильно реализовали. Разработка через тестирование потрясающая, и пользователи вашего плагина будут вам благодарны!
Так чего же мы хотим достичь? Я уже говорил вам, что мы хотим справиться с типографскими сиротами , то есть отдельными словами в последней строке абзаца или другого блочного элемента. Мы сделаем это путем сканирования файлов на наличие элементов блока HTML, извлечения внутреннего текста и замены последнего пробела неразрывным пробелом.
Другими словами, мы кормим наш плагин этим:
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p>
И мы ожидаем, что это превратит это в это:
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p>
Поскольку наш плагин scaffold поставляется с nodeunit
тестирования nodeunit
, мы можем легко реализовать этот вид тестов.
Механизм прост:
- Grunt выполняет нашу типографскую задачу по внедрению для всех файлов, указанных в
Gruntfile.js
(лучшая практика заключается в том, чтобы поместить их вtest/fixtures
). - Преобразованные файлы затем сохраняются в
tmp
(файл.gitignore
гарантирует, что эта папка никогда не.gitignore
в ваш репозиторий кода). - Задача
nodeunit
ищет тестовые файлы вtest
и находитtypographic_adoption_test.js
. Этот файл определяет любое количество тестов, то есть проверяет, равен ли файл вtmp
своему аналогу вtest/expected
. -
nodeunit
сообщает нам в командной строке, если и какие тесты не пройдены или весь набор тестов пройден.
Обычно вы создаете один тест для каждой конфигурации, чтобы убедиться, что ваша задача может обрабатывать все виды сценариев и крайних случаев. Давайте уделим немного времени и подумаем о возможных конфигурациях для нашего плагина Grunt. В основном мы хотим, чтобы пользователь мог настраивать, в каких HTML-элементах выполняется наша задача. Опцией по умолчанию может быть каждый текстовый элемент HTML, содержащий текст ( h1
, p
, blockquote
, th
и многие другие), в то время как мы позволяем пользователю настроить его с помощью опции для установки произвольных селекторов CSS. Это помогает расширить или сузить сферу нашей задачи.
Теперь пришло время запачкать наши руки. Во-первых, перейдите к test/fixtures
, удалите файл 123
и отредактируйте testing
в простой HTML-файл с некоторыми блочными элементами, с которыми вы хотите протестировать свой плагин. Я решил использовать небольшую статью о Черной вдове Марвел, поскольку типографских сирот иногда называют вдовами.
Теперь скопируйте содержимое test/fixtures/testing
и переопределите два файла в test/expected
с ним. Отредактируйте их в соответствии с тем, что вы ожидаете получить в результате обработки плагина testing
файлом. Для случая с пользовательскими параметрами я выбрал сценарий, в котором пользователь хочет, чтобы элементы <p>
были де-сиротами.
Наконец, отредактируйте Gruntfile.js
чтобы он был Gruntfile.js
только на ваш testing
файл (это означает удаление 123
битного из файловых массивов) и дал вашим тестам содержательное описание в test/typographic_adoption_test.js
.
Момент истины настал. Запустите grunt
в корне вашего проекта:
grunt ... Warning: 2/2 assertions failed
Brilliant! Все наши тесты не пройдены, давайте исправим это.
Реализация задачи
Прежде чем мы начнем с реализации, мы должны подумать о помощниках, которые могут нам понадобиться. Так как мы хотим искать в HTML-файлах определенные элементы и изменять их текстовую часть, нам нужен механизм обхода DOM с jQuery-подобными возможностями. Я нашел cheerio очень полезным и легким, но не стесняйтесь использовать все, что вам удобно.
Давайте подключим Cheerio как зависимость:
npm install cheerio --save
Это установит пакет node_modules
в ваш каталог node_modules
а также, благодаря --save
, сохранит его под dependencies
в вашем package.json
. Осталось только открыть файл tasks/typographic_adoption.js
и загрузить модуль cheerio:
module.exports = function(grunt) { var cheerio = require('cheerio'); ...
Теперь давайте исправим наши доступные опции. На этом этапе пользователи могут настроить только одну вещь: элементы, которые они хотят де-сиротизировать. Найдите объект options
внутри функции grunt.registerMultiTask
и измените его соответствующим образом:
var options = this.options({ selectors: 'h1.h2.h3.h4.h5.h6.p.blockquote.th.td.dt.dd.li'.split('.') });
Объект options
дает нам все индивидуальные настройки, которые пользователи плагина помещают в свои Gruntfile.js
а также возможность устанавливать параметры по умолчанию. Идите дальше и измените цель custom_options
в своем собственном Gruntfile.js
чтобы отразить то, что тестируют ваши тесты из главы 2. Так как я просто хочу обработать абзацы, это выглядит так:
custom_options: { options: { selectors: ['p'] }, files: { 'tmp/custom_options': ['test/fixtures/testing'] } }
Обязательно обратитесь к документации Grunt API для получения дополнительной информации.
Теперь, когда у нас есть cheerio и наши опции, мы можем пойти дальше и реализовать ядро плагина. Вернитесь к tasks/typographic_adoption.js
и прямо под строкой, в которой вы строите объект параметров, замените код scaffolding следующим:
this.files.forEach(function(f) { var filepath = f.src, content, $; content = grunt.file.read(filepath); $ = cheerio.load(content, { decodeEntities: false }); $(options.selectors.join(',')).each(function() { var text = $(this).html(); text = text.replace(/ ([^ ]*)$/, ' $1'); $(this).html(text); }); grunt.file.write(f.dest, $.html()); grunt.log.writeln('File "' + f.dest + '" created.'); });
Мы перебираем все файлы, которые мы указали в Gruntfile.js
. Функция, которую мы вызываем для каждого файла, загружает содержимое файла с grunt.file
API grunt.file
, grunt.file
его в cheerio и ищет все элементы HTML, которые мы выбрали в опциях. Найдя его, мы заменяем последний пробел внутри текста каждого элемента неразрывным пробелом и записываем его обратно во временный файл. Наш тестовый набор теперь может сравнивать эти временные файлы с нашими ожидаемыми и, надеюсь, он показывает вам что-то вроде этого:
grunt ... Running "nodeunit:tests" (nodeunit) task Testing typographic_adoption_test.js..OK >> 2 assertions passed (59ms) Done, without errors.
Потрясающие! Мы только что реализовали наш собственный маленький плагин Grunt, и он работает как шарм!
Если вы хотите, вы можете улучшать, расширять и полировать его до тех пор, пока вы не будете довольны результатом и не захотите делиться им с другими разработчиками.
Опубликуйте свой плагин
Публикация нашего плагина проста и занимает всего несколько минут. Прежде чем мы добавим наш код, мы должны убедиться, что все настроено правильно.
Давайте посмотрим на файл package.json
где находится вся информация, которую npm использует в своем реестре. Наш первоначальный шаблон уже позаботился о добавлении gruntplugin
в список keywords
, что необходимо для того, чтобы наш плагин был найден как плагин Grunt . Это момент, чтобы занять некоторое время и добавить больше ключевых слов, чтобы люди могли легко найти наш плагин.
Мы также заботимся о нашем файле README.md
и предоставляем нашим будущим пользователям документацию по общему использованию нашей задачи, вариантам использования и опциям. Благодаря grunt-init
у нас уже есть хороший первый черновик для работы, и мы можем отшлифовать его оттуда.
После того, как эти приготовления сделаны, мы можем опубликовать наш плагин. Если у вас еще нет учетной записи npm, вы можете создать ее на их веб-сайте или запустить npm в командной строке и настроить там все. Следующая команда попросит вас .npmrc
имя пользователя и пароль и либо создать нового пользователя на npm и сохранить свои учетные данные на .npmrc
либо войти в систему:
npm adduser
Как только вы зарегистрируетесь и войдете в систему, вы можете загрузить свой плагин в npm:
npm publish
Вот и все! Вся необходимая информация автоматически извлекается из файла package.json
. Взгляните на плагин Grunt, который мы только что создали здесь .
Выводы
Благодаря этому руководству вы узнали, как создать плагин Grunt с нуля. Более того, если вы опубликовали его, вы теперь являетесь счастливым владельцем плагина Grunt, который доступен в Интернете и готов для использования другими веб-разработчиками. Продолжайте в том же духе, продолжайте поддерживать свой плагин и придерживайтесь тестируемой разработки.
Если вы находитесь в процессе создания плагина Grunt или уже создали его и хотите поделиться чем-то в процессе, пожалуйста, оставьте комментарий в разделе ниже. Еще раз хочу подчеркнуть, что плагин, который мы создали в этой статье, доступен на GitHub .