SlideShare a Scribd company logo
Жизнь в изоляции
Роман Дворнов
Avito
Санкт-Петербург 2015
Работаю в Avito
Делаю SPA
Автор basis.js
Я…
За любую движуху, 

кроме голодовки ;)
Проблема
Большие сайты и SPA
4
5
Мамонта нужно есть по частям…
Компонентный подход 

и модульность – возможность
решать большую проблему
порционно
6
Основная задача:
избежать конфликтов
7
Инкапсуляция
8
«обеспечение доступности главного … путем
помещения всего мешающего, второстепенного
в некую условную капсулу (чёрный ящик)»
ru.wikipedia.org/wiki/Инкапсуляция
Способы инкапсуляции
9
Способы инкапсуляции
• Скрипты – замыкания, модули (ES6)
9
Способы инкапсуляции
• Скрипты – замыкания, модули (ES6)
• Разметка – неймспейсы (например, SVG)
9
Способы инкапсуляции
• Скрипты – замыкания, модули (ES6)
• Разметка – неймспейсы (например, SVG)
• Стили – ???
9
Изоляция стилей
4 подхода
11
Соглашение
Подход №1
Некоторая договоренность,
описывающая принцип
именования классов
13
блок__элемент--модификатор
14
Например
Это БЭМ, но все далее так же справедливо

и для OOCSS, SMACSS, SUIT, ACSS и т.д.
Изоляция достигается путем
придумывания уникальных имен
15
«Есть только две трудные задачи в
области информатики: инвалидация
кеша и придумывание названий.»
16
– Фил Карлтон
17
Знаешь сколько верстальщики тратят на
придумывание одного имени класса?
Целый день.
Целый день, Карл!
Это не проблема, когда мало
уникальных компонент
18
Универсальный компонент
v.s.
Компонент под задачу
19
20
21
<div class="app-bookings-change-status-popup-option 

app-bookings-change-status-popup-option_{disabled} 

app-bookings-change-status-popup-option_{hidden}">	
<span class="app-bookings-change-status-popup-option__caption
app-bookings-change-status-popup-option__caption_{selected}">	
{title}	
</span>	
</div>
Проблема, когда уникальных
компонент много
Реальный пример из жизни
Другие проблемы
• Уникальность обеспечивается человеком
• Сложность автоматизированного анализа
• Нет механизмов интеграции сторонней
верстки в свою или свою в чужое окружение
• …
22
Основная проблема –
человеческий фактор
23
Если правило можно нарушить –
оно будет нарушено
24
Нельзя проверить правильно ли
вы делаете, это может сказать
только человек
25
Привет, субъективное мнение!
Плюсы
• Хоть какая-то система
• Дешево для внедрения
26
Не смотря на популярность –
так себе решение*
27
* для сложных проектов
Технология
Подход №2
Shadow DOM
29
часть Web Components
w3c.github.io/webcomponents/spec/shadow/
Shadow DOM – 

возможность инкапсулировать
DOM-фрагмент
30
31
Все созданные ранее API не
видят содержимое Shadow Tree
32
А там может быть любая разметка
и стили к ней
Любая вложенность
Любая вложенность
Shadow DOM – 

это всегда JavaScript
34
35
function init(container) {	
var shadowRoot = container.createShadowRoot();	
!
var content = document.createElement('div');	
content.innerHTML = 'some markup';	
!
var styles = document.createElement('style');	
styles.textContent = '/* some css */';	
!
shadowRoot.appendChild(styles);	
shadowRoot.appendChild(content);	
}
Создаем корень Shadow Tree
36
function init(container) {	
var shadowRoot = container.createShadowRoot();	
!
var content = document.createElement('div');	
content.innerHTML = 'some markup';	
!
var styles = document.createElement('style');	
styles.textContent = '/* some css */';	
!
shadowRoot.appendChild(styles);	
shadowRoot.appendChild(content);	
}
Создаем DOM фрагмент
37
function init(container) {	
var shadowRoot = container.createShadowRoot();	
!
var content = document.createElement('div');	
content.innerHTML = 'some markup';	
!
var styles = document.createElement('style');	
styles.textContent = '/* some css */';	
!
shadowRoot.appendChild(styles);	
shadowRoot.appendChild(content);	
}
Создаем стили
38
function init(container) {	
var shadowRoot = container.createShadowRoot();	
!
var content = document.createElement('div');	
content.innerHTML = 'some markup';	
!
var styles = document.createElement('style');	
styles.textContent = '/* some css */';	
!
shadowRoot.appendChild(styles);	
shadowRoot.appendChild(content);	
}
Вставляем все в Shadow Tree
Custom Elements позволяют
абстрагироваться от нюансов
реализации
39
www.w3.org/TR/custom-elements/
Для них также нужен JavaScript
Проблема изоляции решена?
40
Миф:
Shadow DOM обеспечивает
полную изоляцию стилей
41
На текущий момент
А Shadow DOM-то – протекает
• Часть стилей наследуется от хоста

