Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Изоморфный JavaScript
Будущее уже здесь
Денис Речкунов, Flamp
«Мартин, в будущем
JavaScript изоморфный!»
Что такое изоморфный JavaScript код?
• Исполняется в различных окружениях
(нам важен сервер и браузер)
• Гарантирует одно поведение
• Справляется с разностью окружений через абстракции
3
Что он нам даёт?
• Мы можем создать изоморфный Web UI
• Который будет строить HTML на сервере для SEO
• Работать как Single Page Application в браузере
• Получим единую языковую среду — JavaScript
• Максимально переиспользуем код
• Получим прирост производительности на старте (ms vs sec)
4
Что он нам не даёт?
• Не работаем с хранилищем
• Как правило, работаем с RESTful API
• Не включает код для обеспечения безопасности
• Чаще всего это только Web UI
5
Как мы к этому пришли?
27 мая 2009 года вышел релиз
Автор — Райан Дал, разработчик из Joyent
Вот оно!
В 2011 году вышел релиз сборщика
Автор — Джеймс Холлидей (substack)
Словно Делориан для изоморфного
JavaScript
Люди начали его использовать
В своих проектах
18 октября 2011 появился пост Nodejitsu
"Scaling Isomorphic Javascript Code"
9 ноября 2011 nodejitsu представляет
фреймворк
16 июня 2012 года Yahoo релизит
фреймворк Mojito
Но термин "изоморфный"
Стал популярным благодаря
Спайку Брехему из Airbnb
11 ноября 2013 появляется пост
"Isomorphic JavaScript:
The Future of Web Apps"
Позже Спайк Брехм выступает на
JSConf 2014 с докладом
"Building Isomorphic Apps"
Как добиться изоморфизма?
Нужно решить ряд проблем
• Разный рендеринг
• Зависимость от окружения
• Запросы за данными к RESTful API по-разному
• Собирать серверный код для браузера
19
Разный рендеринг
Virtual DOM (на сервере)
• Имитация DOM для фронт-енд фреймворка на сервере
• Приложение применяет изменения к эталонному DOM
• Происходит сериализация в строку HTML
• HTML уходит в браузер
21
Virtual DOM (в браузере)
• Приложение делает изменения в Virtual DOM
• Состояние Virtual DOM сравнивается с DOM
• При найденном отличии применяется поэлементный patch к DOM
• Используется в React
22
Мартин не в восторге от Virtual DOM
Template Helpers (на сервере)
• Берем шаблонизатор, например Handlebars
• Определяем Helper, который будет рендерить View с данными
• При вызове хелпера запрашиваем данные для шаблона
• Рендерим шаблон с данными, создавая элемент-обертку с меткой
• Когда отрендерили все View – отдаем HTML браузеру
24
Template Helpers (в браузере)
• Компилируем шаблоны для браузера
• Клиентский код привязывается к помеченным элементам-обёрткам
• Обновляем поддеревья DOM (каждую View полностью)
25
Мартин по-прежнему не сильно рад
Прогрессивный рендеринг (на сервере)
• Используем кастомные тэги HTML
• Используем Node.js Streams API и реализуем Transform Stream
• ourTransform.pipe(response).end(root.render());
• Transform Stream ищет наши тэги в потоке HTML
• Если нашел—рендерит в них соответствующий шаблон
• Который пропускается через такой же Transform Stream
• Весь отрендеренный HTML сразу порциями уходит в браузер
27
Изоморфный JavaScript — будущее уже здесь
Когда у вас прогрессивный рендеринг
29
Прогрессивный рендеринг (в браузере)
• Компилируем шаблоны для браузера
• Используем привязки клиентского кода по нашим тэгам HTML
• Обновляем поддеревья DOM (каждый HTML-тэг полностью)
• Используется в Catberry.js
30
Мы с Мартином выбираем этот вариант
Как балансировать между серверным и
браузерным окружением
Серверный роутер
Router.prototype.route = function (request, response) {
var context = { ... };
var state = this.getState(request.url);
renderer.render(state, context, response);
};
01.
02.
03.
04.
05.
33
Серверный контекст
var context = {
userAgent: request.headers['user-agent'],
location: request.url,
redirect: function (url) {
response.writeHead(302, {Location: url});
},
getCookie: function () { return request.headers.cookie; }
setCookie: function (string) {
response.setHeader('Set-Cookie', string);
}
};
01.
02.
03.
04.
05.
06.
07.
08.
09.
10.
11.
34
Браузерный роутер
Router.prototype.route = function (state) {
var context = { ... }
renderer.render(state, context);
};
01.
02.
03.
04.
35
Браузерный контекст
var context = {
userAgent: window.navigator.userAgent,
location: window.location.pathname + window.location.search,
redirect: function (url) {
window.location = url;
},
getCookie: function () { return document.cookie; }
setCookie: function (string) {
document.cookie = string;
}
};
01.
02.
03.
04.
05.
06.
07.
08.
09.
10.
11.
36
На что срабатывает роутинг?
window.addEventListener('popstate', function (event) {
router.route(event.state);
});
window.document.body.addEventListener('click', function (event) {
event.preventDefault();
var location = window.location.toString();
var state = router.getState(location);
window.history.pushState(state, '', location);
router.route(state);
});
01.
02.
03.
04.
05.
06.
07.
08.
09.
10.
37
Ну а остальное детали
Запросы к API по-разному
• На сервере http или https модули node.js
• В браузере XMLHttpRequest
• Есть готовые решения
(superagent, catberry-uhr, iso-http)
39
Собирать серверный код для браузера
• Для нас это уже делает browserify
• Умеет подставлять браузерные версии модулей node.js
• Делает заглушки для того, что работать не может
• Можно указать в package.json замену на браузерную версию
40
package.json
"browser": {
"./lib/Renderer.js": "./browser/Renderer.js",
"./lib/Router.js": "./browser/Router.js"
}
01.
02.
03.
04.
41
И так, что мы имеем?
• Рендеринг можно реализовать несколькими способами
• С разницей окружений вполне можно разобраться
• Есть готовые изоморфные npm-пакеты для HTTP-запросов
• Browserify решает проблемы со сборкой
42
Готовые фреймворки:
• Meteor
• Derby
• React
• Catberry.js
• Slot
• Taunus
• ещё на isomorphic.net
43
Будущее уже здесь
Несколько изоморфных веб-приложений:
• instagram.com
• flickr.com
• airbnb.ru
• 2gis.ru
• konfettin.ru
• flamp.ru
44
Спасибо за внимание!
catberry.org
Денис Речкунов, Flamp (denis.rechkunov@gmail.com)
pragmadash

