misc/class
lib/jquery_pnotify, lib/moment, lib/lodash, misc/notification, site/engine, misc/social
if( $.browser.msie && $.browser.version <= 8 ) include('lib/respond'); $._social.__cfg = {"init":[{"service":"basic"},{"fb_app_id":"1997094873850041","service":"fb"},{"vk_app_id":"2978320","service":"vk"},{"service":"twi"}],"like":[{"service":"fb"},{"service":"vk"},{"via":"","channel":"","hash_tag":"","service":"twi"}]}; window._SiteEngine = new classes.SiteEngine( { user_id: 0, controller: 'content_tape', action: 'view', content_css_version: '1459538664', social_enabled: 0} );

Faiwer

Блог web-программиста

V8 & Async Await

17 марта 2016

Очень жду от nodeJS поддержки async/await. А т.к. nodeJS использует V8, то, получается, я жду async/await именно от V8. Мне так и не удалось найти какого-либо публичного roadmap-а от команды, которая им занимается. Что мы имеем на данный момент?

Ну для начала у нас есть страница на официальном сайте nodeJS, посвящённая ES2015. Она бегло сообщает нам о том, что можно использовать готовые возможности из ES2015 под флагом --es_staging, и посмотреть список всех доступных по --v8-options. Также можно отфильтровать все v8 флаги по in-progress. К примеру мы уже можем использовать --harmony_default_parameters и --harmony_destructuring на свой страх и риск. Я использую, работает. Там же ошибочно указано, что можно включить --harmony_modules, но эту опцию просто забыли убрать.

Затем у нас есть issue в баг-трекере v8 c несколькими сообщениями. Выясняется, что пару лет назад, кто-то уже запиливал поддержку async/await в v8, но получилось не очень. А пока вроде прогресс даже не шевелится. Отсюда же ловим ссылку на то, как какой-то энтузиаст добавил поддержку синтаксиса async/await в виде патча, который отвергли со словами, мол, парень, для начала войти в v8-team.

We have some plans for tackling that next year, but not before we have finished ES6. To be honest, we would prefer not to open that can right now, since ES6 already is producing a lot of churn.

iefserge, 2015-10-27

Полную поддержку ES6 v8 пока не получил, хотя большая часть готова. Когда дойдут у команды руки до awanc/await неизвестно. Хорошо, если это произойдёт в 2016. Остаётся надеяться, что поддержка в Edge ускорит процесс появления оного и в v8.

UPD0: Нашёл RSS с новостями V8!

Простая тег-кнопка для CKeditor 4

10 марта 2016

Возникла довольно тривиальная задача ― написать для CKeditor-а плагин, который бы добавил кнопку, которая бы обрамляла выбранный текст конкретным тегом. По сути тоже самое, что и привычная нам кнопка bold, но вместо <b/> тег <var/>. Для начала нужно декларировать сам плагин:

CKEDITOR.plugins.add( 'insertvar',
    {
        init(editor){ }
    } );

Метод init будет вызываться всякий раз при создании instance-а редактора. В него пишем:

const style = new CKEDITOR.style({ element: 'var' });
const styleCommand = new CKEDITOR.styleCommand( style );
const command = editor.addCommand( 'insertvar', styleCommand );
editor.attachStyleStateChange(style, state =>
    {
        if(!editor.readOnly)
            command.setState(state);
    });

Все эти методы это стандартное API CKeditor-а для внутренних нужд. Для начала мы определяем новый стиль (CKeditor.style), указывая в нём название тега. Затем декларируем стилевую команду, также стандартными средствами. Там довольно много готовой логики. Добавляем эту команду в реестр всех команд редактора (editor.addCommand). 

Метод editor.attachStyleStateChange вызывается всякий раз, когда указанный нами стиль снимается, устанавливается или просто мы перемещаем курсор в другую позицию. command.setState позволяет нам менять состояние кнопки: активная, если курсор внутри тега, неактивная если снаружи. Также от этого состояния зависит и поведение кнопки при нажатии: либо тег установится, либо снимется.

Ну и финальный штрих:

editor.ui.addButton( 'InsertVar',
{
    label: 'Insert Variable',
    icon: 'about',
    command: 'insertvar',
    toolbar: 'insert,99'
} );

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

CasperJS, PhantomJS, SlimerJS

10 марта 2016

SlimerJS ― это Firefox для автоматических тестов или же каких-либо подручных задач. PhantomJS ― это webkit браузер без окна, для тех же целей. CasperJS ― это test-кит, обёртка над PhantomJS и SlimerJS. До недавнего времени CasperJS был присмерти, основной разработчик на него забил и никто проектом не занимался. Но судя по коммитам дело сдвинулось с мёртвой точки, и проект скорее жив, чем мёртв. Появилась поддержка свежих версий PhantomJS, которую я так давно ждал. 

PhantomJS

С ним у меня возникло множество проблем. Дело в том, что webkit в нём очень древний. Он не способен переварить less.js, нуждается в CSS-префиксах к flexbox, не знает ничего о Function.Prototype.bind. В общем less приходится билдить в CSS, а для JS пихать es5-shim и babel-polifill. Про ES2015 молчу :-)

Стабильностью не страдает, и регулярно падает с PhantomJS has crashed, без объяснения причин. Плохо дружит с jQuery.IndexedDB, с некоторой периодичностью выкидывая ошибки.

