четверг, 5 февраля 2015 г.

Информатор–оповещатель

Когда я только–только заинтересовался системой сборки, оптимизации, проверки и упаковки разрабатываемого сайта gulp, установил её у себя и начал с ней «играться», мне постоянно попадались примеры, в которых использовался плагин gulp–notify и демонстрировались его возможности по выводу на экран компьютера сообщений о ходе выполнения задач — оповещения об удачном или неудачном завершении, произошедшей ошибке и т.п.

Когда же я принял судьбоносное решение об использовании в качестве базового прототипа сборник задач gulpfile.js из пакета WebStarterKit, там ничего похожего на процедуры дополнительного оповещения не обнаружилось. По здравому размышлению, я пришёл к мысли, что особой острой необходимости в в таких процедурах (например, gulp–notify), вроде бы, нет: «глоток» самостоятельно и интенсивно выводит на экран консоли достаточное количество сведений о процессах, которые происходят при выполнении инициированных задач. Однако, совершенно очевидно, что такое положение дел не в полной мере соответствует представлениям о комфорте работы: разработчик вынужден постоянно наблюдать за экраном, не побоюсь этого слова, таращиться в монитор, при том, что в некоторых случаях работа задачи может растянуться на довольно продолжительное время. Кроме того, если уж взялся автоматизировать процесс разработки, то нужно идти до конца, то есть, упрощать себе, любимому, работу по максимуму, создавая всяческие удобства по тому же самому максимуму.

В общем, я бы тоже охотно и радостно попользовал бы плагин gulp–notify, чтобы просто и незатейливо передать в операционную систему команду, которая выведет на экран нужное мне сообщение. Но в моём случае решение оказалась невозможнім: чтобы использовать функционал gulp–notify с Windows, операционка должна иметь версию не ниже восьмой, то есть, моя Windows XP, а также некоторые другие версии помоложе моей (Vista, Win7) оказываются «лишними на этом празднике жизни».

Надежда забрезжила, когда оказалось, что этот плагин можно «прикрутить» к системе оповещения Growl. Я быстренько установил себе «рычалку» (вольный перевод английского growl), но что–то там не заладилось и скрипты никак не хотели выдавать долгожданные сообщения: то ли я что–то не так настроил, то ли просто они (плагин или Growl) меня невзлюбили (я, действительно, бываю порой неприятным). Недолго думая, решил сменить и плагин, и «рычалку».

Оказалось, что gulp–notify при работе «в тандеме» с Growl использует плагин node-notifier, и я решил «припасть к истокам», то есть, обратиться к первоисточнику. Поскольку мой предыдущий негативный опыт взаимодействия с Growl ещё был свеж в памяти, и горючие слёзы разочарования не высохли на упитанных ланитах, я обратил внимание на возможность вызова с помощью этого плагина всплывающей подсказки из системного лотка, широко известной среди пользователей винды как WindowsBalloon. Для этого, правда, требовалась дополнительная программа notifu — бесплатная утилита из двух не требующих инсталляции файлов (notifu.exe и notifu.pdb для 32–битных систем, notifu64.exe и notifu64.pdb для 64–битных; каждая пара размером около 4,5М).Но, оказалось, что эта утилита поставляется вместе с пакетом node-notifier (потому–то он и «весит» в общей сложности 10М).

Итак, взял я рекомендованный пример и попробовал «проиграть» его на примере задачи JShint (проверка корректности сценария Javascript):

var WindowsBalloon = require('node-notifier').WindowsBalloon;
 
var notifier = new WindowsBalloon();

gulp.task('jshint', function () {
    var proc = gulp.src('js/*.js')
        .pipe($.jshint())
        .pipe($.jshint.reporter('jshint-stylish'));

         notifier.notify({
             title: 'GULP JShint',
             message: 'Выполнение задачи завершено',
             sound: true, // При выводе сообщения подаётся звуковой сигнал
             time: 5000, // Сообщение демонстрируется в течение 5 секунд
             wait: false});

    return proc;
});

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

Вместе с тем, мне когда–то попадался на глаза пример вызова внешней команды (а notifu является именно такой внешней командой), поражающий своей простотой и изяществом: используется вызов стандартного метода дочернего процесса (child_process), изначально встроенного в пакет node.js, то есть, никакие плагины не нужны:

var exec_f = require('child_process').execFile;
exec_f('C:\\Program Files\\Accessories\\notifu', 
  ['/p', 'GULP JShint', '/m', 'Работа сценария завершена', '/i', 'info'], 
  {timeout: 250}
  );

что аналогично вызову команды с аргументами:

> notifu /p 'GULP JShint' /m 'Работа сценария завершена' /i 'info'

У этого способа использования системы оповещения есть несколько особенностей. Во–первых, необходимо обзавестись утилитой notifu (я её загрузил с сайта разработчика и поместил в каталоге C:\Program Files\Accessories). Во–вторых, директива timeout: 250 позволяет прервать этот child_process через 250 мс (продолжительность таймаута должна быть кратной 250): в результате, сообщение в жёлтом «облачке» продолжает «висеть» над системным лотком, а выполнение задачи продолжается практически сразу (ну, что такое 250 миллисекунд!). Похоже, удалось обойти досадный баг с wait в node-notifier.

Итак, приемлемое решение было найдено, осталось уничтожить следы неудачных экспериментов, то есть «снести» node-notifier и Growl, после чего твёрдой поступью зашагать в светлое будущее под знаменем notifu.

«Не введи в искушение, но избавь от лукавого» — гласит основная христианская молитва (кстати, единственная рекомендованная Спасителем). Не получилось: и в искушение ввёл, и от лукавого не избавил. А всё потому, что решил я напоследок попробовать, работает ли node-notifier с growl′ом — просто так попробовать, на всякий случай. Попробовал. Работает.

Получилось гораздо выразительнее, красивее и нагляднее — никакого сравнения с notifu

var Growl = require('node-notifier').Growl;

var notifier = new Growl({
  name: 'Growl @ zaliv.info', 
  host: 'localhost',
  port: 23053
});

