IT-инфраструктура для бизнеса и творчества
Разработка
Danil Shashkov

Фронтенд проекта Shortstories

Для начала расскажу о проекте. Shortstories — это open source платформа для чтения и написания любительских рассказов. Делаю я этот проект в одиночку и здесь хочу рассказать о том как устроен фронтенд. Сайт можно посмотреть здесь:

Фронтенд я реализовывал дважды. Первый раз, когда только начал делать проект, второй раз после полугодовой паузы. Первая версия состояла из create-react-app, redux, redux-thunk, стили в CSS. Всё просто: отправка запросов в thunk’ах к REST API, хранение ответов в redux store. При таком подходе не было server side rendering'a (SSR), который для моего проекта важен из-за SEO продвижения. Также пришлось переписывать большую часть компонентов, потому что бэкэнд был переписан GraphQL.

Я не стал писать велосипед и за основу проекта взял Next.js, он поддерживает SSR из коробки. Интеграция с GraphQL API происходила посредством библиотеки react-apollo, которая является некой прослойкой между бэком и фронтом. Стили переписал на styled-components, просто потому что привык. Но не советую брать эту либу, если у ваших клиентов низкая скорость интернета, styled-components тянет лишние 30 кб js кода для генерации стилей. Если для вас это критично возьмите astroturf или linaria.

После переписывания сайт стал работать быстрее, потому что почти все запросы выполнялись на сервере, а html со стилями отдавался моментально. Также я был приятно удивлен упрощением разработки: не нужно вручную обрабатывать состояния отправки запроса (loading, error), реализация optimistic UI делается в пару строк кода.

Но не все так гладко. Я столкнулся с несколькими проблемами. Компоненты в react-apollo используют паттерн render props, поэтому если у нас в компоненте несколько мутаций (аналог POST/PUT запроса), то падает читабельность. Решить это можно, используя либу react-adopt. Также есть проблемы с кэшем — обновлять его надо вручную и следить, чтобы он обновлялся корректно.

Код можно посмотреть здесь:

Буду признателен если проведете код-ревью или поучаствуете в разработке.

{ "author_name": "Danil Shashkov", "author_type": "self", "tags": [], "comments": 0, "likes": 0, "favorites": 2, "is_advertisement": false, "subsite_label": "dev", "id": 59916, "is_wide": true, "is_ugc": true, "date": "Thu, 28 Feb 2019 18:15:24 +0300", "is_special": false }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ // { // name: 'camera', // url: `${cdnUrl}CameraCat`, // text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', // link: '1', // }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', } ] let buttonCycle = document.querySelector('.button--cycle') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите почитать?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
0 комментариев
Популярные
По порядку
Читать все 0 комментариев
Китай запретил любые операции с криптовалютами

Китай объявил все операции с криптовалютами нелегальными. Запрещено оказание любых услуг, связанных с криптовалютами и соответствующими производными инструментами.

Разворотная фигура Бриллиант в техническом анализе

Фигуру «Бриллиант» (с англ. – «Diamond») называют также «Кристалл», «Алмаз», «Ромб». Формация состоит из двух конфигураций — расходящегося и симметричного (сходящегося) треугольников. Этот паттерн в теории служит сигналом для смены тренда или как минимум коррекцией в средне- или долгосрочном движении актива.

Печальный опыт со СберМегаМаркет и Сберлогистик

Приветствую всех!

Зачем платить больше?

Генеральный директор IPCodex, юрист Наталья Полианчик — о том, почему кинотеатрам не стоит обижать кинокомпозиторов

Канал в телеграме с нуля до 40 тысяч подписчиков, или как отказала модная железа

Два года назад, когда я заводила свой канал в телеграме «Отказала модная железа», мне казалось, что уже поздновато, вся аудитория сформировала лист читаемого и новый канал нафиг не сдался.

Контроль доступа как сервис: интегрированное решение Gaskar Group на базе Sigur
Новая облицовка для сайта Kerama Marazzi

Команда Aero поддерживает самого крупного производителя плитки в цифровом развитии.

Бывший дизайнер Apple Джонни Айв подписал многолетний контракт с Ferrari Статьи редакции

Подробной информации о сотрудничестве компания пока не раскрыла.

Как охватить 98% сотрудников кадровым электронным документооборотом

Кейс Альфа-Лизинга и EasyDocs

Продажа Mailchimp за $12 млрд возмутила сотрудников — им не давали бонусы опционами, обещая не продавать компанию Статьи редакции

Бывшие и нынешние работники огорчены: они не смогли стать миллионерами, как бывает в Кремниевой долине. И ещё разочаровались в основателях, которые гордились духом независимости проекта, а теперь получили миллиарды за сделку с корпорацией.

«Тинькофф Журнал» запустил сервис подбора ИТ-курсов на основе реальных отзывов Статьи редакции

Перед добавлением отзыва сервис проверяет чеки об оплате курса.

null