font, line-height, color и т.д.
• Можно стилизовать извне, используя
комбинатор >>> (бывш. /deep/ и ^^)
42
dev.w3.org/csswg/css-scoping/
43
Хорошая новость:
Все производители браузеров
намерены внедрять Shadow DOM
44
встреча Google, Mozilla, Apple и Microsoft
45
Но текущий дизайн «не очень»…
Надо «все» переделать
• Будет два режима open (то что сейчас) 

и close (более закрытый)
• Отказ от комбинатора >>> (м.б. будут слоты)
• Потребуется переделать текущий API
• ...
46
tinyurl.com/oqkv5u6
Плюсы
• Честная изоляция (особенно в режиме close)
• Браузерное решение (возможный стандарт)
47
Минусы
• Сложная концепция
• Требуется JavaScript
• Трудно полифилить
• Спецификация далека от завершения, 

все еще поменяется
48
Пока рано использовать,
нужно еще подумать…
49
Инлайн-стили
Подход №3
Предложение от команды React –
пишем CSS в JavaScript
51
speakerdeck.com/vjeux/react-css-in-js
speakerdeck.com/vjeux/react-css-in-js-react-france-meetup
52
var React = require('react');	
!
var styles = {	
button: {	
color: 'white',	
backgroundColor: 'red'	
}	
};	
!
var MyButton = React.createClass({	
render: function() {	
return <button style={styles.button}>Hello, world!</button>	
}	
});
А как же каскад, 

псевдоклассы, 

медиавыражения и т.д.?
53
54
function merge(...args){	
return Object.assign({}, ...args);	
}	
!
var styles = {	
// ...	
disabled: {	
opacity: .5	
}	
};	
!
<button style={merge(	
styles.button,	
condition && styles.disabled	
)}>Hello, world!</button>	
Каскад
.button {	
...	
}	
!
.disabled {	
opacity: .5;	
}
55
.button {	
background-color: gray;	
}	
.button:hover {	
background-color: red;	
}	
!
<button 	
onMouseEnter={function(){ this.setState({ hover: true }); }}	
onMouseLeave={function(){ this.setState({ hover: false }); }} 	
style={{ background: this.state.hover ? 'red' : 'gray' }}>	
Hello, world!	
</button>	
:hover
56
.button {	
width: 600px;	
}	
@media (max-device-width: 1024px) {	
.button {	
width: 300px;	
}	
}	
!
<button style={{ width: window.innerWidth > 1024 ? 600 : 300 }}>	
Hello, world!	
</button>	
Media Queries
+ обработчик на window.resize
57
Реакция 

здорового человека
Они убили Кенни

лучшее в CSS
58
Плюсы
• Изолированные стили без селекторов
• Все возможности JavaScript для стилей
• Нет проблемы специфичности
59
Минусы
• Подходит только для решений в стиле React
• Полное слияние логики и представления
• Нельзя использовать пре- и пост-процессоры
• Нельзя применять анализ и оптимизировать
• Бесполезность браузерных Developer Tools
60
61
Шурик, Вы комсомолец?
Это же не наш метод! Где гуманизм?
Процессинг
Подход №4
Пре- и пост-процессоры:
транспиляция, трансформация,
оптимизация, минификация…
63
Скрипты Разметка Стили
«Проблема»:
процессоры рассматриваются
в рамках одной технологии
64
Но если работать с технологиями
совместно, можно получить больше
65
Рассмотрим
Basis
Ember
React
66
Basis
Подход №4.1
DOM-шаблонизаторы –

не только «быстро»
68
tinyurl.com/domtemplates
Год назад в докладе
Тогда была только идея, 

теперь есть реализация и опыт
69
Предусловия
• В JavaScript не используем CSS-классы