gulp.task('jshint', function () {
    var proc = gulp.src('js/*.js')
        .pipe($.jshint())
        .pipe($.jshint.reporter('jshint-stylish'));

         notifier.notify({
             title: 'GULP JShint',
             message: 'Выполнение задачи завершено',
             wait: false});

    return proc;
});

Здесь отказ от ожидания реакции пользователя wait: false (см. строку 17) работает исправно, а продолжительность показа сообщения на экране и куча других свойств регулируются уже в настройках Growl. В общем, моё сердце дрогнуло…

А потом я «встретил» growly и понял, что это — судьба. Я таки удалил node-notifier со всеми его десятью мегабайтами разного мотлоха, включая пять подвязанных к нему плагинов, входящих в его зависимости. Потому, что node-notifier для «общения» с Growl′ом использовал именно growly, а я, как уже заметил мой читатель, стараюсь добраться до первоисточников.

Итак, знакомьтесь: конечная цель моих изысканий — плагин growly.

    var growly = require('growly');
    growly.register('GULP @ zaliv.info'); 

    gulp.task('jshint', function () {  
        var proc = gulp.src('js/*.js')
            .pipe($.jshint())
            .pipe($.jshint.reporter('jshint-stylish'));

        growly.notify('Скрипт выполнен', { title: 'JShint'});
 
        return proc;
});

Можно было бы на этом и остановиться, но я ударился в усовершенствования и украшательства — соорудил три иконки для основных типов сообщений и наваял универсальную функцию для вызова «рычалки»:

var growly = require('growly');

growly.register('GULP @ zaliv.info', 'zaliv.png', [
 {label: 'success', dispname: 'Успешно'},
 {label: 'warning', dispname: 'Предупреждение'},
 {label: 'error', dispname: 'Ошибка'}
]); 

function depesha (header, message, mode) {
 var labels = {
   'i': 'success',
   'w':'warning',
   'e':'error'},
  t = new Date();
  
 growly.notify(message, { 
  title: header + " [" + t.toLocaleTimeString() + "]",
  label: labels[mode],
  icon: 'zaliv-' + mode + '.png'  
  })
};

gulp.task('jshint', function () {  
 gulp.src('js/*.js')
  .pipe($.jshint())
  .pipe($.jshint.reporter('jshint-stylish'));
  
  depesha("JShint", "Задача выполнена", "i");
  depesha("JShint", "Есть незначительные погрешности", "w");    
  depesha("JShint", "Ошибка выполнения", "e");
});

В настройках Growl установил «липкий» (sticky) режим отображения сообщений, то есть, они будут болтаться на экране, пока я их сам не закрою — лучше так, чем пропустить что–нибудь, пока на кухне чайком с зефиркой баловался. Получилась такая картина:

Если будет время, можно ещё «пошаманить» с темами в настройках Growl (настроить свою для каждого типа сообщений в зависимости от метки), но это не к спеху.

воскресенье, 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}}

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

суббота, 6 декабря 2014 г.

Большое средство малой механизации

Да здравствует лень — величайший двигатель прогресса! Именно благодаря лени древний человек изобрёл колесо и приручил лошадь, не менее ленивые представители населения планеты изобрели и компьютеры. Это, так сказать, эпохальные проявления нежелания самостоятельно выполнять монотонную или тяжёлую работу. Есть и более скромные, но не менее полезные результаты «ленивых» изощрений: застёжка–«молния», пылесос, «крутилка» суши–роллов (как на картинке в начале статьи), гель для бритья, джин, поиск и замена в текстовых редакторах… Вот, только, растворимый кофе напрасно изобретали…

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

Меня тоже частенько накрывает плотной мягкой и тёплой волной ленивости: при малейшем удобном случае стремлюсь автоматизировать рутинные повторяющиеся операции и сформировать максимально комфортную среду для работы. В этой статье речь пойдёт о «малой механизации» в работе с таблицами стилей (CSS) и сценариями–скриптами (JS и jQuery). И выбор пал на систему сборки, оптимизации, проверки и упаковки всего перечисленного добра (и не только!) под игривым названием «Хрюк» (по–английски Grunt) — согласитесь, мечта лентяя (и в смысле функциональности, и, некоторой степени, в смысле названия).

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

Почти сразу образовалась альтернатива «злобному хрюку»: аналогичный пакет и даже с немного похожим английским названием — Gulp. Не то, чтобы я испугался свирепой кабаньей хари, но гораздо ближе по духу оказался «глоток» (по–английски gulp): и с кофе удачно ассоциируется (см. логотип справа), и поновее «хрюка», и те же функции реализованы на более прогрессивной концепции.

Также, как и в случае использования «хрюка», установка «глотка» начинается с установки Node.js — платформы, использующей V8 (движок Google Chrome, исполняющий сценарии Javascript) для запуска скриптов вне браузера. Ничего особенного в процессе установки пакета в Windows нет — запускаешь node-v0.10.33-x86.msi и отвечаешь на типовые вопросы, возникающие при инсталляции любой программы.

Следующий шаг — установка собственно Gulp, и для этого (а также последующей установки gulp–плагинов) используется встроенный в Node.js менеджер пакетов — npm (Node Package Manager). Сначала «гульп» устанавливается глобально. Для этого нужно перейти в каталог проекта, то есть, в папку, в которой будут размещены все ресурсы, из которых Gulp будет «собирать» компоненты для сайта и создать там файл package.json при помощи команды init, ответив на пошаговые вопросы. Если вдруг возникнет чувство неудовлетворённости простотой решения, файл package.json можно сварганить «руками» с использованием текстового редактора.

npm init
npm install --global gulp

Затем этот же пакет нужно установить локально — не спрашивайте, зачем нужна эта двойная инсталляция:

npm install --save-dev gulp

После этого в папке проекта устанавливаются все необходимые для полного счастья gulp–плагины:

npm install --save-dev <имя_плагина>

