Le-go-go или как мы
делаем медийные сайты.
Frontend-разработчик

в Rambler&Co.
Департамент разработки и дизайна
медийных проектов.
Ширяев
Евгений
2
3
Как работали раньше
4
• свой стек технологий
• своя инфраструктура
• своя админка
У каждого сайта был:
5
Проблемы
• Сложно переключать разработчиков между
проектами
• Редакции неудобно работать
• Взаимодействие с другими отделами (SEO, реклама)
• Высокая стоимость сопровождения
6
Unity
Идея: создание сайтов за счёт компоновки разных
компонентов.
7
Unity
• Проектирование дизайн-системы
• API
• Админка
• Layout builder
8
Анализ макетов
9
Карточки
10
Новостной Feed
11
Звезды WMJ
12
Концепция
13
Layout builder
Набор утилит и компонентов, созданных на React,
которые могут быть использованы как конструктор
Lego.
14
• Сборка
• Конфигурация
• Веб-сервер и SSR
15
Layout builder
Выбор инструмента
16
Преимущества инструмента
17
Стилизация компонентов
18
export default function stylesAtomsFactory(params = {}) {
const fonts = {
display: 'Arial, "Helvetica Neue", Helvetica, sans-serif',
…params.fonts,
};
const colors = {
hint: 'rgba(0, 0, 0, .5)',
placeholder: 'rgba(0, 0, 0, .3)',
…params.colors,
};
const controls = deepmerge({
feed,
drum,
comments,
bouesque,
topicContent,
…
}, params.controls || {});
…
return {
fonts,
icons,
…
controls,
};
}
Стилевые атомы галереи
19
const gallery = {
imageInfo: {
captionFont: texts.caption3.font,
captionColor: colors.primary,
...
},
arrow: {
Left: icons.arrowLeft,
Right: icons.arrowRight,
idle: {...},
hover: {
color: colors.primary,
},
},
thumbs: {
position: 'bottom',
},
thumb: {
reloadIconColor: colors.active1,
...
},
};
Использование стилевых атомов
20
<style jsx>{`
.caption
font ${imageInfo(this.props).captionFont}
color ${imageInfo(this.props).captionColor}
.credits
font ${imageInfo(this.props).creditsFont}
color ${imageInfo(this.props).creditsColor}
.showOverlay
animation ${this.props.theme.animations.hover} both show-content
.zone
transition opacity ${this.props.theme.animations.hover}
.thumb
&:before
background ${gallery(this.props).thumb.idle.fade}
transition background ${this.props.theme.animations.hover}
&:after
border 3px solid ${gallery(this.props).thumb.idle.borderColor}
transition border ${this.props.theme.animations.hover}


…
`}</style>
21
Layout builder
BaseTheme
C1 C2 Cn
site1
C1 theme
siteN
C1 theme
Структурная схема
22
Пример
23
<Footer
…
socialLinks={[
{ name: 'Facebook', link: 'https://www.facebook.com/wmj.ru' },
{ name: 'Vkontakte', link: 'https://vk.com/wmjournal' },
{ name: 'Odnoklassniki', link: 'https://ok.ru/womanjournal' },
{ name: 'Twitter', link: 'https://twitter.com/wmjournal' },
]}
…
/>
<Footer
…
socialLinks={[
{ name: 'Facebook', link: 'https://www.facebook.com/autorambler/' },
{ name: 'Vkontakte', link: 'https://vk.com/autorambler' },
{ name: 'Odnoklassniki', link: 'https://ok.ru/group/53065509634214' },
{ name: 'Twitter', link: 'https://twitter.com/autorambler' },
{ name: 'Youtube', link: ‘https://youtube.com/chanel/autorambler' },
]}
…
/>
Autorambler
Wmj
24
AutoramblerWmj
footer: {
const: {
background: atoms.colors.accent,
social: {
idle: {
color: atoms.colors.active1,
…
},
hover: {…}
},
},
desktop: {
social: {
size: 52,
iconSize: 20,
borderRadius: 27,
}
},
mobile: {
social: {…}
}
}
footer: {
const: {
background: atoms.colors.accent,
social: {
idle: {
color: atoms.colors.primary,
…
},
hover: {…}
},
},
desktop: {
social: {
size: 40,
iconSize: 17,
borderRadius: 20,
}
},
mobile: {
social: {…}
}
}
Типы компонентов
• Presenter
• View-less
• HOC
• UI
25
Presenter
Умный компонент, умеет загружать данные, как
правило имеет состояние.
26
Feed
27
<Feed
title='Гороскоп на сегодня'
card={Card8}
columns={3}
include='horoscope'
limit={12}
/>
Swagger
28
API client
29
При работе со swagger клиент предоставляет объект
tags, который содержит список методов.
Пример
Получение данных для ресурса /topics/getTopics.
30
const dataProvider = resolve('horoscope', ({api}) => {
return api.tags.topics.getTopics({
rubric: 'horoscope',
limit: 12,
});
});
View-less
Компоненты отвечают за бизнес логику, не имеют представления.
31
<BaseRoutes
main={Main}
about={About}
search={Search}
notFound={NotFound}
/>
Начало разработки
32
{
"name": "SiteName",
"version": "1.0.0",
…
"dependencies": {
"layout-builder": "6.2.7",
"prop-types": "^15.6.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
…
},
…
}
Добавить необходимые зависимости.
Разработка проекта
33
import App from ‘layout-builder/components/App';
import BaseRoutes from 'layout-builder/components/BaseRoutes';
import Layout from 'site/components/Layout';
import Main from ‘site/pages/main';
import About from 'site/pages/about';
import Search from 'site/pages/search';
import NotFound from ‘site/pages/not-found';
import config from ‘site/app-config';
export default function Site() {
return (
<App {...config}>
<Layout>
<BaseRoutes
main={Main}
about={About}
search={Search}
notFound={NotFound}
/>
</Layout>
</App>
);
}
Главный файл сайта:
Config проекта
34
export default {
host,
theme: 'light',
themes: { light, dark },
swaggerUrl: {…},
pushWoosh: {…},
schemaOrg: {…},
videoHosting: {…},
ramblerCommentsAppId:,
ramblerSubscribeKey:,
ads: {…},
};
Индивидуальные особенности сайта:
Результаты
• Единая кодовая база и инфраструктура

• Единая админка для работы редакции

• Дизайнеры работают в рамках своих гайдлайнов

• SEO-разметка

• Готовая рекламная структура, остается только
сконфигурировать

• Time2Market до 3-х недель

• Одна команда на все проекты
35

Le-go-go или как мы делаем медийные сайты.