(абстрагируемся от верстки)
• В шаблонах явно указываются используемые
файлы стилей (нет глобальных)
70
71
<b:style src="block.css"/>	
<div class="block block_{hidden}">	
{caption}	
</div>
.block { … }	
.block_hidden { … }
block.css
block.tmpl
Вот так
Инструкция шаблонизатору 

о необходимости
подключить файл стилей
Префикс b: (сокр. от basis)
стандартный механизм
неймспейсов в XML
(для избежания конфликта
имен)
Взяв любой шаблон, 

мы «знаем» всю его разметку 

и используемые им стили
72
Изоляция включается
инструкцией шаблонизатору
<b:isolate/>
73
Изоляция достигается путем
добавления уникального
префикса всем именам классов
74
75
<b:style src="block.css"/>	
<b:isolate/>	
<div class="block block_{hidden}">	
{caption}	
</div>
.block { … }	
.block_hidden { … }
block.css
block.tmpl
Добавляем инструкцию
76
<b:style src="block.css"/>	
<b:isolate/>	
<div class="block block_{hidden}">	
{caption}	
</div>
.block { … }	
.block_hidden { … }
block.css
block.tmpl
Отдаем шаблонизатору
!
!
Шаблонизатор
Пре-процессор
77
Шаблонизатор преобразует разметку и стили
<b:style src="block.css"/>	
<b:isolate/>	
<div class="block block_{hidden}">	
{caption}	
</div>
.block { … }	
.block_hidden { … }
block.css
block.tmpl
!
!
Шаблонизатор
Пре-процессор
77
Шаблонизатор преобразует разметку и стили
<link href="block.css?prefix=jc1hsy_">	
!
<div class="jc1hsy_block jc1hsy_block_{hidden}">	
{caption}	
</div>
.jc1hsy_block { … }	
.jc1hsy_block_hidden { … }
block.css?prefix=jc1hsy_
Разметка
!
!
Шаблонизатор
Пре-процессор
Префиксы генерируются
случайным образом, 

вид зависит от задачи
78
Еще вернемся к этому
Непредсказуемость префикса
лишает возможности «хакать»
верстку извне
79
Честный АНБ – без вариантов
80
<div class="app-bookings-change-status-popup-option 

app-bookings-change-status-popup-option_{disabled} 

app-bookings-change-status-popup-option_{hidden}">	
<span class="app-bookings-change-status-popup-option__caption
app-bookings-change-status-popup-option__caption_{selected}">	
{title}	
</span>	
</div>
Помните пример?
81
<b:style src="option.css"/>	
<b:isolate/>	
!
<div class="option option_{disabled} option_{hidden}">	
<span class="caption caption_{selected}">	
{title}	
</span>	
</div>
То же с изоляцией
Фишка не только в
префиксах…
82
Переопределение стилей
вместо добавления 

новых классов
83
84
Безопасное дополнение стилей
<b:style src="button.css"/>	
<button class="button">	
click me	
</button>
button.tmpl
<b:isolate/>	
<b:style>	
.button { background: green; }	
</b:style>	
<b:include src="./button.tmpl"/>
ok-button.tmpl
<b:isolate/>	
<b:style>	
.button { background: red; }	
</b:style>	
<b:include src="./button.tmpl"/>
cancel-button.tmpl
85
Безопасное дополнение стилей
<b:isolate/>	
<b:style>	
.button { background: green; }	
</b:style>	
<b:include src="./button.tmpl"/>
ok-button.tmpl
<b:isolate/>	
<b:style>	
.button { background: red; }	
</b:style>	
<b:include src="./button.tmpl"/>
cancel-button.tmpl
<b:style src="button.css"/>	
<button class="button">	
click me	
</button>
button.tmpl
85
Безопасное дополнение стилей
<b:isolate/>	
<b:style>	
.button { background: green; }	
</b:style>	
<b:include src="./button.tmpl"/>
ok-button.tmpl
<b:isolate/>	
<b:style>	
.button { background: red; }	
</b:style>	
<b:include src="./button.tmpl"/>
cancel-button.tmpl
<style>	
.jkc83s_button { … }	
.jkc83s_button { background: green; }	
</style>	
<button class="jkc83s_button">	
click me	
</button>
<style>	
.h9sg2n_button { … }	
.h9sg2n_button { background: green; }	
</style>	
<button class="h9sg2n_button">	
click me	
</button>
!
Стили раздельно для примера, 

