63

SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

  • Upload
    others

  • View
    15

  • Download
    0

Embed Size (px)

Citation preview

Page 1: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI
Page 2: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

Джеймс Аквух, Software Engineer

SSR: DIY

Page 3: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

3

spinner.com

Page 4: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

SPA

4

Page 5: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

5

Page 6: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

SSR

6

Page 7: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

+

7

〉SEO〉Никакого SPA-синдрома〉Плавная деградация〉Улучшение FMP, TTI〉Кэширование HTML

Page 8: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

8

{ "express": "^4.15.2", "handlebars": "^4.0.7", "webpack": "^2.4.1", "babel-loader": "^7.0.0", }

Page 9: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

* 3G соединение 9

FMPTTI

Page 10: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

10

FMP

TTI

Page 11: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

0. SPA

https://goo.gl/ch55hU

Page 12: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

12

{{!–– Document.hbs ––}}

...

<link rel="stylesheet" href="dist/styles.css">

...

<div class="bicycle"> {{content}} </div>

...

<script src="dist/bundle.js"></script>

Page 13: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

13

// entries/server.js

...

app.use(async (req, res, next) => { const content = new SafeString( `<div class="loader"></div>` );

res.end(template({content})); next() });

...

Page 14: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

14

// entries/client.js

...

function start() { const $container = document.querySelector('div.bicycle'); const app = new Bicycle({fetch});

app.render().then(html => { // XSS ! don't do that ;) $container.innerHTML = html; }); }

...

Page 15: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

15

// fetch.js

...

const delay = IS_SERVER ? 100 : 500;

export default function({offset = 0, count = 20} = {}) { return new Promise(resolve => { setTimeout(() => resolve(data.slice(offset, offset + count)), delay ) }); }

...

Page 16: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

16

Page 17: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

17

Page 18: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

FMP: ~6300 мсTTI: ~6300 мс

18

Page 19: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

1. SSR

https://goo.gl/mwd8yr

Page 20: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

20

// entries/server.js

...

app.use(async (req, res, next) => { const app = new Bicycle({fetch}); const content = await app.render(); res.end(template({content})); next() });

...

Page 21: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

21

Page 22: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

22

Page 23: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

23

FMP: ~1700 мсTTI: ~6900 мс

Page 24: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

〉Прямой доступ к DOM〉Унифицированный API〉Глобальные переменные〉Синглтоны〉Реактивность данных

*

24

Page 25: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

2. Хэш-сумма

https://goo.gl/b3140J

Page 26: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

26

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

<div data-reactid=".157rq30hudc" data-react-checksum="556954499" >

Page 27: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

27

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

{{!–– Bicycle.hbs ––}}

<div {{SSR_HASH_ATTR}}="{{uid}}" class="bicycle"> {{content}} </div>

Page 28: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

28

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

// Bicycle.js

export class Bicycle {

...

getUID() { return `${this.count}-${this.chunks}`; }

... }

Page 29: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

29

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

<div class="bicycle" data-ssr-hash="100-3" >

Page 30: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

30

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

// entries/client.js

function start() { ... const app = new Bicycle({fetch});

const expectedUID = app.getUID(); const actualUID = $container.children[0] .getAttribute(SSR_HASH_ATTR);

if (expectedUID !== actualUID) { app.render().then(html => { ... }); } }

Page 31: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

31

—//—

Page 32: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

32

FMP: ~1700 мсTTI: ~5100 мс

Page 33: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

uid — плохоhash(VDOM) — хорошо

33

*

Page 34: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

3. Кэширование

https://goo.gl/GnRRaZ

Page 35: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

35

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

// Bicycle.js import Cache from 'lru-cache'; const cache = new Cache(100); ... async render() { const uid = this.getUID();

if (cache.has(uid)) { console.info('Cache hit.'); return cache.get(uid); }

cache.set(uid, html); return html; } ...

Page 36: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

36

Page 37: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

37

−300 мс

Page 38: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

38

FMP: ~1400 мсTTI: ~4800 мс

Page 39: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

Кэшируйте только для неавторизованных пользователей

39

*

Page 40: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

4. Prefetch

https://goo.gl/k63GLC

Page 41: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

41

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

{{!–– Document.hbs ––}}

<link rel="prefetch" as="script" href="dist/bundle.js">

Page 42: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

42

MDN: Link prefetching — это браузерный механизм, использующий время простоя браузера для предзагрузки ресурсов, которые могут скоро понадобиться пользователю

Page 43: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

Ха. Ха. Ха.

43

Page 44: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

44

Page 45: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

45

FMP: ~1400 мсTTI: ~7800 мс

Page 46: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

5. Preload

https://goo.gl/V5oa7O

Page 47: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

47

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

{{!–– Document.hbs ––}}

<link rel="preload" as="script" href="dist/bundle.js">

Page 48: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

48

Page 49: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

49

FMP: ~1600 мсTTI: ~5000 мс

Page 50: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

6. Streams

https://goo.gl/7MppPe

Page 51: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

51

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

export class GeneratorStream extends Readable {

constructor(generator) { super(); this.iterator = generator(); }

async readAndEmit() { ... }

}

Page 52: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

52

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

let stop = false; do { let {value, done} = this.iterator.next(); // если текущее значение - Promise - ожидаем его if (value && value.then) { value = await value; } // прекращаем отдачу контента, если его больше нет // либо .push() вернул false // (что означает, что клиент не успевает // выкачать данные - backpressure) stop = !this.push(done ? null : value) || done; } while (!stop)

Page 53: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

53

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

// DocumentGenerator.js

export default function *() { yield headerTemplate();

const app = new Bicycle({fetch}); // Делегируем рендеринг корневому компоненту yield * app.render();

yield footerTemplate(); }

Page 54: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

54

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

{{!–– Header.hbs ––}}

<html> <head> <title>SSR demo app</title> <link rel="stylesheet" href="dist/styles.css"> <link rel="preload" as="script" href="dist/bundle.js"> </head> <body> <div class="title"> <h1>Bitcoin rate</h1> </div> <div id="container">

Page 55: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

55

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

// Bicycle.js

*render() { const uid = this.getUID(); const {count, chunks} = this;

yield headerTemplate({SSR_HASH_ATTR, uid});

for (let i = 0; i < chunks; ++i) { yield this.renderPartial({ offset: count * i, count }); }

yield footerTemplate(); }

Page 56: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

56

<div data-reactid=".157rq30hudc" data-react-checksum=“556954499" >

{{!–– Footer.hbs ––}}

</div> <div class="copyright"> Data taken from <a target="_blank" href="/price/"> coindesk.com </a> </div> <script src="dist/bundle.js"></script> </body> </html>

Page 57: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

57

Page 58: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

58

Page 59: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

59

FMP: ~1600 мсTTI: ~4600 мс

Page 60: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

〉HTTP-статус всегда 200 :)〉Меньший размер gzip_buffers〉Поисковики (не ждут)

60

*

Page 61: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

61

TL;DRSPA → SSRFMP: 6300 → 1600 мсTTI: 6300 → 4600 мс

Page 62: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

62

Демо: akwuh.me/ssr-demoКод: github.com/jakwuh/ssr-demo

Page 63: SSR: DIY2017/10/21  · SSR: DIY 3 spinner.com SPA 4 5 SSR 6 + 7 〉SEO 〉Никакого SPA-синдрома 〉Плавная деградация 〉Улучшение FMP, TTI

Джеймс АквухSoftware Engineer

[email protected]

jakwuh

jakwuh

Спасибо за внимание

t.me/dailytip