Алексей Андросов "Криокамера для статики"

61
Криокамера для статики Алексей Андросов Старший разработчик интерфейсов Я.Субботник, Киев, 27 апреля 2013 года

description

Все знакомы с различными способами ускорения загрузки страницы. Эта тема уже давно исследована. Но в обычной ситуации при выпуске новой версии сайта у пользователя сбрасывается кеш, и ему приходится заново загружать все статические ресурсы, что увеличивает время загрузки страницы. Как сделать так, чтобы пользователь скачивал только действительно изменившиеся ресурсы? В докладе речь идет о простом, но мощном опенсорсном инструменте borschik (https://github.com/veged/borschik), который поможет ускорить загрузку в условиях постоянных релизов.

Transcript of Алексей Андросов "Криокамера для статики"

Page 1: Алексей Андросов "Криокамера для статики"

Криокамера  для  статики

Алексей  Андросов

Старший  разработчик  интерфейсов

Я.Субботник,  Киев,  27  апреля  2013  года

Page 2: Алексей Андросов "Криокамера для статики"

Обо  мне

 aandrosov@yandex-­team.ru    @doochik

●    По  образованию  –  специалист  по  защите

информации

●    6  лет  в  Яндексе,  2  года  ведущий  разработчик

фронтенда  в  Я.Почте

●    Люблю  копаться  в  браузерах  и  внедрять  новые  фичи  из  HTML5

●    Можете  спрашивать  про  JS,  CSS  и  frontend  в  целом

02

Page 3: Алексей Андросов "Криокамера для статики"

Я.Почта  (mail.yandex.ru)●    Одностраничное  AJAX-­приложение  на  11  языках

●    Отдельные  версии  для  мобильных  и  для  старых  браузеров

●    Месячная  аудитория:  26  млн

●    Общий  объем  загружаемой  статики  >1  Мб

●    12  frontend  разработчиков

●    2  релиза  в  неделю

03

Page 4: Алексей Андросов "Криокамера для статики"

Частые  релизы+ Проще  собирать

+ Быстрее  протестировать

+ Проще  откатывать  в  случае  проблем

04

Page 5: Алексей Андросов "Криокамера для статики"

Частые  релизы:  проблемы− Каждый  релиз  инвалидириует  кеш  статики

− У  пользователей  плохо  работает  браузерный  кеш

− Увеличивается  время  загрузки  почты

05

Page 6: Алексей Андросов "Криокамера для статики"

Мы  нашли  решение  –freeze

Page 7: Алексей Андросов "Криокамера для статики"

И  получили  хорошийрезультат

07

Page 8: Алексей Андросов "Криокамера для статики"

Как  все  начиналось

Page 9: Алексей Андросов "Криокамера для статики"

Вставляем  скрипты  и  стили<link href="//mysite.lv/css/_style.css"/>

<script src="//mysite.lv/js/_script.js"/>

Кеширования  статики  еще  нет

01.

02.

09

Page 10: Алексей Андросов "Криокамера для статики"

Добавляем  кеширующиезаголовкиКешириуют  обычно  «навечно»  и  добавляют  версию  в  URL,  чтобы

инвалидировать  статику

<link href="//mysite.lv/css/_style.css?ver=1.0.0"/>

<script src="//mysite.lv/js/_script.js?ver=1.0.0"/>

01.

02.

10

Page 11: Алексей Андросов "Криокамера для статики"

Уносим  на  отдельный  домен  иCDN<link href="//yandex.st/prj/css/_style.css?ver=1.0.0"/>

<script src="//yandex.st/prj/js/_script.js?ver=1.0.0"/>

01.

02.

11

Page 12: Алексей Андросов "Криокамера для статики"

Версии  раскладываем  попапками  без  проблем  переключаемся  между  версиями

<link href="//yandex.st/prj/1.0.0/_style.css"/>

<script src="//yandex.st/prj/1.0.0/_script.js"/>

01.

02.

12

Page 13: Алексей Андросов "Криокамера для статики"

Грузим  картинки  в  CSS.page {

background: url("i/bg.png")

}

Полный  путь  до  изображения  выглядит  так:

//yandex.st/prj/1.0.0/i/bg.png

01.

02.

03.

01.

13

Page 14: Алексей Андросов "Криокамера для статики"

Грузим  картинки  в  JS$('.insert').html(

'<img src="'+ PRJ.STATIC + '/i/ico.png"/>'

);

Полный  путь  до  изображения  выглядит  так:

//yandex.st/prj/1.0.0/i/ico.png

01.

02.

03.

01.

14

Page 15: Алексей Андросов "Криокамера для статики"

И  тут  мы  выпускаемновую  версию!

Page 16: Алексей Андросов "Криокамера для статики"

Теперь  ссылки  выглядят  так<link href="//yandex.st/prj/ 1.0.1 /_style.css"/>

<script src="//yandex.st/prj/ 1.0.1 /_script.js"></script>

И  картинки  грузятся  по  другим  урлам

//yandex.st/prj/ 1.0.1 /i/ico.png

//yandex.st/prj/ 1.0.1 /i/bg.png

01.

02.

01.

02.

16

Page 17: Алексей Андросов "Криокамера для статики"

А  ведь  картинки  непоменялись!

Page 18: Алексей Андросов "Криокамера для статики"

Что  же  не  так?Нечестно  заставлять  пользователя  грузить  всю

статику,  если  поменялась  только  часть

18

Page 19: Алексей Андросов "Криокамера для статики"

Чего  мы  хотим?Чтобы  файлы  перезагружались  пользователем,  когда  они

реально  изменились

19

Page 20: Алексей Андросов "Криокамера для статики"

ВариантыМожно  управлять  версиями  самостоятельно

+ Просто

− Неудобно

− Сложно  покрыть  все  файлы

− Большая  вероятность  ошибок

20

Page 21: Алексей Андросов "Криокамера для статики"

ВариантыМожно  добавлять  к  урлу  ревизию  файла  из  VCS

+ Не  надо  ничего  делать  руками

− Сложно  реализовать

− Сложно  покрыть  все  файлы

21

Page 22: Алексей Андросов "Криокамера для статики"

Что  делаем  мыГрузим  файлы  не  по  урлу  с  версией,  а  по  урлу  с  хеш-­суммой

.page {

background: url("//yandex.st/prj/_/jUK5O9GsS2gPWOhR.png")

}

01.

02.

03.

22

Page 23: Алексей Андросов "Криокамера для статики"

С  помощьюborschik  0.3.0+

bit.ly/borschik

23

Page 24: Алексей Андросов "Криокамера для статики"

Что  такое  borschik●    Это  текстовый  процессор  для  файлов  на  node.js

●    Умеет  склеивать  файлы

●    Умеет  преобразовывать  файлы

●    Умеет  минимизировать  файлы

●    Поддерживает  «из  коробки»  CSS  и  JS

●    Можно  расширять  своими  «технологиями»

24

Page 25: Алексей Андросов "Криокамера для статики"

CSS

Page 26: Алексей Андросов "Криокамера для статики"

CSSborschik  умеет

●    раскрыть  @import  и  собрать  всё  в  один  файл

●    минимизировать

●    freeze  картинок  и  шрифтов

26

Page 27: Алексей Андросов "Криокамера для статики"

Сначала  пишем  конфигКонфиг  –  файл  с  именем  .borschik

{

"paths": {

"_freeze": "//yandex.st/prj/_freeze"

},

"freeze_paths": {

".": "_freeze"

}

}

01.

02.

03.

04.

05.

06.

07.

08.27

Page 28: Алексей Андросов "Криокамера для статики"

Берем  CSS.class {

background: url("1.png");

}

01.

02.

03.

28

Page 29: Алексей Андросов "Криокамера для статики"

Запускаем$ borschik --input 1.css --freeze yes --minimize no01.

29

Page 30: Алексей Андросов "Криокамера для статики"

Все  готово!.class {

background: url("_freeze/jUK5O9GsS2gPWOhRMeBxR0GThf0.png");

}

01.

02.

03.

30

Page 31: Алексей Андросов "Криокамера для статики"

JS

Page 32: Алексей Андросов "Криокамера для статики"

Тут  немного  сложнее●    Вставлять  картинку  можно  бесконечно  разными  способами

●    Урл  может  быть  динамическим

32

Page 33: Алексей Андросов "Криокамера для статики"

Наше  решение

Мы  написали  технологию  для  borschik  для  фриза  картинок  в  JS

по  аналогии  с  CSS

Вам  надо  всего  лишь  несложно  разметить  картинки

33

Page 34: Алексей Андросов "Криокамера для статики"

JS:  статический  урл  докартинкиnew Image().src = borschik.link('1.png')

$ borschik --tech js-link --input 1.js

new Image().src = "_freeze/jUK5O9GsS2gPWOhRMeBxRGThf0.png"

01.

01.

01.

34

Page 35: Алексей Андросов "Криокамера для статики"

JS:  статический  урл  докартинкиborschik.link  при  разработке  выглядит  вот  так

borschik.link = function(link) {

return link;

}

В  продакшене  можно  убрать

01.

02.

03.

35

Page 36: Алексей Андросов "Криокамера для статики"

JS:  динамический  урл  докартинкиnew Image().src = borschik.link('@icon-' + name + '-png');

Тут  ничего  не  меняется,  а  правильный  урл  до  картинки  отдаст

borschik.entity

01.

36

Page 37: Алексей Андросов "Криокамера для статики"

JS:  динамический  урл  докартинкиОбъявляем  JSON  с  entity:

{"icon-test-png": "1.png"}

$ borschik --tech json-links --input images.json

{"icon-test-png":"_freeze/jUK5O9GsS2gPWOhRMeBxR0GThf0.png"}

01.

01.

01.

37

Page 38: Алексей Андросов "Криокамера для статики"

JS:  динамический  урл  докартинкиvar links = {};

borschik.addLinks = function(json) {

for (var link in json) {

links[link] = json[link];

}

};

01.

02.

03.

04.

05.

06.

38

Page 39: Алексей Андросов "Криокамера для статики"

JS:  динамический  урл  докартинкиborschik.link = function(link) {

if (link.charAt(0) === '@') {

return links[link.substr(1)];

}

return link;

}

01.

02.

03.

04.

05.

06.

39

Page 40: Алексей Андросов "Криокамера для статики"

JS:  динамический  урл  докартинкиСобираем  всё  вместе…

boschik.addLinks(/* borschik:include:_images.json */);

new Image().src = borschik.link('@icon-' + name + '-png');

Собираем

$ borschik --minimize no --input 1.js

01.

02.

01.

40

Page 41: Алексей Андросов "Криокамера для статики"

JS:  динамический  урл  докартинки…  и  всё  работает!

boschik.addLinks({

"icon-test-png":"_freeze/jUK5O9GsS2gOhRMeBxR0GThf0.png"

});

new Image().src = borschik.link('@icon-' + name + '-png');

01.

02.

03.

04.

41

Page 42: Алексей Андросов "Криокамера для статики"

А  теперь  зафризимсами  файлы!

Page 43: Алексей Андросов "Криокамера для статики"

borschik  и  тут  поможет$ borschik freeze \

--input path/to/dir \

--output freeze-info.json

01.

02.

03.

43

Page 44: Алексей Андросов "Криокамера для статики"

После  запуска  получаем  JSON

$ borschik freeze --input js

{

"js/index.js":"434046cd5d1b54ae2374868a7363d7d8.js",

"js/setup.js":"bcbf293578cfda2d4543d401d12e2e49.js"

}

Можно  отдать  в  конфиг  RequireJS,  например.

01.

01.

02.

03.

04.

44

Page 45: Алексей Андросов "Криокамера для статики"

Как  это  выглядит  в  Я.Почте{

"js/message.ru.js":"43...40.js"

"js/message.en.js":"46...cd.js"

"js/setup.ru.js":"5d...1b.js"

"js/setup.en.js":"54...ae.js"

"css/blue.css":"23...74.js"

"css/green.css":"a7...d8.js"

}

01.

02.

03.

04.

05.

06.

07.

08.

45

Page 46: Алексей Андросов "Криокамера для статики"

Почему  мы  делаем  так?●    У  нас  модульная  динамическая  загрузка  и  подгрузка.  Урлы

подменяются  на  лету.

●    В  браузер  выгружаются  только  информация  для  нужной  пары

тема+язык.

46

Page 47: Алексей Андросов "Криокамера для статики"

А  у  меня  просто

HTML-­страница,  и  я

хочу  фриз!

Page 48: Алексей Андросов "Криокамера для статики"

Решение  для  ленивых$ borschik --tech html --input 1.html

На  статической  странице  зафризит:

●    Картинки

●    JS

●    CSS

01.

48

Page 49: Алексей Андросов "Криокамера для статики"

Было<html>

<head>

<link rel="stylesheet" href="1.css"/>

</head>

<body>

<!-- <img src="1.png"> -->

<img src="1.png">

<script src="1.js"></script>

</body>

</html>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

49

Page 50: Алексей Андросов "Криокамера для статики"

Стало<html>

<head>

<link rel="stylesheet" href="//yandex.st/prj/_/n8mJAmyb...s2s6y0.css"/>

</head>

<body>

<!-- <img src="1.png"> -->

<img src="//yandex.st/prj/_/jUK5O9GsS2gPWOhRMeBxR0GThf0.png">

<script src="//yandex.st/prj/_/1qHhHrD9m5i9sdDbCe590URPaBw.js"></script>

</body>

</html>

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

50

Page 51: Алексей Андросов "Криокамера для статики"

Важные  моменты●    В  каждый  файл  (JS/CSS)  стоит  добавить  описание,  иначе  потом

не  понять  где  кто.  Например,

/*!mail:weather*/.class{...}

"mail:setup";(function(){...})();

●    Из  файлов  придется  убрать  всё,  что  содержит  текущую  версию.

Иначе  файлы  каждый  раз  будут  разные.

01.

02.

51

Page 52: Алексей Андросов "Криокамера для статики"

Измеряем  результат

Page 53: Алексей Андросов "Криокамера для статики"

Нам  помогут

●    window.performance.timing  или  new  Date().

Считаем  domContentLoad  и  onload.

●    window.performance.webkitGetEntries  (Chrome  25+).

Можно  считать  время  загрузки  отдельных  ресурсов.

53

Page 54: Алексей Андросов "Криокамера для статики"

domready  меньше  на  15%

54

Page 55: Алексей Андросов "Криокамера для статики"

Наши  цифры:  эффективность

фриза  платформы  (24  релиза)

bootstrap.css 75%* 10Кб

bootstrap.js 50% 16кб

CSS 64% 320Кб

JS 22% 330Кб

Yate-­шаблоны 50% 51Кб

*  Доля  неизменившихся  файлов55

Page 56: Алексей Андросов "Криокамера для статики"

Наши  цифры:  эффективность

фриза  платформы  (24  релиза)

Суммарный  размер  новой  статики  (без  gzip)  –  727Кб

После  фриза  (в  среднем)  –  400Кб

Экономия  для  пользователя  –  45%

56

Page 57: Алексей Андросов "Криокамера для статики"

Наши  цифры:  эффективность

фриза  почты  (19  релизов)

JS Yate

Общее 18%  /  460Кб 27%  /  360Кб

Адресная  книга 73%  /  30Кб 73%  /  50Кб

Написание  письма 46%  /  120Кб 37%  /  60Кб

Просмотр  письма 64%  /  40Кб 64%  /  50Кб

Настройки 64%  /  35Кб 64%  /  150Кб

WYSWYG 100%  /  280Кб -­57

Page 58: Алексей Андросов "Криокамера для статики"

Наши  цифры:  эффективность

фриза  почты  (19  релизов)

Суммарный  размер  новой  статики  (без  gzip)  –  1,6Мб

После  фриза  (в  среднем)  –  863Кб

Экономия  для  пользователя  –  47%

58

Page 59: Алексей Андросов "Криокамера для статики"

Почему  это  касается  и  вас?●    Вне  зависимости  от  размера  статику  надо  загрузить

●    Чем  чаще  пользователь  к  вам  приходит,  тем  больше  он  качает

●    Пользователи  не  будут  ждать  медленного  сайта

– bit.ly/goog-­speed-­matters

– bit.ly/msft-­goog-­slow-­page

59

Page 60: Алексей Андросов "Криокамера для статики"

Что  вы  получите●    Уменьшите  нагрузку  на  статический  кластер

●    Супер-­дешёвые  хотфиксы.

Изменили  один  файл  -­  пользователи  выкачили  один  файл

●    Дешёвые  релизы.

Пользователи  выкачивают  то,  что  реально  изменилось

●    Релиз  хоть  каждый  день!  

60

Page 61: Алексей Андросов "Криокамера для статики"

Алексей  Андросов

Старший  разработчик  интерфейсов

 aandrosov@yandex-­team.ru

 @doochik

 github.com/doochik