Я собрал для себя такую «коллекцию»:

  • beepbeep — включение системного звука (аргументы задают количество и продолжительность сигналов);
  • del — удаление файлов;
  • glob — выбор файлов по шаблону (например, *.js);
  • gulp-autoprefixer — добавление префиксов для адаптации CSS–файлов для использования с браузерами, поддерживающими собственный синтаксис (аналогично тому, как это делает Compass);
  • gulp-browserify — сборка исходных файлов со скриптами в один js–файл с контролем корректности синтаксиса языка программирования;
  • gulp-concat — «склеивание» исходных файлов в единый файл;
  • gulp-filesize — определение размера файла;
  • gulp-imagemin — минимизация файла изображения JPG, PNG. GIF и SVG;
  • gulp-livereload — обновление страницы в браузере;
  • gulp-minify-html — мнимизация HTML–файлов;
  • gulp-notify — вывод сообщения;
  • gulp-plumber — предотвращение прерывания потока (pipe) при возникновении ошибки;
  • gulp-rename — переименование файлов;
  • gulp-sass — преобразование SASS/SCSS–файлов в CSS («конкурент» фреймворка Compass, уже развёрнутого на моём компьютере);
  • gulp-sourcemaps — формирование «карт» объединённых файлов для возможности последующей отладки;
  • gulp-uglify — минимизация js–файлов;
  • gulp-uncss — удаление из CSS–файла стилей, не используемых в проекте;
  • gulp-util — вспомогательные функции (вывод сообщения, обработка ошибок, замена расширения файлов и т.п.);

Должен заметить, что некоторые плагины у меня не инсталлировались из виртуальной машины (я использую VMWare Player 6.0.1 build-1379776): попытки установить gulp-uncss, gulp-sass и некоторых других пакетов появлялись «ругательные» сообщения такого вида:

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

Что касается формирования файла заданий gulpfile.js, который управляет работой Гульпа, то я нахожусь в самом начале пути, поэтому не буду изображать из себя гуру, копируя многочисленные рекомендации и примеры, которые сам нашёл в Сети. Но готов делится с громадой всеми удачными и ошибочными достижениями в этой области — следите за рекламой!

А начать решил с настройки автообновления страницы сайта: при изменение какого–либо из «контролируемых» файлов, состояние страницы в браузере должно немедленно и без дополнительной команды, то есть, самостоятельно обновляться. Для этой цели существует плагин gulp-livereload, но он, похоже, должен работать в тандеме с мини–сервером, предоставляемым другим плагином. Я пытался разобраться в этой спарке, но с налёта у меня не получилось, а долго ломать голову желания не возникло. Поэтому очень кстати оказалось одноимённое расширение к моему браузеру (Mozilla Firefox 34.0). Там же, такое же «удовольствие» имеется и для Google Chrome, и для Safari. Есть такое же расширение и для IE, но придётся разбираться с его установкой, потому что, например, на официальном «мозиловском» сайте предлагается расширение старой версии (и неизвестно, какая версия потребуется для IE).

// Файл gulpfile.js
var gulp = require('gulp'),
    refresh = require('gulp-livereload');

gulp.task('monitor', function(){
  refresh.listen();
  gulp.watch('css/*.css', ['css'])
      .on('change', refresh.changed);
})

Этим скриптом запускается встроенный в gulp-livereload сервер, а встроенная в gulp утилита наблюдения за изменениями файлов (gulp.watch) начинает следить за этими самыми изменениями.

С практической точки зрения, сначала запускается из командной строки задача слежения:

> gulp monitor

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

P.S. Менее, чем через месяц предложенный список gulp–плагинов претерпел существенные изменения.

четверг, 4 декабря 2014 г.

Рубиновый механизм

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

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

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

В общем, Япония так и продолжает оставаться «вещью в себе».

К чему этот географически–исторический экскурс? Дело в том, что в конце предыдущего века, в 1995 году, японский разработчик программного обеспечения опубликовал созданный им язык программирования Ruby, призванный, по замыслу автора, устранить недостатки Perl'а при помощи использования сильных сторон нескольких языков программирования. Свой, более «крепкий» язык Ю.Мацумото назвал «Рубином» (именно так переводится с английского слово ruby), очевидно в противовес «Жемчугу» (английское слово perl читается точно так же, как и pearl — жемчуг). То есть, с намёком на несравненно бо́льшую ценность.

Не исключено, что новый «рубиновый» язык изначально тоже предназначался для «внутреннего потребления» — его описание на английском языке появилось только спустя два года. Но с 1997 года начинается распространение Ruby по планете: был отмечен некоторый начальный всплеск интереса, но невероятной популярности, соответствующей «драгоценному» названию, он не приобрёл, хотя и занял свою нишу рядом с PHP, Python, Java и уже упоминавшимся Perl.

Пока в мои планы не входит переводить свой сайт «Заливная рыба» на Ruby — меня вполне устраивает старый добрый PHP, как бы ни исходили ненавистью к этому языку злопыхатели, — но эта статья возникла по другой необходимости: очень уж мне приглянулась система SASS/SCSS, а реализована она именно на Ruby.

Беглое ознакомление со «стилистически классными таблицами стилей» — так переводится с английского название системы, образующей аббревиатуру SASS — повергло меня в печаль великую: как же я раньше жил без этого «рубинового» механизма? Как можно по–старому верстать сайт, если в CSS–файла можно, оказывается, использовать переменные, вложенность, наследования, функции, подмешивания!

Я ни в коем случае не собираюсь разворачивать на страницах своего блога курсы работы с Ruby или SASS/SCSS: я сам только начинаю осваивать новые возможности по созданию таблиц стилей, а до изучения «Рубина» дело вообще может не дойти. В любом случае, в Сети есть прорва ресурсов, способных рассказать, показать, научить и первому, и второму. А также, третьему и четвёртому: эти самые «третий» и «четвёртый» — фреймворк Compass и система Scout — очень кстати обнаружились в процессе пятидневного разбирательства в ситуации (начитался я до одури всяких публикаций и про «рубин» и «рубинозависимые» приложения, а потом ещё дня три отходил от обилия информации и переваривал её).

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