в сборке все стили
объединяются и сжимаются
86
Масштабируем подход:
изоляция включаемой верстки
87
88
<b:isolate/>	
<b:style>	
.example-foo { color: red; }	
</b:style>	
<div class="panel">	
<b:include src="foo.tmpl" isolate="example-"/>	
<b:include src="foo.tmpl" isolate>	
<b:style src="nested.css"/>	
</b:include>	
</div>
example.tmpl
<b:style src="foo.css"/>	
<div class="foo">	
example	
</div>
foo.tmpl
Можно указывать конкретный префикс для
обращения вне включения, или не указывать 

и добавлять стили внутри инструкции включения
Изолируем включения
89
<link href="foo.css?prefix=hs83shyf_example-">	
<link href="foo.css?prefix=hs83shyf_y0dk7x_">	
<link href="nested.css?prefix=hs83shyf_y0dk7x_">	
<style>	
.hs83shyf_example-foo { color: red; }	
</style>	
<div class="hs83shyf_panel">	
<div class="hs83shyf_example-foo">	
example	
</div>	
<div class="hs83shyf_y0dk7x_foo">	
example	
</div>	
</div>
90
<link href="foo.css?prefix=hs83shyf_example-">	
<link href="foo.css?prefix=hs83shyf_y0dk7x_">	
<link href="nested.css?prefix=hs83shyf_y0dk7x_">	
<style>	
.hs83shyf_example-foo { color: red; }	
</style>	
<div class="hs83shyf_panel">	
<div class="hs83shyf_example-foo">	
example	
</div>	
<div class="hs83shyf_y0dk7x_foo">	
example	
</div>	
</div>
3 изолированные области имен
в одной разметке!
CSS неймспейсы:
изоляция файлов стилей
91
92
<b:style src="bootstrap.css" ns="bt"/>	
<b:style src="icons.css" ns="icon"/>	
<b:style src="style.css"/>	
!
<div class="active">	
<span class="icon icon:active"></span>	
<button class="bt:btn bt:active">	
Button	
</button>	
</div>
Решаем проблему конфликта имен
93
<link href="bootstrap.css?prefix=iv7z2b_">	
<link href="icons.css?prefix=jasdhb_">	
<link href="style.css">	
!
<div class="active">	
<span class="icon jasdhb_active"></span>	
<button class="iv7z2b_btn iv7z2b_active">	
Button	
</button>	
</div>
Имена из разных файлов стилей не пересекаются
94
<link href="bootstrap.css?prefix=iv7z2b_">	
<link href="icons.css?prefix=jasdhb_">	
<link href="style.css">	
!
<div class="active">	
<span class="icon jasdhb_active"></span>	
<button class="iv7z2b_btn iv7z2b_active">	
Button	
</button>	
</div>
Знаем какой класс из какого файла
Кое что еще
95
Есть же еще есть 

пост-процессинг!
96
97
PostCSS
множество плагинов
csso
структурная оптимизация
…
Например
Оптимизации
98
99
.jkc83s_button {	
width: 100px;	
color: green;	
}
.jkc83s_button {	
color: red;	
width: 100px;	
}	
.jkc83s_button {	
color: green;	
}
csso
csso умеет объединять блоки
с одинаковым селектором
100
.foo {	
color: red;	
width: 100px;	
}	
.bar {	
color: green;	
}
Но в таком случае бессилен
селекторы разные
Понимание границ верстки дает
возможность для больших
оптимизаций
101
Границы обеспечивает изоляция стилей
102
<b:style src="style.css"/>	
<b:isolate/>	
!
<div class="foo bar">	
...	
</div>
.foo {	
color: red;	
width: 100px;	
}	
.bar {	
color: green;	
}
example.tmpl style.css
У нас есть все информация об использовании
foo и bar встречаются только 