More Related Content

Изоморфный JavaScript — будущее уже здесь

  • 1. Изоморфный JavaScript Будущее уже здесь Денис Речкунов, Flamp
  • 3. Что такое изоморфный JavaScript код? • Исполняется в различных окружениях (нам важен сервер и браузер) • Гарантирует одно поведение • Справляется с разностью окружений через абстракции 3
  • 4. Что он нам даёт? • Мы можем создать изоморфный Web UI • Который будет строить HTML на сервере для SEO • Работать как Single Page Application в браузере • Получим единую языковую среду — JavaScript • Максимально переиспользуем код • Получим прирост производительности на старте (ms vs sec) 4
  • 5. Что он нам не даёт? • Не работаем с хранилищем • Как правило, работаем с RESTful API • Не включает код для обеспечения безопасности • Чаще всего это только Web UI 5
  • 6. Как мы к этому пришли?
  • 7. 27 мая 2009 года вышел релиз Автор — Райан Дал, разработчик из Joyent
  • 9. В 2011 году вышел релиз сборщика Автор — Джеймс Холлидей (substack)
  • 10. Словно Делориан для изоморфного JavaScript
  • 11. Люди начали его использовать В своих проектах
  • 12. 18 октября 2011 появился пост Nodejitsu "Scaling Isomorphic Javascript Code"
  • 13. 9 ноября 2011 nodejitsu представляет фреймворк
  • 14. 16 июня 2012 года Yahoo релизит фреймворк Mojito
  • 15. Но термин "изоморфный" Стал популярным благодаря Спайку Брехему из Airbnb
  • 16. 11 ноября 2013 появляется пост "Isomorphic JavaScript: The Future of Web Apps"
  • 17. Позже Спайк Брехм выступает на JSConf 2014 с докладом "Building Isomorphic Apps"
  • 19. Нужно решить ряд проблем • Разный рендеринг • Зависимость от окружения • Запросы за данными к RESTful API по-разному • Собирать серверный код для браузера 19
  • 21. Virtual DOM (на сервере) • Имитация DOM для фронт-енд фреймворка на сервере • Приложение применяет изменения к эталонному DOM • Происходит сериализация в строку HTML • HTML уходит в браузер 21
  • 22. Virtual DOM (в браузере) • Приложение делает изменения в Virtual DOM • Состояние Virtual DOM сравнивается с DOM • При найденном отличии применяется поэлементный patch к DOM • Используется в React 22
  • 23. Мартин не в восторге от Virtual DOM
  • 24. Template Helpers (на сервере) • Берем шаблонизатор, например Handlebars • Определяем Helper, который будет рендерить View с данными • При вызове хелпера запрашиваем данные для шаблона • Рендерим шаблон с данными, создавая элемент-обертку с меткой • Когда отрендерили все View – отдаем HTML браузеру 24
  • 25. Template Helpers (в браузере) • Компилируем шаблоны для браузера • Клиентский код привязывается к помеченным элементам-обёрткам • Обновляем поддеревья DOM (каждую View полностью) 25
  • 27. Прогрессивный рендеринг (на сервере) • Используем кастомные тэги HTML • Используем Node.js Streams API и реализуем Transform Stream • ourTransform.pipe(response).end(root.render()); • Transform Stream ищет наши тэги в потоке HTML • Если нашел—рендерит в них соответствующий шаблон • Который пропускается через такой же Transform Stream • Весь отрендеренный HTML сразу порциями уходит в браузер 27
  • 29. Когда у вас прогрессивный рендеринг 29
  • 30. Прогрессивный рендеринг (в браузере) • Компилируем шаблоны для браузера • Используем привязки клиентского кода по нашим тэгам HTML • Обновляем поддеревья DOM (каждый HTML-тэг полностью) • Используется в Catberry.js 30
  • 31. Мы с Мартином выбираем этот вариант
  • 32. Как балансировать между серверным и браузерным окружением
  • 33. Серверный роутер Router.prototype.route = function (request, response) { var context = { ... }; var state = this.getState(request.url); renderer.render(state, context, response); }; 01. 02. 03. 04. 05. 33
  • 34. Серверный контекст var context = { userAgent: request.headers['user-agent'], location: request.url, redirect: function (url) { response.writeHead(302, {Location: url}); }, getCookie: function () { return request.headers.cookie; } setCookie: function (string) { response.setHeader('Set-Cookie', string); } }; 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 34
  • 35. Браузерный роутер Router.prototype.route = function (state) { var context = { ... } renderer.render(state, context); }; 01. 02. 03. 04. 35
  • 36. Браузерный контекст var context = { userAgent: window.navigator.userAgent, location: window.location.pathname + window.location.search, redirect: function (url) { window.location = url; }, getCookie: function () { return document.cookie; } setCookie: function (string) { document.cookie = string; } }; 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 36
  • 37. На что срабатывает роутинг? window.addEventListener('popstate', function (event) { router.route(event.state); }); window.document.body.addEventListener('click', function (event) { event.preventDefault(); var location = window.location.toString(); var state = router.getState(location); window.history.pushState(state, '', location); router.route(state); }); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 37
  • 39. Запросы к API по-разному • На сервере http или https модули node.js • В браузере XMLHttpRequest • Есть готовые решения (superagent, catberry-uhr, iso-http) 39
  • 40. Собирать серверный код для браузера • Для нас это уже делает browserify • Умеет подставлять браузерные версии модулей node.js • Делает заглушки для того, что работать не может • Можно указать в package.json замену на браузерную версию 40
  • 42. И так, что мы имеем? • Рендеринг можно реализовать несколькими способами • С разницей окружений вполне можно разобраться • Есть готовые изоморфные npm-пакеты для HTTP-запросов • Browserify решает проблемы со сборкой 42
  • 43. Готовые фреймворки: • Meteor • Derby • React • Catberry.js • Slot • Taunus • ещё на isomorphic.net 43
  • 44. Будущее уже здесь Несколько изоморфных веб-приложений: • instagram.com • flickr.com • airbnb.ru • 2gis.ru • konfettin.ru • flamp.ru 44
  • 45. Спасибо за внимание! catberry.org Денис Речкунов, Flamp (denis.rechkunov@gmail.com) pragmadash