Ещё более полезным оказался пакет Scout (мне досталась версия 0.7.1 для Windows) «3–in–1», как дерзко и цинично претендующая на звание кофе бурда MacCoffee. Вернее, я получил даже «четыре в одном»: и Ruby, и SASS/SCSS, и Compass и графическая оболочка (честно говоря, GUI можно назвать таковым весьма условно). Более того, всё моё новое достояние даже отдалённо не напоминает MacCoffee.

Установка пакета не занимает много времени и, в принципе, не может составлять какой–либо трудности: запускаешь ScoutAppInstaller-0.7.1.exe и отвечаешь на вопросы оконных диалогов (в какую папку ставить, куда выкладывать иконки и т.п.). В конечном итоге, пользователь получает возможность лицезреть серенькое окошко с заголовком «Scout» в левом верхнем углу и кнопкой со значком «+» в левом нижнем углу (см. скриншот внизу слева). Поскольку никаких иных элементов не наблюдается, шаловливые ручонки, практически без вмешательства головного и спинного мозгов нажимают кнопочку с плюсиком, что приводит к появлению диалога для выбора каталога, в котором размещён проект (см. скриншот справа внизу).

Искушённый читатель, наверное, уже догадался, что мой проект, базирующийся на домене «zaliv.info», располагается в папке с неожиданным именем Zaliv. После этого «Скауту» явно полегчало: он начал деловито собирать сведения о месте, где будут скрываться исходные SCSS–файлы (Input Folder) и куда потом нужно будет складывать результаты обработки «сырья», прошедшего горнило Compass и SASS (Output Folder — оба поля находятся в разделе Stylesheet Directories, см. скриншот внизу). Можно было указать и «Другие каталоги» (Other Directories), то есть, адреса папок, в которых расположены скрипты (Javascripts Folder), изображения (Imagess Folder), — говорят, что Scout с Compass'ом умеют «паковать» не только CSS, — но у меня насчёт всего остального (скрипты, изображения, страницы) были другие планы. Что касается файла конфигурации (Config File), то речь идёт, скорее всего, о тонких настройках работы системы: можно поиграться с различными параметрами, уходящими своими корнями в «рубиновый механизм», но я отложил эти эксперименты «на потом» (а может и «на никогда»).

Есть ещё два блока настроек: один связан с режимом вывода (Output Mode), а второй — с управлнием проектом (Manage Project). Сразу необходимо отметить, что управление проектом в Скауте оформлено очень незатейливо и сводится к его (проекта) удалению: рядом с лейбой «Удалить проект» (Remove Project) располагается кнопка удаления Remove. А вот режимы вывода предлагают выбор: то ли разработчик находится в процессе разработки (Environment:Devolopment в выпадающем списке), то ли формирует окончательный продукт для публикации (Environment:Production), то ли выходные файлы нужны во вложенном виде (Output Style::Nested), то ли развёрнутом (Output Style::Expanded), то ли компактном (Output Style::Compact), то ли сжатом (Output Style::Compressed). Вообще–то, разбираться в некоторых аспектах Скаута довольно непросто: пакет, практически недокументирован и пребывает в непонятном состоянии — ни альфа, ни бета, не говоря уже о пре-релизе. Да, и документация Компаса, хоть и подробна, но коряво организована, то есть, оставляет желать лучшего.

По некоторым косвенным данным можно предположить, что режим конечного продукта (Environment:Production) проводит какие–то более глубокие, трудоёмкие и длительные операции с исходными файлами. Режимы упаковки и сжатия (Output Style::Compact и Output Style::Compressed) удаляют из конечных файлов ненужности и красивости (например, комментарии, форматирующие пробелы и табуляции), что обеспечивает уменьшение размера CSS–файла и, соответственно, время на его загрузку.

«Шаловливые ручонки, нет покоя мне от вас!» Ну, как же утерпеть от проверки работоспособности установленной софтины?! Конечно же, наваял я простенький SCSS–файлик в своём прекрасном Блокноте и сохранил его в папку исходников (Input Folder) как test.scss:

@import "compass/css3"; 
@import "compass/support";

$color : green; 

.panella {
 background-color: $color;
 @include border-radius(25px);
}

Затем я запустил режим обработки SCSS–файла (при помощи кнопки Play в слоте моего проекта на левой панели). Как нетрудно заметить, графическая оболочка в этом месте «сдулась» и на глазах у изумлённой публики появилось традиционное окно для отображения командной строки (вот что я имел ввиду когда писа́л об «условном GUI»). При этом кнопка Play превратилась в кнопку Stop, то есть, Scout заступил на дежурство по наблюдению за изменениями в папке исходящих файлов, а на консоль выведено сообщение о замеченном изменении файла test.scss и его компиляции в файл test.css (на скриншоте внизу — верхние две строчки белым шрифтом на чёрном фоне). Любые попытки внести изменения в файл test.scss (например, удаление пробела) после его пересохранения немедленно обрабатывались системой с перезаписью файла test.css.

А вот так выглядит содержимое файла test.css:

/* line 6, scss/test.scss */
.panella {
  background-color: green;
  -webkit-border-radius: 25px;
  -moz-border-radius: 25px;
  -ms-border-radius: 25px;
  -o-border-radius: 25px;
  border-radius: 25px;
}

Как говорится, насладитесь результатом.

По ходу дела вскочила ещё одна заковыка: любовно настроенный под мои предпочтения Notepad++ взял за моду грубо «ругаться» при каждом сохранении SCSS–файла. Дело в том, что предвкушая дружную и слаженную работу с SASS/SCSS я добавил в плагин jN скрипт Sass-Auto-Compile.js, призванный дело то же самое, что и Scout (тогда ещё Скаут даже не маячил на горизонте). Оказалось, что скрипту для правильной работы необходимо знать путь к интерпретатору Ruby, а в установленном пакете Scout интерпретатор не обнаружен. Перемещение проблемного скрипта в папку disabled проблему ликвидировало (Блокно перестал выбрасывать возмущённые сообщения), но «неприятный осадок остался»: что же я такое установил?

Внимательное исследование лога установки пакета Scout показало, что дополнительно была установлена только среда выполнения Adoba AIR, а вместо Ruby был установлен его Java–клон jruby-complete.jar, и при запуске Scout система вызывает интерпретатор Java.