на одном элементе
103
<b:style src="style.css"/>	
<b:isolate/>	
!
<div class="s82jhs">	
...	
</div>
.s82jhs {	
color: red;	
width: 100px;	
}	
.s82jhs {	
color: green;	
}
example.tmpl style.css
Можно склеить
.foo + .bar
104
.s82jhs {	
width: 100px;	
color: green;	
}
example.tmpl style.css
<b:style src="style.css"/>	
<b:isolate/>	
!
<div class="s82jhs">	
...	
</div>
Дальше за дело снова берется csso
Поиск ошибок и
ликвидация мертвого кода
105
106
<b:style src="example.css"/>	
!
<span class="foo never-used">	
...	
</span>	
.foo {	
/* ... */	
}	
.dead-style {	
/* ... */	
}	
example.tmpl example.css
Если класс используется в разметке, но
не используется в стилях или наоборот…
Не используемые имена классов
107
Инструменты нам скажут об этом
Проблемы отладки
108
109
Длинные префиксы,
трудно искать исходник
Нет ссылки на
оригинальный файл стилей
Префиксы
110
Мы определяем вид префикса,
в зависимости от окружения
111
В режиме разработки
используются префиксы вида
iNNN__
112
Где NNN – номер шаблона, часто совпадает
между перезагрузками страницы
113
Короткие префиксы, 

легко отличать друг от друга
В боевой среде

используются base36 хеши
h5fjy1bkfb4zcskh__
114
115
function generatePrefix(){	
function base36(num){	
return Math.round(num).toString(36);	
}	
!
// префикс должен начинаться с буквы	
var result = base36(10 + 25 * Math.random());	
!
while (result.length < 16)	
result += base36(new Date * Math.random());	
!
return result.substr(0, 16);	
}
Вероятность пересечения

1 / 5 747 921 912 739 067 000 000 000
Функция генерации префикса
Трансформация имен классов
116
Трансформация имен классов
• В шаблоне:

.example
116
Трансформация имен классов
• В шаблоне:

.example
• В документе – режим разработки:

.i123__example
116
Трансформация имен классов
• В шаблоне:

.example
• В документе – режим разработки:

.i123__example
• В документе – боевая среда:

.h5fjy1bkfb4zcskh__example
116
Трансформация имен классов
• В шаблоне:

.example
• В документе – режим разработки:

.i123__example
• В документе – боевая среда:

.h5fjy1bkfb4zcskh__example
• В документе – боевая среда + сжатие имен:

.Gh
116
117
Наша верстка в боевой среде
Поиск и ссылка на источник
118
Видео
119
Инструменты могут решить проблему поиска
Подробнее в докладе «SPA инструменты»
Видео
119
Инструменты могут решить проблему поиска
Подробнее в докладе «SPA инструменты»
120
Но как быть с информацией
в Developer Tools?
121
.example {	
/* … */	
}	
!
style.css
Исходный файл стилей
122
.jdf9gd__example {	
/* … */	
}	
!
!
style.css?prefix=jdf9gd__
Подставляем префикс – получаем новый файл
123
.jdf9gd__example {	
/* … */	
}	
!
/*# sourceURL=style.css?prefix=jdf9gd__ */	
!
style.css?prefix=jdf9gd__
Добавляем sourceURL
Имя сгенерированного
файла
124
.jdf9gd__example {	
/* … */	
}	
!
/*# sourceURL=style.css?prefix=jdf9gd__ */	
/*# sourceMappingURL=data:application/json;base64,... */	
style.css?prefix=jdf9gd__
Добавляем карту кода
Содержимое

карты кода в base64
125
btoa(	
JSON.stringify({	
"version": 3,	
"sources": ["style.css"],	
"mappings":	
"AAAA" + ";AACA".repeat(css.split('n').length) 	
})	
)
Генерация карты с построчным соответствием
Оригинальное имя файла
без префикса
Повторяем ";AACA" столько раз, сколько строк
126
Не забудьте включить карты кода для CSS
127
Ссылка на оригинальный файл стилей
с правильным номером строкиPROFIT!
Не так важна реализация,
главное – идея
128
Можете повторить у себя дома
Ember
Подход №4.2
130
Более простая реализация
github.com/ebryn/ember-component-css
Осторожно – эксперимент!
Ember 2.0
131
Изоляция достигается путем
уникального класса 

на корневом элементе компонента
132
& {	
padding: 2px;	
}	
.foo {	
color: red;	
}
example.hbs example.css
<div class="example-a34fba">	
<span class="foo">	
hello world	
</div>	
</div>
133
.example-a34fba {	
padding: 2px;	
}	
.example-a34fba .foo {	
color: red;	
}
<div class="example-a34fba">	
<span class="foo">	
hello world	
</div>	
</div>
example.hbs example.css
Проблемы
• Пока на уровне прототипа
• Конфликты при вложении компонент
• Нет изоляции включений или стилей
• Под вопросом возможности отладки
134
В самом начале пути, 

