воскресенье, 25 января 2015 г.

Настройка на gulpfile.js

Удивительную и несравненную индийскую кухню невозможно представить без экзотических специй: есть у южан масала для овощей, есть для риса, для рыбы, птицы и мяса, есть и масала–чай. Но это не полный перечень многообразий и разновидностей. Дело в том, что каждая хозяйка в каждом доме имеет свой собственный рецепт масалы для овощей, риса, мяса и всего прочего — нередко этот рецепт трепетно и бережно передаётся из поколения в поколение, как в европейских аристократических фамилиях передаётся столовое серебро.

Эти самые масалы прижились и на Ближнем Востоке: в бакалейных отделах супермаркетов можно увидеть ряды, уставленные картонными пачками с готовыми смесями. Впрочем, в арабском мире эти наборы могут иметь и другие имена: например, я охотно пользовался ливанской смесью, называемой «за′атар» (или «загатар», если читать это слово по правилам чтения украинского языка — в арабском тоже есть фрикативный звук «г»). Как бы там ни было, но восточные базары, включая «супербазары» (то есть, супермаркеты) предоставляют достаточный ассортимент специй (например, см. фото в начале статьи), чтобы составить композицию приправ — масалу — на любой, даже самый взыскательный, вкус.

Я, вот, тоже решил замесить свою gulp—«масалу» для автоматизации работы над сайтом, но приступил к работе не с чистого листа, а разбирая и отлаживая уже имеющийся файл сценариев gulpfile.js из весьма неплохого набора WebStarterKit 0.5.2 от Google.

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

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

$.useref();

Оказалось, что этот инструмент загружает (в базовом gulpfile) 17 плагинов, имена которых начинаются с «gulp» — вроде бы, ничего особенного, но при изменении набора этих самых плагинов (удалении ненужных и добавлении необходимых), они неизменно будут «подтягиваться» в скрипт по списку установленных пакетов, имеющихся в из package.json. А вызывается загруженный с помощью этого загрузчика плагин как некий метод: в приведенном выше примере вызывается плагин gulp-useref.

По умолчанию, gulp-load-plugins загружает плагины, соответствующие маске «gulp-*», но эту маску можно изменить. Разработчики рассматриваемого gulpfile.js, по какой–то причине, не стали этого делать и часть плагинов загружают «руками», то есть, путём явного указания имён. Не вдаваясь в причины подобной избирательности, я решил следовать той же тактике (по крайней мере, пока).

В дальнейшем, после вдумчивого и неторопливого сравнения моего первичного перечня плагинов и предлагаемого гугловскими экспертами, мой файл gulp–настроек (package.json) обогатился такими приобретениями:

  • gulp–cache — создание промежуточного временного файла;
  • gulp–changed — отслеживание изменённых файлов;
  • gulp–csso — оптимизация и минимизация CSS–файлов;
  • gulp-if — управление выполнением задачи по условию;
  • gulp-jshint — проверка файлов сценариев Javascript на наличие ошибок;
  • gulp-replace — замена строки;
  • gulp-size — вывод сведений о размере проекта или составляющих его файлов;
  • gulp-useref — редактирование ссылок на используемые ресурсы (css, javascript) с учётом изменений конечных имён файлов;
  • jshint-stylish — дополнение к плагину gulp-jshint, позволяющее выводить разработчику более содержательные описания выявленных ошибок;
  • psi — тестирование компонентов проекта и вывод подробной информации о проекте;
  • run-sequence — запуск нескольких задач gulp последовательно или параллельно.

Оказались невостребованными шесть плагинов из упоминавшихся в гугловском файле сценариев:

  • apache-server-config, gulp–flatten и opn — плагины установлены (имеются в файле конфигурации package.json), но не упоминаются в базовом gulpfile.js, то есть, нет практической надобности в их использовании;
  • browser-sync — дублирует функциональность gulp-livereload;
  • require-dir — подключает файлы из указанной в аргументах папки, но пока подключать нечего;
  • gulp-ruby-sass — дублирует функциональность Scout.

Кроме того, из первоначального набора, составленного при установке gulp, удалены пакеты:

  • gulp-autoprefixer и gulp-sass — дублируют функциональность Scout;
  • gulp-browserify, gulp-notify и gulp-util — не нашлось применения.

А ещё угроза удаления нависла над плагинами из первоначального набора, которые, похоже, дублируют утилиты из нового набора (WebStarterKit):

  • gulp-concat и gulp-rename, похоже, дублирует gulp-useref;
  • gulp-filesize — gulp-size;
  • glob вроде бы, нигде не используется, но вдруг пригодится….

воскресенье, 18 января 2015 г.

Интеграция и кооперация