суббота, 29 ноября 2014 г.

Блокнот·два·плюса — форэва!

Ведь клялся же себе, что буду придерживаться умеренности, но опять сорвался: стремление к обновлению не имеет границ и с этим стремлением, можно даже сказать, страстью нужно поступать как с ремонтом в квартире — «закончить нельзя — можно только прекратить». Хорошо, что в этот раз удалось отделаться «малой кровью».

Как–то незаметно мои усилия по реорганизации инфраструктуры для разработки сайта (вернее, его переделки) во второй раз посягнули на святая святых разработчика — его редактор кодов. Напомню невнимательному читателю моего дневника, что однажды я уже перешёл с Homesite на Notepad++, а тут ещё раз шайтан взялся меня попутать — подсунул чудо современной программерско–компьютерной мысли, редактор Sublime Text. Грешен: повёлся! Ну, кто, скажите на милость, в здравом уме и при твёрдой памяти откажется от чуда чудного и дива дивного?

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

В конечном итоге, результаты заочного знакомства с новым редактором выглядели весьма оптимистично и привлекательно: и работает он шустрее, и интерфейс приятнее, и всяких приблуд для него видимо–невидимо… Весьма убедительны были традиционные пользователи Notepad++, которые стройными рядами, практически в едином порыве, с пламенным взором и песня́ми переходили под новые знамёна. Несколько настораживали встречавшиеся в Сети рекомендации о том, как изменить этот прекрасный редактор, чтобы он был похож на Notepad++.

И сегодня я, наконец–то, созрел: решил установить и попробовать — уж слишком много было хвалебных отзывов и практически отсутствовали весомые аргументы против (самым весомым являлась бесплатность Блокнота против «условнобесплатности» Сублима). Итак, установил, попробовал и …снёс, то есть, удалил. Фуфло!

Вообще–то, на этом можно было бы статью и закончить, но я решил, всё–таки, аргументировать свою позицию. Для начала повторю уже упоминавшийся аргумент: NPP (Notepad++) бесплатен, а ST (Sublime Text) пока условно бесплатен (лицензия стоит $70) — ключевой слово в этой фразе «пока», потому что никто не знает, когда разработчик включит обязательность приобретения лицензии, то есть, у пользователя возникнет необходимость поиска «таблэтки».

Кроссплатформенность ST, которую его апологеты выдвигают в качестве основного и весьма существенного преимущества, для меня неактуальна, а вот богатый инструментарий NPP для работы с различными кодировками кириллицы — весьма и весьма ценная фича. В ST я вообще не нашёл управления кодировками: наверное, потому, что редактор заточен под англоязычного пользователя, которому совершенно незачем заморачиваться со всякими там KOI–CP1251 и их многочисленными братьями–сёстрами. Я уж не говорю о том, что интерфейс редактора исключительно английский, и хотя у меня не возникает в этой связи языковой проблемы, русскоязычный NPP сердцу милее.

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

Правильно настроенный NPP может творить чудеса: макросы, расширения (один только Emmet, a.k.a ZenCoding чего стоит), с подсветкой синтаксиса, перекодировкой. Я, кстати, добавил «раскраску» синтаксиса для SCSS, HTML5 и CSS3, а также скрипт для компиляции SCSS в CSS прямо из NPP (без плагина jN скрипт не работает). Я уж не говорю о разнообразных «стандартных» плагинах (тех, которые устанавливаются через Plugin Manager), щедрой рукой добавляющих Блокноту·два·плюса разнообразные полезности и «вкусности»

В общем, снова здравствуй, Блокнот! Я вернулся.

понедельник, 17 ноября 2014 г.

Исправление весенней ошибки

Авторство в создании концепции «отвечающего» веб–дизайна (responsive web design, RWD) приписывается американскому дизайнеру из Бостона Итану Маркотту, хотя за шесть лет до опубликования его статьи на эту тему, другой дизайнер–разработчик, Камерон Адамс, выдвинул общую идею динамической адаптации представления веб–сайта на различных устройствах: смартфонах, планшетах, ноутбуках и офисных компьютерах.

Как бы там ни было, но выявление «первородства», а также дальнейших перипетий развития и совершенствования теории и практики адаптивного дизайна — именно так эта техника называется в русскоязычной литературе — имеет схоластическое значение: гораздо важнее вопросы практической имплиментации. Тем более, что некоторые веб–изощренцы, доходя порой даже до стадии извращенцев, находят принципиальный и непримиримые различия между понятиями адаптивный дизайн, адаптивная разметка, отзывчивый дизайн и всеми остальными производными от этих понятий. Жуть и жесть!

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

Другими словами, решил сделать «работу над ошибками». В качестве резинки–ластика для стирания этих ошибок и карандаша, способного красивым почерком вписать в историю моего сайта правильные современные «слова», связав их в логически верные «предложения», которые, в конечном итоге, сложатся в интересный, увлекательный «роман» призван вызвать набор CSS/Javascript Bootstrap, недавно приобретённый вместе с пакетом HTML5 Bootstrap.

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

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

Для устройств с несколько бо́льшим разрешением (больше 768, но меньше 992 пикселей) — раскладка с двумя колонками для контента и дополнительной информации, «обрамлёнными» сверху и снизу блоками меню и вспомогательной информации (рисунок слева внизу). А для больших и очень больших разрешений — всего, что больше 992 пикселей в ширину, — ранее описанное трёхколоночное представление (для наглядности я повторил этот рисунок справа внизу).

Наверное, можно было бы всё это многообразие макетов реализовать и через таблицы (как мечталось в далёком апреле), но инструментарий пакета Bootstrap позволяет не только преодолеть возможную «головную боль» с дизайном, но и полностью её предотвращает. Спрашивается, зачем ломиться «скрозь» лес, ломая рогами ветки и треща валежником, если можно спокойно прогуляться по аллейке с рюмкой кофе в руках, наблюдая красоты окружающей природы? Я, например, выбрал «прогулку».