но в правильном направлении
135
React
Подход №4.3
137
+ +
React Webpack PostCSS
(local-scope plugin)
tinyurl.com/m9xoefq
138
Изоляция достигается путем
замены имен классов и id

и предоставления карты замен
139
!
Webpack
local-scope
.foo { background: red; }	
#bar { background: green; }
Оригинальный файл стилей
139
!
Webpack
local-scope
.foo { background: red; }	
#bar { background: green; }
Оригинальный файл стилей
139
!
Webpack
local-scope
.foo { background: red; }	
#bar { background: green; }
.ze2420…e8b7 { background: red; }	
#zdf120…a66d { background: green; }
Оригинальный файл стилей
Преобразованный
файл стилей
139
exports.locals = {	
foo: "ze2420…e8b7",	
bar: "zdf120…a66d"	
}
!
Webpack
local-scope
.foo { background: red; }	
#bar { background: green; }
.ze2420…e8b7 { background: red; }	
#zdf120…a66d { background: green; }
Оригинальный файл стилей
Преобразованный
файл стилей
Карта замен
140
loader: 'css?localIdentName=' + (	
process.env.NODE_ENV === 'development' ?	
'[name]__[local]___[hash:base64:5]' :	
'[hash:base64:20]'	
)
Можно управлять видом замены
В режиме разработки:
MyComponent__foo___1rJwx
В боевом окружении:
rJwx92gmbvaLiDdzgXiJ
141
import React from 'react';	
import styles from './MyComponent.css';	
!
class MyComponent extends React.Component {	
render() {	
return (	
<div className={styles.foo}>	
<div className={styles.bar}>	
Local scope!	
</div>	
</div>	
);	
}	
};
Используем оригинальные имена,
не зная их текущего вида
В самом начале пути, 

но в правильном направлении
142
Hot! Появилось всего два месяца назад
Все идет к тому, что это будет
стандартной функцией
загрузчика CSS в Webpack
143
Эпилог
Пока нет идеального способа
изоляции стилей
145
Разработчики браузеров
думают над проблемой
146
Возможно решением будет
Shadow DOM
147
Пока же лучшая альтернатива
пре- и пост-процессинг
148
Надежнее и больше
возможностей
149
Вопросы?
150
Роман Дворнов
@rdvornov
rdvornov@gmail.com
basis.js
basisjs.com
github.com/basisjs

More Related Content

PDF
Баба Яга против!
Roman Dvornov
 
PDF
Инструменты разные нужны, инструменты разные важны
Roman Dvornov
 
PDF
DOM-шаблонизаторы – не только "быстро"
Roman Dvornov
 
PDF
Basis.js – «под капотом»
Roman Dvornov
 
PDF
Не бойся, это всего лишь данные... просто их много
Roman Dvornov
 
PDF
SPA инструменты
Roman Dvornov
 
PDF
Быстро о быстром
Roman Dvornov
 
PDF
Basis.js - почему я не бросил разрабатывать свой фреймворк (extended)
Roman Dvornov
 
Баба Яга против!
Roman Dvornov
 
Инструменты разные нужны, инструменты разные важны
Roman Dvornov
 
DOM-шаблонизаторы – не только "быстро"
Roman Dvornov
 
Basis.js – «под капотом»
Roman Dvornov
 
Не бойся, это всего лишь данные... просто их много
Roman Dvornov
 
SPA инструменты
Roman Dvornov
 
Быстро о быстром
Roman Dvornov
 
Basis.js - почему я не бросил разрабатывать свой фреймворк (extended)
Roman Dvornov
 

What's hot (20)

PDF
Опыт разработки эффективного SPA
Eugene Abrosimov
 
PDF
basis.js - почему я не бросил разрабатывать свой фреймворк
Roman Dvornov
 
PDF
Как построить DOM
Roman Dvornov
 
PDF
Инструментируй это
Roman Dvornov
 
PDF
JavaScript Базовый. Занятие 07.
Igor Shkulipa
 
PDF
JavaScript Базовый. Занятие 11.
Igor Shkulipa
 
PPTX
Chef @DevWeb
Alex Chistyakov
 
PDF
JavaScript Базовый. Занятие 09.
Igor Shkulipa
 
PPT
SWD Page Recorder: Записывает PageObject'ы со скоростью ниндзя SeleniumCamp 2014
Dmytro Zharii
 
PDF
БЭМ в дикой природе
Ihor Zenich
 