Несомненно, интегрированная среда разработчика (IDE — Intregrated Development Environment) штука хорошая, можно сказать, замечательная. Как правило, под такой средой понимается единая программа, объединяющая в себе и редактор для написания кода, и компилятор, и систему сборки, и отладчик — потому она и называется интегрированной. Вообще–то, особых проблем с её освоением и использованием быть не должно: можно даже подстроить отдельные компоненты под свои личные префернции с помощью плагинов. Но как быть, если уже привык к некоторому набору инструментов, не только идеально подстроив–настроив, а и отшлифовав–отполировав каждый из них? Перспектива перехода на любую «классическую» IDE воспринимается как замена мягких и уютных бурок на стариковских ногах стильными кожаными туфлями на модном, но некомфортном каблуке.

Вот и возникает противоречие: с одной стороны, чтобы всё срабатывало само собой («механизация и автоматизация в действии»), а с другой стороны, сердце кровью обливается от грядущего расставания с отдельными приложениями, столь милыми сердцу, глазам и прочим органам.

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

Свою «кооперативно–интегрированную» среду для работы с сайтом я начал строить на Notepad++ и «джентльменском наборе» Денвер (веб–сервер Apache, СУБД MySQL, интерпретатор PHP и много других утилит, локально имитирующих стандартную службу хостинга). Строго говоря, текстовый редактор и пакет веб–процессинга никак между собой не связаны, то есть, не интегрированы, но в ближайшее время и с неизбежностью мировой революции будут скооперированы: все усилия по интегрированию или псевдоинтегрированию направлены на решение светлой задачи — добиться незамедлительного и автоматического отображения в браузере любых изменений в компонентах веб–страницы (html, css, php, javascript, изображения jpeg, png, gif), большая часть которых производится именно в текстовом редакторе.

Крайние элементы «пазла» обозначены, теперь нужно выстроить цепочку из правильно подобранных промежуточных компонентов.

Если начинать движение от Блокнота, то к нему уже «прикручен» интерпретатор–преобразователь SASS: и сама система установлена (вернее, клон этой системы, без Ruby, — Scout), и плагин, обеспечивающий интерфейс редактора с интерпретатором.

Следующий элемент цепочки — gulp, система сборки проекта, который «подхватывает» изменённые файлы (в том числе и созданный Скаутом), обрабатывает их в соответствии с моим набором инструкций и посылает сигнал Огнелису о необходимости перегрузить страницу. Браузер распознаёт этот сигнал благодаря предусмотрительно установленному расширению и запрашивает обновлённую версию страницы у веб–сервера. Апач, входящий в состав Денвера (вот мы до него и добрались) выполняет запрос, и перед глазами изумлённого разработчика — ай, шайтан! — возникает то, чего он добивался (или же нечто совершенно неожиданное — в случае ошибки).

Ключевым элементом в этой цепочке на текущий момент оказался Гульп: всё остальное уже настроено и работает на благо любимого сайта. Поскольку автор статьи не располагает кривой козой (нормальной козы, кстати, тоже нет), то возможности объехать проблему на этом сомнительном транспортном средстве не предвидится, по крайней мере, в обозримом будущем. Таким образом, задачу приходится решать.

В качестве отправной точки я выбрал гугловский «стартовый пакет разработчика», который тоже использует Gulp. Итак, начинаю читать документацию и разбираться в его устройстве и функциональности по старому детскому принципу: откручивать кукле голову, чтобы увидеть внутренности.

Собственно говоря, начальный пакет разработчика содержит набор шаблонов и инструментов, который способен полностью заменить HTML5Boilerplate и Bootstrap, хотя команда Google тактично и дипломатично оставляет решение об отказе от этих двух пакетов (и переходе на их продукт) на усмотрение разработчика, то есть, вполне допускает некий симбиоз. Для меня же объектом первостепенного интереса в гугловском наборе является предлагаемый файл–сценарий gulpfile.js: именно в него я и полез с зубилом, молотком, сверлом и плоскогубцами.

воскресенье, 11 января 2015 г.

Шаблоны–трафареты

Детские воспоминания о летнем отдыхе на море, воскрешют перед мысленным взором живописное полотно, изображающее тщедушную лошадёнку размером со здоровенную псину, на которую взгромоздился лихой горец в папахе и чёрном цее с газырями — какой–нибудь весёлый дядька суёт свою розовую от южного солнца и опухшую от разливного вина морду в дырку между папахой и воротником цея, суетливый фотограф клацает затвором и получается фотография: будто бы скачет штымп верхом, почему–то развернувшись лицом и корпусом к объективу, унося в неведомую даль толстомясую тётку с густыми сросшимися бровями и равнодушным взглядом, сидящую на той же конесобаке. Тётка должна бы олицетворять украденную невесту, но даже неискушённые отроческине представления о взаимоотношениях полов вызывали смутные сомнения: неужели этот мужик не мог найти себе чувиху получше?