Речь идёт о наборе из четырёх типов классов, которые соответствуют четырём диапазонам разрешений экрана:

  • .col-xs- (eXtra Small) — колонка (столбец) для самого малого разрешения (меньше 768px);
  • .col-sm- (SMmall) — колонка для малого разрешения (от 768 до 992px в ширину);
  • .col-md- (MeDium) — колонка для среднего разрешения (между 992 и 1200px);
  • .col-lg- (LarGe) — колонка для большого разрешения (больше 1200px).

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

Для удобства дизайнера, всё пространство, на котором будет расположено содержимое веб–страницы с заголовками, меню, подвалом и дополнительными блоками — в общем, всё — разбивается по ширине на двенадцать вертикальных полос. Можно, конечно, разделить пространство на большее или меньшее количество полос, но именно двенадцать включено по умолчанию в пакете Bootstrap, и я не нашёл причины, по которой необходимо изменять их количество для моего сайта. На схеме внизу представлены три макета (для трёх разрешений), наложенный на двенадцатиполосную сетку.

А теперь, прочувствуйте простоту и удобство вёрстки страницы с помощью сетки и Bootstrap: для самого маленького разрешения, которому соответствует группа классов .col-xs-, блок меню–навигации (жёлто–оранжевого цвета) будет «награждён» классом .col-xs-4 («простирается» на четыре полосы сетки), блок основного контента (зелёного цвета) и вспомогательной информации (лилового цвета) — .col-xs-12 (ширина всех 12 полос), а второй блок дополнительной информации — .col-xs-4.

Макет для планшетов и нетбуков (если такие ещё существуют) строка меню и левый блок дополнительной информации наделяются классом .col-sm-12 (занимают всю ширину экрана), блок основного контента — .col-sm-8 и правый блок вспомогательной информации — .col-sm-6.

По такому же принципу, — решительно и деловито, — назначаются классы для среднего разрешения: .col-md-6 — для блока основного контента и .col-md-3 — для всех остальных. Группу классов .col-lg- решил вообще не трогать: с экранами больших разрешений успешно справится «средняя» группа (.col-md-).

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

Первый порыв применения Bootstrap на практике, можно сказать, «проба пера» вылилась в такую конструкцию (интересно, как она себя поведёт в жизни, то есть, на сайте?):

<div class="container"> 
 <div class="row"> 
  <div class="col-sm-12 col-md-3 hidden-xs">
   <!-- на смартфонах меню спрятано и вызывается принудительно, по нажатию пиктограммы (механизм вызова меню здесь не рассматривается) -->
   <h2>Меню</h2>
   <p>(жёлто-оранжевый блок)</p>
   <div class="hidden-sm">
    <!-- ... а блок дополнительной информации отображается в другом месте и на смартфонах, и на планшетах (см. ниже) -->
    <h2>Доп.информация левой колонки</h2>
    <p>(лиловый блок)</p>
   </div>
  </div>
  <div class="col-xs-12 col-sm-8 col-md-6">
   <h2>Контент</h2>
   <p>(зелёный блок)</p>
  </div>
  <div class="col-xs-4 col-sm-4 col-md-3 hidden-xs">
   <!-- на смартфонах правая колонка спрятана и вызывается принудительно, по нажатию пиктограммы (механизм вызова блока здесь не рассматривается) -->
   <h2>Правая колонка</h2>
   <p>(синий блок)</p>
  </div>
 </div>
 <div class="row"> 
  <div class="col-xs-12 hidden-md hidden-lg">
   <!-- дополнительная информация из левой колонки на смартфонах и планшетах выводится под блоком с основным содержанием -->
   <h2>Доп.информация левой колонки</h2>
   <p>(лиловый блок)</p>
  </div>
 </div>
</div>

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

суббота, 15 ноября 2014 г.

Не изобретая велосипед…

Обновлять, так обновлять! Следуя этому девизу ещё семь месяцев тому назад я решили максимально кардинально подойти к модернизации сайта. Именно по этой причине совершались «шаманские пляски» вокруг базы данных по весне, а сейчас настала пора принципиально–кардинальных изменений всей веб–среды моего сайта.

Поскольку негоже «в наш век прогресса и прогрессивки» продолжать передвигаться на конной тяге, предстоит мне перебираться со старого доброго

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
на новый, но, похоже, тоже добрый
<!DOCTYPE html>
то есть, вливаться в стройные ряды приверженцев наиболее современного стандарта разметки html5.

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

Как всегда, мир оказался не без добрых людей, и эти самые добрые люди собрали воедино несколько независимых техник и подходов, которые позволяют разработчику не задумываться над проблемой совместимости. То есть, я создаю сайт по стандарту html5, а упомянутая разработка добрых людей гарантированно обеспечивает правильное отображение этого сайта в любом (ну, практически любом) браузере — даже старом, выпущенном до принятия html5, даже новом, но с коряво реализованной поддержкой нового стандарта.

Имя этой волшебной «приблуды» — HTML5 Boilerplate (переводится, примерно, как «заготовка для HTML5», но я бы назвал её «HTML5–костыли» — точнее отражает суть пакета). На момент публикации статьи доступна версия 4.3.0 и именно к её разворачиванию и приступаю. До этого я пару дней потратил на изучение предыстории возникновения и совершенствования набора, но для практического использования эта информация ценности не представляет, а наиболее любознательные могут воспользоваться поисковыми системами, чтобы повторить мои изыскания.

Гораздо более важным, опять–таки, с практической точки зрения, является наличие ресурса, который позволяет в интерактивном режиме скомплектовать нужный разработчику набор утилит.

При входе на упомянутый ресурс, вы получаете возможность псевдовыбора: то ли вы возьмёте классический набор HTML5Boilerplate (серая кнопка), то ли классический пакет с довеском из html–шаблона, сработанного на принципе «отзывчивого» веб–дизайна (красная кнопка), то ли стандартный пакет с твиттеровским набором Bootstrap для создания собственных «отзывчивых» шаблонов (синяя кнопка).

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

В первой колонке (HTML/CSS Template), собственно, и выбирается вариант, обозначенный тремя кнопками предварительной конфигурации (предыдущее изображение): классический пакет (только HTML5 Boilerplate), классический пакет с готовым «отзывчивым» шаблоном (Mobile-first Responsive) и классический пакет с набором Bootstrap (Twitter Bootstrap).

