Изоморфные

React-приложения
Денис Измайлов
23 ноября 2015
Денис Измайлов
• 15 лет опыта разработки ПО и web
• Последние 5 лет полностью Front-end,
Node.js и архитектуре
• Более 10 проектов, в т.ч. много SPA,
highload и React
• Коммиты в Redux, webpack и koa
• Спикер HighLoad++ 2015, MoscowJS
• Автор статей на Habrahabr и
англоязычных ресурсах
, CEO
Почему от классического
Single Page Application
необходимо отказаться?
Как изоморфные приложения
отразятся на Вашей зарплате?
Что вы будете делать

на этих выходных?
Вы уже знаете
1. React 14
2. webpack
3. ES6
4. Node.js
5. Express / koa
6. Isomorphic (Universal) apps
6
Часть 1
Web стал очень
большим
Искусство

Разработка под Web



Наука
Раньше было просто
• Создал страницу
• Добавил пару скриптов
• Отправил в Production
Раньше было просто
Сервер
Браузер
11
Раньше было просто
Сервер
Браузер
Делал всё
12
Раньше было просто
Сервер
Браузер
- HTML
- [CSS, JavaScript]
Делал всё
13
Это работало
Single Page

Applications

(SPA)
Single Page Application
Сервер
Браузер
16
Single Page Application
Сервер
Браузер
Страница существует?

Авторизация нужна?

Доступ есть?
17
Single Page Application
Сервер
Браузер
Страница существует?

Авторизация нужна?

Доступ есть?
- Tiny HTML, [CSS]
- JavaScript bundle
18
Single Page Application
Плюсы
• Легко начать
• webpack
• <div id=“root” />
• React, Redux
• build
19
Single Page Application
Плюсы
• Легко начать
• Богатый функционал
webpack, <div id=“root” />, React, Redux
20
Single Page Application
Плюсы
• Легко начать
• Богатый функционал
• Быстро дорабатывать
webpack, <div id=“root” />, React, Redux
21
Single Page Application
Плюсы
• Легко начать
• Богатый функционал
• Быстро дорабатывать
• Отзывчивый UI
webpack, <div id=“root” />, React, Redux
22
Single Page Application
Плюсы
• Легко начать
• Богатый функционал
• Быстро дорабатывать
• Отзывчивый UI
• Удобно кэшировать
webpack, <div id=“root” />, React, Redux
23
- Wow. И не одного
минуса?
Single Page Application
Минусы
• Долгая загрузка
• JavaScript bundle up to 3-5 Mb
• первое обращение
• исполнение
• память
25
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
• side-эффекты
• memory leak
1st request, CPU, mem
26
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница, один URL
1st request, CPU, mem
side-эффекты, memory leaks
27
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница, один URL
• Legacy Browsers
1st request, CPU, mem
side-эффекты, memory leaks
28
- Разве это минусы?
Single Page Application
Минусы
• Долгая загрузка
для бизнеса
снижение UX
30
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
для бизнеса
снижение UX
риски
31
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
для бизнеса
снижение UX
риски
проблемы SEO
32
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
• Один URL
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
33
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
• Один URL
• Legacy Browsers
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
потеря ЦА
34
Single Page Application
Минусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
• Один URL
• Legacy Browsers
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
потеря ЦА
Расходы
Single Page Application
Минусы
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
потеря ЦА
Расходы
- WAT? Что делать?
Взять лучшее из обоих
миров
Изоморфные
приложения
Изоморфные приложения
By isomorphic we mean that any
given line of code (with notable
exceptions) can execute both on
the client and the server.


Charlie Robbins,

18 Oct 2011
Шаблоны
Стили
Локализация
Конфигурация
Routes
Права доступа
Модели
Схемы
Валидация
Сервисы
Изоморфные приложения
server.jsNode.js
worker.js
client.jsBrowser
admin.js
Бизнес-логика
Компоненты
API-интерфейсы
Actions, Reducers
Static Files
Браузер
Изоморфные приложения
Front-end
сервер
Back-end
сервер



Database
Java

etc
Браузер
Изоморфные приложения
Front-end
сервер
Back-end
сервер



Database
Java

etc
Браузер
Изоморфные приложения
Front-end
сервер
Back-end
сервер



Database
Java

etc
- HTML
- [critical CSS]
- …
Front-end
клиент
Изоморфные приложения
Front-end
сервер
Back-end
сервер



Database
Java

etc
- HTML
- [critical CSS]
- JS Bundle
Front-end
клиент
Изоморфные приложения
Front-end
сервер
Back-end
сервер



Database
Java