PDF
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Ontico
 
PDF
Пишем БЭМ правильно
Ihor Zenich
 
PDF
Виталий Харисов "История создания БЭМ. Кратко, сбивчиво и неполно"
Yandex
 
PPTX
Читабельные отчеты для автоматизации на C# / Gallio / BDDfy
Dmytro Zharii
 
PDF
Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС)
Ontico
 
PDF
JavaScript Базовый. Занятие 08.
Igor Shkulipa
 
PDF
kranonit S15 Vladimir Melnik - Ruby on Rails, BDD
Krivoy Rog IT Community
 
PPTX
Тесты в стиле BDD на C# (Подходы и инструменты; SpecFlow, BDDfy)
Dmytro Zharii
 
PDF
Внутреннее устройство и оптимизация бандла webpack
Alexey Ivanov
 
PDF
13 октября, DEV {web} - конференция о Highload веб-разработке. "Java под нагр...
IT-Portfolio
 
Опыт разработки эффективного SPA
Eugene Abrosimov
 
basis.js - почему я не бросил разрабатывать свой фреймворк
Roman Dvornov
 
Как построить DOM
Roman Dvornov
 
Инструментируй это
Roman Dvornov
 
JavaScript Базовый. Занятие 07.
Igor Shkulipa
 
JavaScript Базовый. Занятие 11.
Igor Shkulipa
 
Chef @DevWeb
Alex Chistyakov
 
JavaScript Базовый. Занятие 09.
Igor Shkulipa
 
SWD Page Recorder: Записывает PageObject'ы со скоростью ниндзя SeleniumCamp 2014
Dmytro Zharii
 
БЭМ в дикой природе
Ihor Zenich
 
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Ontico
 
Пишем БЭМ правильно
Ihor Zenich
 
Виталий Харисов "История создания БЭМ. Кратко, сбивчиво и неполно"
Yandex
 
Читабельные отчеты для автоматизации на C# / Gallio / BDDfy
Dmytro Zharii
 
Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС)
Ontico
 
JavaScript Базовый. Занятие 08.
Igor Shkulipa
 
kranonit S15 Vladimir Melnik - Ruby on Rails, BDD
Krivoy Rog IT Community
 
Тесты в стиле BDD на C# (Подходы и инструменты; SpecFlow, BDDfy)
Dmytro Zharii
 
Внутреннее устройство и оптимизация бандла webpack
Alexey Ivanov
 
13 октября, DEV {web} - конференция о Highload веб-разработке. "Java под нагр...
IT-Portfolio
 
Ad

Viewers also liked (20)

PDF
CSS parsing: performance tips & tricks
Roman Dvornov
 
PDF
CSSO – compress CSS (english version)
Roman Dvornov
 
PDF
Парсим CSS
Roman Dvornov
 
PDF
Парсим CSS: performance tips & tricks
Roman Dvornov
 
PDF
CSSO – история ускорения
Roman Dvornov
 
PDF
Как сделать ваш JavaScript быстрее
Roman Dvornov
 
PDF
CSSO — минимизируем CSS
Roman Dvornov
 
PDF
Карточный домик
Roman Dvornov
 
PDF
Remote (dev)tools своими руками
Roman Dvornov
 
PPT
чувства и эмоции в жизни человека
tenshova
 
PPT
Технологии продления молодости
Mikhail Kryzhanovskiy
 
PPT
Базовые потребности и эмоции человека
Sergey Aleksanin
 
PDF
Журнал "Про e-learning" #4
eLearning center
 
PPTX
психологический портрет личности
MetOb
 
PPT
Motcsii
guest49bd0fe
 
PDF
Проектирование услуг
Parcsis
 
PDF
Управление людьми. Как эмоции влияют на характер? Вадим Нарейко
Vadim Nareyko
 
PPTX
эмоции человека
af1311
 
PPT
эмоции человека
Olga Demyanova
 
PPTX
окомистин др
1ivanr33
 
CSS parsing: performance tips & tricks
Roman Dvornov
 
CSSO – compress CSS (english version)
Roman Dvornov
 
Парсим CSS
Roman Dvornov
 
Парсим CSS: performance tips & tricks
Roman Dvornov
 
CSSO – история ускорения
Roman Dvornov
 
Как сделать ваш JavaScript быстрее
Roman Dvornov
 
CSSO — минимизируем CSS
Roman Dvornov
 
Карточный домик
Roman Dvornov
 