Вторая колонка (HTML5 Polyfills) позволяет выбрать между компонентами HTML5Shiv (исправляет ошибки реализации HTML5 в Internet Explorer) и Modernizr (CSS и JS расширенной функциональности, включая возможность HTML5Shiv). Третья позиция колонки может включить в общий пакет скрипт response.js, который позволяет решить проблемы старых мобильных устройств, не поддерживающих медийные запросы в CSS (Media Queries). Впрочем использование этого скрипта имеет некоторые скрытые недостатки, но альтернативой является

В третьей колонке можно выбрать вариант библиотеки jQuery — сжатый (Minified) и/или полный (Development). Традиционно рекомендуется использовать последнюю версию jQuery из сетевого репозитория, и эта рекомендация реализована разработчиками HTML5 Boilerplate, но, тем не менее, в пакет включается скрипт с библиотекой, главным образом, на случай каких–либо проблем с доступом к сетевому репозитарию. Вместе с тем, в другом разделе документации рекомендуется использовать только локальную копию: дескать, прилагаемая версия не вызывает конфликтов со скриптами (неизвестно, как поведёт себя более новая версия) и в ней предусмотрено более длительное кэширование.

Последний раздел — «подвал» формы тонких настроек, H5BP Optional — содержит несколько очевидных, не очень очевидных и, на неподготовленный взгляд, совершенно неочевидные дополнения: часть из них включены несколькими строками в базовый шаблон (как, например, классы для IE или блок для Google Analytics), а другие — в виде дополнительных файлов (например, plugins.js, robots.txt или .htaccess).

Для себя я выбрал такой пакет:

  • из опций «HTML/CSS Template» — набор стилей Bootstrap (тесноваты оказались для меня границы одного шаблона Mobile–first);
  • из вариантов «HTML5 Polyfills» — скрипты Modernizr и Respond;
  • «упакованный» вариант jQuery;
  • и всё из «H5BP Optional» (потом буду разбираться, что там лишнее).

После разархивирования полученного файла образовалась структура каталогов со скриптами, стилями и разными другими файлами, включая index.html, содержание которого приведено ниже (с моими тремя малюсенькими правками):

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link rel="stylesheet" href="css/bootstrap.min.css">
        <style>
            body {
                padding-top: 50px;
                padding-bottom: 20px;
            }
        </style>
        <link rel="stylesheet" href="css/main.css">

        <script src="js/vendor/modernizr-2.6.2-respond-1.1.0.min.js"></script>
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="browsehappy">Вы используете <strong>устаревший</strong> браузер. Пожалуйста, <a href="http://browsehappy.com/" rel="nofollow noindex">обновите свой браузер</a> чтобы улучшить отображение страниц.</p>
        <![endif]-->
        
        

        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.1.min.js"><\/script>')</script>

        <script src="js/vendor/bootstrap.min.js"></script>

        <script src="js/plugins.js"></script>
        <script src="js/main.js"></script>

        <!-- Google Analytics: замените UA-XXXXX-X на свой идентификатор сайта. -->
        <script>
            (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
            function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
            e=o.createElement(i);r=o.getElementsByTagName(i)[0];
            e.src='//www.google-analytics.com/analytics.js';
            r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
            ga('create','UA-XXXXX-X');ga('send','pageview');
        </script>
    </body>
</html>

Вот, отсюда теперь и предстоит плясать–танцевать.

пятница, 18 апреля 2014 г.

Переключение кодировки

Решил я, что пришло время изменить кодировку страниц своего сайта «Заливная рыба», по крайней мере, начать эту работу. Хорошо бы, конечно, для таких случаем иметь Большую Красную Кнопку — голубую мечту Доктора Кто. Написа́л предыдущее предложение, прочитал его и осознал двусмысленность: то ли мечта Доктора голубая из–за её несбыточности, то ли вследствие изрядной (хотя не вполне явной) «голубизны» самого Доктора. Осторожнее нужно быть с эпитетами…

В общем, кнопки нет и в обозримом будущем не предвидится, а процесс перевода предыдущей версии сайта из кодировки CP-1251 в более прогрессивную UTF-8 нужно начинать. Первым делом, взялся за базу данных: в ней уже накоплено сведения о 80 давно подготовленных статьях и таблицы словарей (теги, категории, рубрикаторы). Сначала, с помощью встроенной в панель управления моего хостинг–провайдера утилиты phpMyAdmin скопировал всё содержимое базы данных MySQL к себе на компьютер в один файл («экспорт» называется). Затем вычистил БД, то есть удалил все таблицы вместе с содержимым, после чего поменял кодировку базу на вожделенную utf8-general_ci.

Потом нужно было собственно перекодировать данные: ведь из базы данных они выгрузились на мой жёсткий диск в кодировке cp1251.

Долгое время я пользовался старым добрым Macromedia Homesite+ версии 5.5 — старичок натужно пыхтел, жрал немилосердно внушительные объёмы ресурсов, гадёныш, но привык я к нему (всё–таки 10 лет вместе!), несмотря на некоторые неудобства. Буквально месяц тому назад я вынужден был с ним «распрощаться навеки»: взялся я ваять новый сайт, непременно в кодировке UTF-8, а мой «старикашка» ни сном, ни духом не знает что это такое.

Пришлось искать альтернативу, и она нашлась довольно быстро — Notepad++. Редактор простой, мощный и, что немаловажно, бесплатный (мой старый Homesite без таблэтки работать отказывался). А главное — понимает любые кодировки и, будучи дополнительно укреплён–усилен плагинами (я установил Emmet, QuickText и некоторые другие) оказался не менее функциональным и исполнительным, чем привычная софтина.

В общем, открыл я в NPP (Notepad++) файл экспорта из БД и запустил перекодировку в «UTF-8 без BOM» — секунда дела! Перед тем, как сохранить перекодированный файл пришлось порихтовать свойства таблиц: вместо

) ENGINE=MyISAM AUTO_INCREMENT=148 DEFAULT CHARSET=cp1251;