Позже, изобретательные уличные фотографы перешли на «дурилки картонные», и можно было в центре любого мегаполиса сфотографироваться с фанерными М.Горбачёвым, Р.Рейганом или Усамой бен–Ладеном (не к ночи будь помянут!)

Цифровая эра внесла новые подходы и техники в арсенал фотографов–приколистов: теперь даже не требуется, высунув от старания кончик языка, выпиливать из фанерки какую–нибудь знаменитость или изощряться, малюя на холстине вокруг дырки для лица клиента заведомо малохудожественную композицию. Теперь достаточно запустить графический редактор, вырезать из цифрового изображения физиономию заказчика и вставить его в цифровой же трафарет (например, такой, как изображён на фото вверху).

Вообще говоря, ирония по поводу шаблонов уместна только в контексте неудачных реализаций — в большинстве остальных случаях трафареты весьма и весьма полезны. Гордо выпятив грудь от переполняющего чувства собственной прозорливости и догадливости, должен ответственно заявить, что много лет тому назад самостоятельно пришёл к идее разделять данные (программно создаваемый контент сайта) и представление (оформление сайта, его дизайн). Тогда появились первые версии систем управления контентом, но мне совершенно не хотелось тратить время на вникание в Wordpress или Joomla! — душа просила чего—нибудь попроще.

Я нашёл невероятно простое и столь же невероятно эффективное средство — php–класс XTemplate: нет ничего лишнего, но есть всё, что необходимо.

Вдохновлённый классами шаблонов FastTemplate и QuickTemplate, венгерский программер Варнава Дебрецени (Barnabas Debreczeni) разработал в 2000 году свой движок, который оказался существенно быстрее своих предшественников, хотя и основывался на идентичных синтаксисе и идеологии (заметьте, не развил существовавшие, а наваял «с нуля»). Энтузиазма у него хватило только на год с небольшим, и он забросил этот проект. «Знамя подхватил» британец Джереми Коутс (Jeremy Coates), развивал этот движок с 2002 по 2007 год (добавил некоторые удобные возможности, «перековал» под PHP5) и довёл его до версии 0.4.0, которая уже почти восемь лет радует своей незатейливостью и эффективностью.

Вот как выглядит использование класса со стороны php–скрипта:

 require "xtpl.class.php"; 
 $xtpl=new XTemplate ("page.xtpl");
  
 $xtpl->assign("VARIABLE_1", "Тест");

 $varstr = "Привет, мир!";
 $xtpl->assign("VARIABLE_2", $varstr);
 
 $row=array(
  ID=>"38",
  NAME=>"cranx",
  AGE=>"20"
  ); 
 
 $xtpl->assign("VARIABLE_3", $row);
 $xtpl->parse("main.block");

 $xtpl->parse("main"); 
 $xtpl->out("main");

А так — со стороны шаблона (файл page.xtpl):

<!-- BEGIN: main -->
<!DOCTYPE html>
<head>
<title>Заголовок страницы</title>
</head>
<body>
<p>Это пример простейшей подстановки: жирным шрифтом будет выведено "Привет, мир":
 <b>{VARIABLE_1}</b></p>
<p>Или так: <b>{VARIABLE_2}</b></p>

 <!-- BEGIN: block#Так можно добавлять в  блоки комментарии -->
 <table border="1">
  <tr>
   <td>id</td>
   <td>{VARIABLE_3.ID}</td>
  </tr>
  <tr>
   <td>name</td>
   <td>{VARIABLE_3.NAME#Можно комментировать и тэги}</td>
  </tr>
  <tr>
   <td>age</td>
   <td>{VARIABLE_3.AGE}</td>
  </tr>
 </table>
 <!-- END: block -->

<p>Глобальные переменные можно выводить без предварительного присвоения:<br />
$_SERVER['HTTP_HOST']={PHP._SERVER.HTTP_HOST}<br />
$_SERVER['PHP_SELF']={PHP._SERVER.PHP_SELF}<br />
$_SERVER['HTTP_USER_AGENT']={PHP._SERVER.HTTP_USER_AGENT}<br />
и т.п.<br />
(но эти переменные должны быть инициализированы в скрипте до создания объекта $xtpl)</p>
</body>
</html>
<!-- END: main -->

В общем, я процитировал только первый из восьми примеров использования шаблона, и эти восемь примеров, собственно, составляют своеобразную документацию класса (отдельного руководства нет).

Список функциональности пакета содержит также возможность включения других файлов–шаблонов, например:

{FILE "another.template.xtpl"}
{FILE {VAR_FILENAME}}

Имеется также набор приёмов и функций для обработки пустых значений переменных. Впрочем, это довольно экзотическая тема (мне не приходилось на практике использовать эти возможности, хотя они не отличается сложностью).