Remote (dev)tools своими руками
Roman Dvornov
 
чувства и эмоции в жизни человека
tenshova
 
Технологии продления молодости
Mikhail Kryzhanovskiy
 
Базовые потребности и эмоции человека
Sergey Aleksanin
 
Журнал "Про e-learning" #4
eLearning center
 
психологический портрет личности
MetOb
 
Motcsii
guest49bd0fe
 
Проектирование услуг
Parcsis
 
Управление людьми. Как эмоции влияют на характер? Вадим Нарейко
Vadim Nareyko
 
эмоции человека
af1311
 
эмоции человека
Olga Demyanova
 
окомистин др
1ivanr33
 
Ad

Similar to Жизнь в изоляции (20)

PDF
Жизнь в изоляции / Роман Дворнов (Avito)
Ontico
 
PDF
Unit-тестирование скриншотами: преодолеваем звуковой барьер
Roman Dvornov
 
PDF
Иван Карев — Клиентская оптимизация
Yandex
 
PDF
Компонентный подход: скучно, неинтересно, бесперспективно
Roman Dvornov
 
PDF
webpack: 7 бед - один ответ
Denis Izmaylov
 
PDF
Denis Bugarchev
yaevents
 
PDF
Денис Бугарчев "Внедрение идей БЭМ на не-Яндекс проект"
Yandex
 
PDF
"Webpack: 7 бед — один ответ" — Денис Измайлов, MoscowJS 17
MoscowJS
 
PDF
D2D Pizza JS Илья Беда "Куда мы все катимся?"
Dev2Dev
 
PDF
Мастер-класс: Разрабатываем сайт с нуля на полном стеке БЭМ-технологий — Жека...
Yandex
 
PPTX
разработка бизнес приложений (7)
Alexander Gornik
 
PPTX
Как развивать библиотеку компонентов, не ломая ее / Артур Удалов (Mail.Ru Group)
Ontico
 
PDF
Баба-Яга против! — Роман Дворнов, Ostrovok.ru
Yandex
 
PDF
Инструменты разные нужны, инструменты разные важны
CodeFest
 
PPTX
Александр Даниленко - Panels как философия
LEDC 2016
 
PDF
Вадим Макишвили "Вёрстка в IntelliJIDEA"
Yandex
 
PDF
JSCS: Разработка архитектуры OpenSource-проектов
Marat Dulin
 
PDF
"Рекомендации по проектированию API" — Марина Степанова, Яндекс
Yandex
 
PPT
Презентация: 1С-Bitrix — как начать
Dmitriy Polisadov
 
PDF
Масштабируемая архитектура фронтенда
Roman Dvornov
 
Жизнь в изоляции / Роман Дворнов (Avito)
Ontico
 
Unit-тестирование скриншотами: преодолеваем звуковой барьер
Roman Dvornov
 
Иван Карев — Клиентская оптимизация
Yandex
 
Компонентный подход: скучно, неинтересно, бесперспективно
Roman Dvornov
 
webpack: 7 бед - один ответ
Denis Izmaylov
 
Denis Bugarchev
yaevents
 
Денис Бугарчев "Внедрение идей БЭМ на не-Яндекс проект"
Yandex
 
"Webpack: 7 бед — один ответ" — Денис Измайлов, MoscowJS 17
MoscowJS
 
D2D Pizza JS Илья Беда "Куда мы все катимся?"
Dev2Dev
 
Мастер-класс: Разрабатываем сайт с нуля на полном стеке БЭМ-технологий — Жека...
Yandex
 
разработка бизнес приложений (7)
Alexander Gornik
 
Как развивать библиотеку компонентов, не ломая ее / Артур Удалов (Mail.Ru Group)
Ontico
 
Баба-Яга против! — Роман Дворнов, Ostrovok.ru
Yandex
 
Инструменты разные нужны, инструменты разные важны
CodeFest
 
Александр Даниленко - Panels как философия
LEDC 2016
 
Вадим Макишвили "Вёрстка в IntelliJIDEA"
Yandex
 
JSCS: Разработка архитектуры OpenSource-проектов
Marat Dulin
 
"Рекомендации по проектированию API" — Марина Степанова, Яндекс
Yandex
 
Презентация: 1С-Bitrix — как начать
Dmitriy Polisadov
 
Масштабируемая архитектура фронтенда
Roman Dvornov
 

Жизнь в изоляции