прописать

) ENGINE=MyISAM AUTO_INCREMENT=148 DEFAULT CHARSET=utf8;

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

После этого всё стало гораздо хуже: к неудачному дизайну добавились совершенно нечитаемые «крокозяблы» (Дальний Восток и весь запад их называют моджибакой: mojibake) на всей поверхности страницы — простые вопросительные знаки (мол, что за хрень творится?!) и вопросительные знаки в чёрных ромбиках (навевают какие–то тревожные и угрюмые ассоциации).

Перекодировка всё в том же NPP файлов шаблонов и скриптов, а также замена кодировки страниц с


на


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

Тогда решил посмотреть, что вообще творится с переменными MySQL. Запустил запрос, получил ответ:

SHOW VARIABLES LIKE 'character_set%'
имя переменной значение
character_set_client utf8mb4
character_set_connection utf8mb4
character_set_database utf8
character_set_filesystem binary
character_set_results utf8mb4
character_set_server latin1
character_set_system utf8
character_sets_dir /usr/share/mysql/charsets/

Оказалось, что кодировка utf8mb4 введена в MySQL начиная с версии 5.5.3 (в начале 2010 года) из–за того, что ранние версии MySQL могли сохранять только 5,88% символов Юникода, в то время как UTF–8 (Unicode Transformation Format, 8-bit — «формат преобразования Юникода, 8-битный») в состоянии отображать все 100%. Проблема в том, что UTF–8 использует для кодировки символов от 1 до 6 байтов (это теоретически, на практике же — от 1 до 4), а MySQL умела сохранять только трёхбайтовый UTF–8.

Стало быть, нужно ещё раз базу данных «перековать» в новую диковинку — utf8mb4. Только, вот какая штука: кодировка windows–1251 однобайтовая, а utf–8 — двухбайтова (для кириллицы, иврита, арабского, греческого, армянского, коптского алфавитов и таких экзотов, как тана, использующегося на Мальдивах и нко — в Гвинее и Мали; кстати, для грузинского алфавита требуется трёхбайтный код, как и для китайского, японского, корейского, индийского). Это значит, что для строки из 100 символов потребуется 100 байт в кодировке cp–1251 и 200 (а то и 300) в кодировке UTF–8.

Дальше — больше (в самом прямом смысле): utf8mb4 использует для хранения каждого символа 4 байта, то есть, для ставшего уже милым для нашего сердца примера с сотней кириллических буковок потребуется 400 байт. Поэтому, простой заменой кодировки тут не отделаешься — придётся ещё и увеличивать размер строковых и текстовых полей в таблицах.

В конечном итоге, получилось так (сравните первый вариант, от windows–1251 и второй, для utf–8 с добавкой от MySQL для одной из таблиц базы данных)

CREATE TABLE `vocabular` (
  `sysn` int(11) unsigned NOT NULL auto_increment,
  `ref` int(11) NOT NULL,
  `defen` varchar(100) NOT NULL,
  `lang` enum('en','ru','la') NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `voc_1` (`ref`,`defen`)
) ENGINE=MyISAM AUTO_INCREMENT=521 DEFAULT CHARSET=cp1251;
ALTER DATABASE `zalivryba` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

SET NAMES 'utf8mb4';

CREATE TABLE `vocabular` (
  `sysn` int(11) unsigned NOT NULL auto_increment,
  `ref` int(11) NOT NULL,
  `defen` varchar(400)  CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `lang` enum('en','ru','la') NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `voc_1` (`ref`,`defen`(235))
) ENGINE=MyISAM AUTO_INCREMENT=521 DEFAULT DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Таким образом:

  • изменена кодировка всей БД, каждой из таблиц и каждого строкового поля (VARCHAR и TEXT) в таблицах;
  • увеличен в 4 раза размер каждого строкового поля;
  • установлены ограничения на размеры некоторых индексов — поскольку размер индекса не может быть более 1000 байт, то для поля, например, `defen` остаётся не более 989 байт (размер `ref` составляет 11 знаков), а это значит, что индексировать можно только первые 989:4 = 247 символов–знаков (ну, и хватит!)

Потом, как советуют бывалые люди, запустил восстановление (REPAIR) и оптимизацию (OPTIMIZE) всех таблиц, — быстро, из панели управления — и, дрожа от нетерпения, бросился смотреть на результат, а там… Ничего не изменилось: на экране была всё та же печальная моджибяковщина…

Очередная проверка переменных среды нарисовала странную картину:

За разъяснениями пришлось обращаться в службу поддержки хостинг–провайдера. Очень вежливые и обходительные специалисты настойчиво втолковывали мне, что они изменить ничего не могут, поскольку серверные установки могут повлиять на сайты всех остальных клиентов — хостинг–то sharing. В общем, ситуация сложилась тупиковая: впору опять всё возвращать в прежнюю кодировку windows–1251 и плакать по ночам от несбывшейся мечты про UTF–8 — не помогла даже очень хорошая статья толкового программера (то, что он является одним из авторов HTML5 Boilerplate, говорит само за себя).

Но решение нашлось, когда я бросил уже прощальный взгляд на мануал MySQL: там, в разделе «10.1.5 Configuring the Character Set and Collation for Applications»:

Приложениям, использующим базу данных, следует конфигурировать свои соединения с сервером при каждом подключении. Это можно сделать путём исполнения запроса SET NAMES 'utf8' после соединения. Этот запрос может использоваться независимо от способа подключения.

Решил напоследок попробовать ещё и этот вариант (а что я теряю?!), запустил в своём PHP–скрипте такую команду:

$db = DbSimple_Generic::connect("mysql://$user:$password@localhost/$name");
$db->query("SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'");

В первой строке кода — подключение к базе данных (я давно использую очень удобную библиотеку Дмитрия Котерова), а во второй — его настройка на utf8mb4 (перешибаются установки сервера character_set_server, collation_connection, collation_server и, наверное, многое другое). После этого всё… заработало!

Всё остальное вообще оказалось детской задачкой: изменил кодировки в заголовках страниц, перекодировал шаблоны, файлы инициализации строковых переменных — деловито и без проблем.

Voilà!