Upload
denis-rechkunov
View
68
Download
8
Tags:
Embed Size (px)
Citation preview
pragmadash Денис РечкуновВедущий JavaScript-разработчик
Зачем изоморфный JavaScript?Почему Catberry.js?
Жизненнаяистория
Вы – веб-разработчик
И вот у вас заказчик
Буду делать Single Page Application!
Берете любимый фронт-енд фреймворк
Радостно сдаёте проект
Почему?
• Долго открывается
• Плохо индексируется
• В старых браузерах—ничего
9
Что можно сделать?
• Использовать headless browser
• Написать бэкенд
• Переписать все на изоморфном JavaScript-фреймворке
10
ИзоморфныйJavaScript?
Коротко
Одностраничный фронт-енд & SEO бэк-енд
Подробнее
Что такое изоморфный JavaScript-код?
• Исполняется в различных окружениях
(нам важен сервер и браузер)
• Гарантирует одно поведение
• Справляется с разностью окружений через абстракции
15
Зачем?
Хочется:
1. Иметь одностраничное приложение
2. Не жертвовать SEO
3. Быструю инициализацию страницы
4. Одну языковую среду — JavaScript
5. Экономить ресурсы сервера
6. И чтобы все это было просто
16
Что получаем
1. Одностраничное приложение
2. HTML с сервера, используя тот же код
3. Задержки инициализации нет, HTML пришел с сервера
4. Вы пишите на серверном JavaScript
5. Сервер не особо напрягается (node.js хорош)
6. За вас всё сделает фреймворк (если он хорош)
17
Какойфреймворк?
Catberry.jsконечно же
Почему?
• Flux-архитектура
• Изоморфные веб-компоненты
• Прогрессивный рендеринг
• Всё на Promises
• Dependency Injection
• Неблокирующие алгоритмы
20
Flux
Flux
Flux
Почему Flux?
Flux — это более безопасный MVC
• Нет моделей и привязок
• Когда Store изменился, данные запрашиваются заново
• Есть Dispatcher, который контролирует Work~ow
• Нет беспорядка с событиями
• Обновление View полностью
25
Flux Stores в Catberry.js
Директория "catberry_stores" с .js-файлами
./catberry_stores/
doge/
Wow.js
Such.js
Store.js
grumpy-cat/
No.js
26
Как писать логику Store
module.exports = Wow;
function Wow() {...}
// время актуальности данных в мс
Wow.prototype.$lifetime = 60000;
// загрузка данных
Wow.prototype.load = function () {...}
// обработка Action
Wow.prototype.handleVeryAction = function () {...}
01.
02.
03.
04.
05.
06.
07.
08.
27
Метод "load"
Wow.prototype.load = function () {...}
// запрашивает данные, например по REST
// возвращает объект или Promise
return {such: 'load'};
};
01.
02.
03.
04.
05.
28
Метод "handle"
Wow.prototype.handleVeryAction = function () {...}
// может запостить данные по REST
// вернуть результат или Promise
return {very: 'action'};
};
01.
02.
03.
04.
05.
29
Метод "handle"
Wow.prototype.handleVeryAction = function () {...}
// а может отправить сигнал,
// что Store изменился
this. $context .changed();
};
01.
02.
03.
04.
05.
30
Web/Cat-Components
Почти как веб-компоненты, но:
• Их можно отрендерить на сервере
• Они хранятся как директория в проекте
• Компонент описыватся файлом cat-component.json
• Шаблон на языке любого* шаблонизатора
• Нет Shadow DOM
• Можно ставить через NPM
32
Cat-component
hello-world/
assets/
hello.svg
world.svg
index.js
template.hbs
error.hbs
cat-component.json
33
Используются как кастомные тэги:
<cat-hello-world id="uniq-id"
cat-store="some/Store"
any-attribute="any-value">
</cat-hello-world>
В этот тэг отрендерится шаблон, который может содержать тэги
компонентов, процесс повторяется рекурсивно
01.
02.
03.
04.
34
Как писать логику в index.js
module.exports = HelloWorld;
function HelloWorld() {...}
// этапы жизни компонента
HelloWorld.prototype.render = function () {...}
HelloWorld.prototype.bind = function () {...}
HelloWorld.prototype.unbind = function () {...}
01.
02.
03.
04.
05.
06.
35
Этап "render"
Тэг компонента рендерит свой шаблон
HelloWorld.prototype.render = function () {
// может вернуть данные для шаблона
// или Promise на них
return {hello: 'world'};
};
01.
02.
03.
04.
05.
36
Этап "bind"
Рендеринг завершен, можно привязать события
HelloWorld.prototype.bind = function () {
// может вернуть карту событий
// для дочерних элементов или Promise на нее
return {
click: {'div.clickable': this.clickHandler}
};
};
01.
02.
03.
04.
05.
06.
07.
37
Этап "unbind"
Компонент готовится к удалению или обновлению
HelloWorld.prototype.unbind = function () {
// здесь нужно прибраться, если вы
// что-то делали в bind помимо карты событий
// события из карты отвязываются автоматически
};
01.
02.
03.
04.
05.
38
Как в итоге это работает?
• Можно привязать компонент к Store через атрибут cat-store
• Когда Store меняется, обновляются все привязанные компоненты
• Store получают параметры из URL через роутинг
• Store может использовать данные другого Store
39
this.$context
У компонента или Store есть $context:
• isBrowser/isServer
• userAgent
• location/referrer
• locator
• redirect('location')/notFound()
• cookie.get('name')/cookie.set(object)
41
У компонента дополнительно:
• element
• attributes
• getComponentById(‘id’)
• createComponent(‘name’, attributesObject)
• collectGarbage()
• getStoreData()
• sendAction(‘name’, object)
• sendBroadcastAction(‘name’, object)
42
У Store дополнительно:
• state
• changed()
• setDependency('storeName')/unsetDependency('storeName')
• getStoreData('storeName')
• sendAction('storeName', ‘actionName’, object)
• sendBroadcastAction(‘name’, object)
43
Как из компонента получить данные Store
this.$context.getStoreData()
.then(function () {
// ура, Store отдал данные
});
.catch(function (error) {
// печаль :(
});
01.
02.
03.
04.
05.
06.
07.
44
Как из компонента отправить Action
this.$context.sendAction('item-submit', item)
.then(function () {
// ура, Action обработался
});
.catch(function (error) {
// печаль :(
});
01.
02.
03.
04.
05.
06.
07.
45
IoC и DI
Service Locator
locator.register(‘uhr’, UHR);
locator.registerInstance('uhr', new UHR());
locator.resolve(‘uhr’);
locator.resolveAll(‘uhr’);
locator.resolveInstance(SomeConstructorDependsOnUHR);
01.
02.
03.
04.
05.
47
Dependency Injection
function StoreConstructor ( $uhr , someConfigSection) {
// можно внедрять и использовать $uhr
// и внедрять даже конфиг-секции
}
01.
02.
03.
04.
48
Прогрессивныйрендеринг
Как работает Catberry.js
50
Что происходит первый раз на сервере:
• Используется Node.js Streams API,
Catberry реализует Transform Stream
• ourTransform.pipe(response).end(document.render());
• Transform Stream ищет кастомные тэги компонентов в стриме HTML
• Если нашел—рендерит в них соответствующий шаблон
• Который пропускается через такой же Transform Stream
• Отрендеренный HTML сразу уходит в браузер порциями
51
Что происходит потом в браузере:
• Используется History API и перехватывается любой клик по ссылке
• Если ссылка попадает под роутинг, из URL парсятся новые параметры
• Параметры применяются к Stores, у них вызывается
this.$context.changed();
• Вычисляются корни изменений в DOM
• Начинается пошаговый ререндеринг изменившихся компонентов
• Данные запрашиваются в процессе
52
Когда у вас прогрессивный рендеринг
54
В боевых условиях
• Flamp.ru/best—это 3 млн уников в месяц и 20 млн просмотров
• Konfettin.ru
• статус-строй.рф
• С десяток проектов в разработке по всему миру:
Аргентина, Латвия, Украина, США, Россия
56
С чего начать?
$ npm -g install catberry-cli
$ catberry init example
catberry-todomvc
catberry-homepage
catberry-debugger
01.
02.
57
Где следить за новостями?
catberry.org
github.com/catberry/catberry
twitter.com/catberryjs
58
Вопросы?