etc
- HTML
- [critical CSS]
- JS Bundle
Front-end
клиент
Изоморфные приложения
Front-end
сервер
• Единая среда
исполнения

• Общая кодовая база

• Полный контроль

• Экосистема
47
- Но как?
Server-Side Rendering

(SSR)
Server-Side Rendering
• Сборка HTML на Front-end сервере
• Моментальное отображение в
браузере, ещё до загрузки JS
• Когда JS загрузится, React только
добавит обработчики событий
• А это очень быстро
50
Server-Side Rendering
Код на сервере выглядит очень просто:
import ReactDOMServer from 'react-dom/server';

import Application from './components/application';



const body = ReactDOMServer.renderToString(

<Application />

);
51
Server-Side Rendering
1. Пользователь видит страницу
мгновенно
2. Отсутствие дополнительных запросов
на получение данных
3. Страница может работать даже без JS
4. Полноценная URL-навигация и мета-
тэги
5. Сохранение всех возможностей
современного JavaScript 52
Часть 2
Производительность
и масштабирование
Масштабирование
Масштабирование

функциональное
Server-Side Rendering
Всё супер, когда данные есть:
import ReactDOMServer from 'react-dom/server';

import Application from './components/application';



const initialState = { siteName: ‘Startup Makers' };

const body = ReactDOMServer.renderToString(

<Application state={initialState} />

);
57
Server-Side Rendering
Всё супер, когда данные есть:
import ReactDOMServer from 'react-dom/server';

import Application from './components/application';



const initialState = { siteName: ‘Startup Makers' };

const body = ReactDOMServer.renderToString(

<Application state={initialState} />

);
Но если их надо
получать извне?
58
Server-Side Rendering
Как получить асинхронный State:

1. Вручную для каждой страницы
2. Facebook Relay
3. redux-catch-promise
59
Асинхронный State
Вручную для каждой страницы:
• Получить State, необходимый для
страницы

• ReactDOMServer.renderToString()
60
Асинхронный State
Facebook Relay:
1. The framework for building data-driven
React applications
2. Declarative. Colocation. Mutations.
3. https://github.com/facebook/relay/
issues/136
4. 1Q2016
61
Асинхронный State
redux-catch-promise:
• Redux - state container для React
• Redux: the best for isomorphic apps,
MoscowJS 25

https://youtu.be/Uyk_8WWna6s
• redux-catch-promise - это middleware
для Redux
62
Асинхронный State
redux-catch-promise:
1. callback для захвата Promise-экшнов
2. Делаем рендер компонент
3. Из компонент - запрос к БД, отдавая
Promise
4. Собираем все эти промисы, ожидаем их
завершения
5. Повторный рендер, с данными
63
Асинхронный State
redux-catch-promise:
1. Примеры и исходный код:

https://github.com/DenisIzmaylov/
redux-catch-promise
2. Установка:
npm install redux-catch-promise
64
Производительность
Производительность
Тестовый стенд:
MacBook Pro 15” Retina (Early 2013)
2.4 GHz Intel Core i7
66
Производительность
Размер страницы: 56 238 байт
Производительность
Размер страницы: 56 238 байт
Производительность
Размер страницы: 56 238 байт
Производительность
Размер страницы: 56 238 байт
Производительность
Размер страницы: 56 238 байт
Производительность
Размер страницы: 56 238 байт
Производительность
Для теста используем:
ab -n 100 http://localhost:3000/profile

73
Производительность
Для теста используем:
ab -n 100 http://localhost:3000/profile
Запускаем…
74
Производительность
Для теста используем:
ab -n 100 http://localhost:3000/profile
Запускаем…
Time per request: 61.850 ms
75
Производительность
61.850 ms

Это медленно или быстро?
76
Производительность
61.850 ms

Это медленно или быстро?



Тот же шаблон в Handlebars:

8.385 ms



86% less
77
Производительность
61.850 ms

Это медленно или быстро?



Тот же шаблон в Handlebars:

8.385 ms



86% less
78
Производительность
1. Идём в Google - ничего полезного
2. Пробуем спросить Twitter - тишина:
79
Производительность
Ок, а что если?
NODE_ENV=production
Запускаем…
80
Производительность
Ок, а что если?
NODE_ENV=production
Запускаем…
Time per request: 37.943 ms

(vs 61.850 ms)

39% less
81
Производительность
Вроде лучше.



Но всё ещё не торт.
82
Ищем дальше
GitHub issues
Производительность
• “Server rendering is slower with npm react”



https://github.com/facebook/react/issues/812



85
Производительность
• “Server rendering is slower with npm react”



https://github.com/facebook/react/issues/812



Решение:

явно подключать react/dist/react.min.js
86
Производительность
Создаём node_modules/react.js:



if (process.env.NODE_ENV === 'production') {
module.exports = require('react/dist/react.min.js');
} else {
module.exports = require('react/dist/react.js');
}

87
Производительность
Создаём node_modules/react.js:



if (process.env.NODE_ENV === 'production') {
module.exports = require('react/dist/react.min.js');
} else {
module.exports = require('react/dist/react.js');
}

88
Как это изменило
результат?
Производительность
Server rendering is slower with npm react
react/dist/react.min.js
Запускаем…
90
Производительность
Server rendering is slower with npm react
react/dist/react.min.js
Запускаем…
Time per request: 38.253 ms

(vs 37.943 ms)

0.08% more
91
Производительность
Server rendering is slower with npm react
react/dist/react.min.js
Запускаем…
Time per request: 38.253 ms

(vs 37.943 ms)

0.08% more
FAILED
92
0
17,5
35
52,5
70
38,25337,943
8,385
61,85
React SSR Handlebars production react.min.js
Результаты
0
17,5
35
52,5
70
38,25337,943
8,385
61,85
React SSR Handlebars production react.min.js
Результаты
NODE_ENV=production

39% less
Часть 3
Продвинутые

решения
Продвинутые решения
1. Precompilation + Cache
2. Rendering Separation
3. Progressive Rendering
4. Facebook BigPipe
5. HAProxy
97
Precompilation + Cache
• UI = f(state)
• f = React Component
• state = path + [actions] + …

1. Простое решение: redis
2. “Отложенный рендеринг”:

redis + kue.js + workers 98
Rendering Separation
99
Progressive Rendering
100
Progressive Rendering
• React DOM Stream
• Flushing the Document Early
• “Streams make this library as much as 47% faster
in sending down a full page than
ReactDOM.renderToString”
• Target - 108KB page on Heroku
• Time To First Byte (TTFB) - 55% faster
• https://github.com/aickin/react-dom-stream
101
Facebook BigPipe
• Сборка страницы в процессе загрузки
• Загружается параллельно
• Устойчивость к ошибкам
Facebook BigPipe
• Сборка страницы в процессе загрузки
• Загружается параллельно
• Устойчивость к ошибкам
Facebook BigPipe
• Сборка страницы в процессе загрузки
• Загружается параллельно
• Устойчивость к ошибкам
Facebook BigPipe
105
HAProxy
• Несколько экземпляров Node.js
• Обратитесь к DevOps
106
Эпилог
Рекомендации
• Присоединяйтесь

к сообществу MoscowJS

http://moscowjs.ru/
• Улучшайте английский, не читайте
советских газет
• Читайте оригиналы и технические блоги
• Активно внедряйте в свою жизнь Twitter
и GitHub 108
Полезные материалы
1. Supercharging page load (100 Days of Google Dev)

https://youtu.be/d5_6yHixpsQ
2. Making Netflix.com Faster

http://techblog.netflix.com/2015/08/making-netflixcom-
faster.html
3. New technologies for the new LinkedIn home page

https://engineering.linkedin.com/frontend/new-technologies-
new-linkedin-home-page
4. Improving performance on Twitter.com

https://blog.twitter.com/2012/improving-performance-on-
twittercom
5. Scaling Isomorphic Javascript Code

http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/
109
Полезные материалы
6. From AngularJS to React: The Isomorphic Way

https://blog.risingstack.com/from-angularjs-to-react-the-
isomorphic-way/
7. Isomorphic JavaScript: The Future of Web Apps

http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/
8. React server side rendering performance

http://www.slideshare.net/nickdreckshage/react-meetup
9. The Lost Art of Progressive HTML Rendering

http://blog.codinghorror.com/the-lost-art-of-progressive-html-
rendering/
10. Extract and inline Critical Path CSS in HTML pages

https://github.com/addyosmani/critical
110
Послесловие
«Большинство проблем
алгоритмов можно решить
сменой структуры данных»,
Андрей Ситник
“Changes is our work”,

Jake Archibald, Google
Почему от классического
Single Page Application
необходимо отказаться?
izmaylov.dm@gmail.com
Присылайте свой мобильный телефон

и краткую информацию о себе
Спасибо за
внимание
Денис Измайлов
@DenisIzmaylov
https://github.com/DenisIzmaylov
http://startup-makers.ru
denis_izmaylov
izmaylov.dm@gmail.com
Приложение 1

Изоморфные react-приложения