Архив рубрики: Javascript

Кратко про GraphQL

В отпуске появилось по-больше свободного времени, чтобы «оглянуться по сторонам» и заняться давно интересовавшими меня технологиями. В этой записи будет краткое резюме по GraphQL.

GraphQL — это стандарт декларирования структуры данных и способов получения данных, предложенный и реализованный Facebook.

Существует несколько реализаций GraphQL:

  1. От Facebook — http://graphql.org/code/ Тут, правда, странность в том, что базовую технологию https://github.com/graphql/graphql-js не рекомендуют к production. Там же в наборе есть Relay — в чём-то аналог Redux, заточенный на выемку данных с помощью GraphQL-запросов.
  2. От Apollo — http://www.apollostack.com/ Тут ребята постарались сделать full-stack, причем клиентская часть основана на Redux. Минус их в том, что есть задержка в реализации последних версий стандарта GraphQL: сейчас, например, нет stream, defer и пр., технологий ускоряющих работу с многостраничными данными и часто-обновлямыми элементами. Не думаю, что это прям критичный минус, но это стоит учитывать.
  3. И еще 3-4 штуки можно найти тут — https://github.com/chentsulin/awesome-graphql.

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

Что мне понравилось в этой технологии:

1. Декларативное описание структур данных, которые можно запросить с сервера. Только посмотрите на эту красоту:

type Entity {
  _id: String
  title: String
  category: EntityCategory
}

type EntityCategory {
  _id: String
  title: String
}

type RootQuery {
  entity(_id: String): Entity
  entities(limit: Int): [Entity]
}

schema {
  query: RootQuery
}

Так мы описали, например, что с сервера можно запросить Entity с полями _id, title, category типа EntityCategory. В apollo-stack эта строка будет автоматически преобразована в стандартный объект GraphQLSchema.

2. Удобное написание функций, получающих данные (resolvers):

module.exports = {
    RootQuery: {
        entity(_, { _id }) {
            // Тут ожидается либо Promise, либо просто значение
            return vEntities.vertex(_id).then(v => v.vertex);
        },
        entities() {
            return vEntities.all().then(cursor => cursor.all());
        }
    },

    Entity: {
        // Эта функция будет вызвана, только если у Entity также запросили category. Также можно вернуть Promise, который зарезолвится с нужными данными.
        category(entity) {
            return { _id: 1, title: 'Category A' };
        }
    }
};

3. Язык запроса данных и Web UI GraphiQL (супер легко подключается к express) с очень крутой валидацией запросов и auto-complete, который учитывает текущую схему. Например, запросим только поле title у Entity по id:

{
  entity(id: "1") {
    title
  }
}

Из минусов можно отметить не очень понятную документацию на graphql.org (а вот у Apollo по тем же вопросам документация отличная) и официальная клиентская библиотека Relay, использование которой означает отказ от Redux.

Итого