Не имеет собственного окна, что сильно затрудняет отладку тестов или персональных косяков его самого. Но умеет скриншоты, что несколько выручает. А ещё мне пока не удалось завести в нём contenteditable (обновился до 2.1 и завелось).

Касательно работы через CasperJS… Почему-то запускает только 1-ый тест в файле. Много отличий в работе с require по сравнению со SlimerJS. Если ваша тестовая база подбита под SlimerJS, то потребуется много работы напильником, прежде чем тесты хотя бы запустятся.

CSS. Свежие версии фантома умеют зачатки flexbox-а. С префиксом -webkit и сильно устаревшими свойствами. По сути половину не умеет. Насколько я понял, исходя из беглого поиска, там QWebKit 2.2, который сильно устарел. Его возможности примерно равны Safari 5.1. Открыл я в ней проект… поковырялся, понял что безнадёга полнейшая и пришлось от фантома отказаться. Буду ждать обновлений.

В отличии от SlimerJS, фантом умеет падать с правильным exit code, а также умеет работать по file:// протоколу с AJAX запросами, что очень удобно для frontend тестирования.

Отладка. Если кратко ― ад. К примеру console.log для объектов выводит [Object object]. Любит при eval уходить в вечные циклы. Stacktrace-ы выдаёт далеко не всегда. Если запускаемый файл содержит ошибки синтаксиса ― где именно не укажет. Ну и т.д.. Обычно причину приходится искать методом проб и ошибок.

UPD: отдельные граблки это то каким образом casperJS гоняет данные между тестом и страницей. В случае slimerJS, главное чтобы эти данные могли сериализовываться, к примеру, JSON-ом. В случае phantomJS начинаются какие-то чудеса с null и похожими значениями. Разбираться в чём дело я не стал, а критичные к таким багам данные стал вручную перед отправкой перегонять в JSON-строку, а в тесте уже распаковывать.

 

SlimerJS

В отличии от фантома не умеет работать без окна. В Linux эту проблему можно решить, к примеру, так: xvfb-run %команда%, без каких-либо побочных эффектов. 

Очень многие вещи, такие как require, понимает не так, как их понимает PhantomJS. По сути то тут, то там, приходит ставить условие phantom.casperEngine === 'slimerjs', что сильно поело нервов.

В отличии от фантома умеет кое-что и из ES2015, и никакие shim-es5 ему не нужны. Без труда переварил less.js. Отлично справился с flexbox-ом. 

Пока не умеет опции --web-security=no, что не позволяет нормально тестировать по file:// протоколу, т.к. не проходят AJAX запросы.

Всегда завершает скрипт с кодом 0, что создаёт проблемы в определении, провалился ли тест, или был успешен, к примеру, из grunt-задачи.

Отладка примерно столь же ужасная, что и в фантоме. Тоже умеет скриншоты.

 

CasperJS

Располагает интересным API. К примеру может загружать файл в input[type=file], умеет [contenteditable] и курсоры. Умеет дожидаться появления или исчезновения HTMLElement-а по его selector-у и многое другое.

Но требует слишком много возни с подключением скриптов, сами тесты приходится писать без ES2015 возможностей. Располагает ужасной отладкой. API не связанное с самими web-страницами очень проблематично работает, к тому же по разному в зависимости от движка. К примеру, подключить к тесту какой-нибудь lodash может оказаться непростой задачей.

Test-kit очень сильно отличается от привычных мне подходов (таких как в mocha). Я так и не понял, как удобно организовать большие и сложные тесты. Вывод в консоль в итоге напоминает какой-то хаос.

 

Резюмируя

Инструментарий есть, но он ужасен. Требует очень большого и длительного внимания. Работает весьма нестабильно. По сути это сплошная головная боль. А сами проекты почти не развиваются. Увы.

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

String.split и RegExp

9 марта 2016

При написании тестов столкнулся с интересной проблемой. Метод String.split работал не так, как я от него ожидал. Я долго возился с различными вариантами жадного и ленивого поиска, пока наконец не понял, что дело не в них. Перейду сразу к сути:

'aaaa'.split(/a+/); // ["", ""]
'aaaa'.split(/(a+)/); // ["", "aaaa", ""] WAT?
'aaaa'.split(/(?:a+)/); // ["", ""]

Полез в дебри документации:

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

Всё просто. Если знаешь. 

CLI-скрипты и stdout

5 марта 2016

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

Стандартная библиотека предоставляет ряд методов для запуска сторонних программ. Я перебрал несколько из них, но всё как-то мимо. К примеру при ручном перенаправлении spawn-а за счёт pipe в process.stdout выдачи я не добился. При ручной обработке on('data', нет цветной выдачи и затирания уже отрисованного текста. Ну и т.д. 

Как обычно великий stackoverflow помог:

require('child_process').spawn('ffmpeg',
	[
		'-i', fname,
		'-f', ext,
		'-vcodec', vcodec,
		'-acodec', acodec,
		'-ss', fromS,
		'-to', endS,
		result
	], { stdio: 'inherit' });

Весь рецепт в третьем параметре ― { stdio: 'inherit' }

UPD0. Помимо цветного вывода и затирания текста прекрасно работает пользовательский ввод (пример: ffmpeg спрашивает перезаписать ли сущ-ий файл). Получается, что stdin тоже пробрасывается.