Я вижу GraphQL как весьма удобную альтернативу классическому REST API: гораздо удобнее иметь одну «ручку», в которую можно слать разнообразные запросы на получение или изменение данных (тут они называются мутациями (mutation) и декларативное описание структуры данных, чем портянку из обработчиков путей типа req.get(‘/entities’), req.post(‘/entitites’), req.put(‘/entities/:entityId’) и т.д.

Также такой подход облегчает формирование единого state для react-приложений.

Как не надо делать open-source фреймворки

Пост скорее не «пожаловаться», а как напоминание о том, какие проблемы могут быть в open-source проекте, который позиционирует себя как «The most advanced UX framework for enterprise applications».

Выбираю фреймворк для одного небольшого приложения. Наткнулся на Grommet (от HP) — https://github.com/grommet/grommet

Поразительно насколько недружелюбен продукт в точки зрения кастомизируемости и использования в целом:

  1. Использование SASS блокирует возможность изменения базовых переменных фреймворка по своему усмотрению.
    1. Проблема была в том, что встроенный кастомный шрифт не имел кириллицы. Да и в целом, не было необходимости в кастомной шрифте. Я захотел использовать системные, однако потерпел неудачу.
    2. Если бы это был Less или Stylus, то изменить базовый шрифт было бы просто как @import ‘~framework.less’ и $base-font: ‘…’. В SASS так сделать нельзя, т.к. значение переменной определяется в месте её использования.
  2. Развесистый список зависимостей в package.json, который тянет на 150 Мб и 7-8 тысяч файлов. В то время как просто хочется подключить фреймворк и использовать его компоненты, а не заниматься его разработкой. «Используй bower поставку» скажете вы, и будете правы, однако bower-поставка фреймворка лишена разбиения на компоненты. Придется подключать 1.5 Мб  JS + 220 Кб CSS (минифицированные).
  3. CSS не разбит на модули. Подключил CSS фреймворка — получай стили всех компонент, даже если тебе нужна только треть из списка всех компонент.
  4. Мало внятной документации по инструменту «быстрого старта» — grommet-toolbox. Из-за простой необходимости использования express js пришлось от него отказаться, т.к. он это не поддерживает.

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

Пришел к выводу, что проще собрать свой boilerplate из компонентов общего назначения: сборка, типографика, гриды, роутер и т.д.

Коробочный вариант «все в одном» приемлем, только если ты работаешь в компании, где он используется.

ENB плагин для конвертации javascript из стандарта ES2015 в ES5

Оформил наконец в виде npm-пакета ENB технологию конвертации javascript кода из нового стандарта (es2015) в старый (es5), чтобы все браузеры могли работать c таким кодом.

Из интересного:

  • Преобразованный код не содержит лишнего, т.к. выбраны babel плагины, которые не добавляют дополнительный runtime;
  • Преобразуется довольно быстро по след. причинам:
    • Полностью заменяет стандартную технологию компиляции js — enb-js;
    • Код библиотек не преобразуется;
    • Нет sourcemaps (это, впрочем, и минус тоже).

Пакет с технологией тут — https://www.npmjs.com/package/enb-es2015

Спасибо @tenorok за изначальный код технологии.

Архитектура Facebook’s flux в рамках i-bem

Волна статей об «инновационных» JS технологий facebook’s flux, redux, react, immutable.js и пр. окончательно заполонили профильные ресурсы, и у меня практически не осталось выбора кроме как породить что-нибудь по мотивам и вкрутить это в БЭМ стек — основной рабочий набор технологий.

Благо, что i-bem по сути даёт практически всё, что нужно для реализации архитектурного подхода flux. Однако для проверки необходимости перерисовки понадобилась дополнительная библиотека, позволяющая использовать иммутабельные (неизменяемые) структуры данных, — Immutable.JS.

Мои размышления на этот счет вылились в блок и подход организации БЭМ проекта в целом — bem-store (https://github.com/DimitryDushkin/bem-store).

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

Ниже презентация с моего небольшого внутреннего доклада.

Яндекс.Диск: https://yadi.sk/d/7C9VQIRzpxH57
Slideshare (может быть заблокирован в РФ):

Слайды с семинара про БЭМ

1.5 года я работаю в проекте, полностью построенном на стеке технологий БЭМ и считаю этот стек действительно удачным решением многих проблем современного front-end.

Думаю, многие даже небольшие проекты во многом выиграют от перехода на этот стек, но большое количество технологий (иногда даже дублирующих друг друга), используемых в стеке, могут отпугнуть храбрецов, решивших освоить БЭМ.

hammer.js rocks or raps...

hammer.js rocks or raps…

На прошедшем семинаре я попробовал показать, насколько несложно использовать часть стека на проекте полностью построенном на Ruby on Rails, сайте о недвижимости «Идинайди«,  Ниже слайды с этого семинара. Сайт-пример — https://github.com/DimitryDushkin/bem-light-example.

Первая часть (она на слайдах) посвящена «карте» технологий БЭМ. Она весьма разнообразна, но в действительности каждому элементу на ней есть своё место, которое возможно заменить на что-то другое из другого стека. Например, в Rails Борщик можно заменить на Sprockets. Формирование BEMJSON — на использование хелпера.

Вторая часть практическая. В ней описаны базовые принципы сборки проекта и написания блоков.

Скачать и посмотреть презентацию можно на я.диске — https://yadi.sk/i/66-ZYR7YpxHFo

Slideshare (заблокирован в РФ =():

Школа разработки интерфейсов Яндекса 2013 г.

С сентября по декабрь 2013г. я учился в Школе разработки интерфейсов Яндекса. Было очень здорово и интересно. Постараюсь позже написать по-подробнее. Сейчас я просто выложу экзаменационную работу, чтобы не забыть о её существовании.)

Итак, экзаменационная работа – http://sky2high.net/etc/projects/shri_exam/ и её исходный код – https://github.com/DimitryDushkin/shri_exam_1

Если кому интересен пример приложения на БЭМ (блок, элемент, модификатор), то можете посмотреть на облегченную версию задания на БЭМ – https://github.com/DimitryDushkin/shri_exam_1_bem

Javascript: замыкания и анонимные функции

Идея, как просто объяснить анонимные функции и замыкания.

Обычно функцию мы задаем и используем так:

var global_public_var = "handsome";
function mega_func() {
   var secret_var = "vinchi"
   alert('Hey, ' + global_public_var)
}
mega_func();
// Выведет "Hey, handsome"

Так мы делаем, если предполагаем, что функцию будем использовать в дальнейшем в нескольких местах. Интуитивно, думаю, понятно, что извне функции mega_func() доступа к переменной secret_var нет, т.е. в глобальном пространстве её не видно. Однако, в javascript интересно устроены области видимости: хотя извне доступа к содержимому функции нет, но функция имеет доступ к глобальному содержимому. В нашем примере именно этот механизм позволяет алерту внутри mega_func получить содержимое глобальной переменной global_public_var. Именно это имеется в виду под «замыканием«, mega_func замкнула на себе переменную global_public_var.

Теперь про анонимные функции. Часто бывает, что функция нужна единожды, т.е. только в одном месте.) Например, в обработчиках событий, для map/reduce операций и т.д. В таком случае незачем засорять код лишними функциями с именами, достаточно создать анонимную (без имени) функцию там, где необходимо. Переписать пример выше с использованием анонимной функции можно так:

var global_public_var = "handsome";
var anon_func = function() {
   var secret_var = "vinchi"
   alert('Hey, ' + global_public_var)
}
anon_func();
// Выведет "Hey, handsome"

Тут мы функцию записали в переменную anon_func и после её запустили. А вот опять тоже самое, но вообще без лишних переменных и имен:

var global_public_var = "handsome";
(function() {
   var secret_var = "vinchi"
   alert('Hey, ' + global_public_var)
})();
// Выведет "Hey, handsome"

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