TGViewer
Channel Public Channel
Frontend | Иван Усынин

Frontend | Иван Усынин

@usyninis_dev

👨🏻‍💻 TechLead Frontend в Альфа-Банк. Запускал проекты в production до того, как это стало мейнстримом.

💡 На канале: рабочие заметки, решение возникающих проблем, полезные материалы про Frontend

Связаться: @usyninis
Subscribers
118
Photos
46
Videos
6
Links
27
Recent Posts 16 shown
Post #229 25
cva: когда обычного сlsx уже мало

Пока у кнопки два состояния — «обычная» и «выключенная» — легко склеить классы через clsx:
<button className={clsx("btn", isDisabled && "btn-disabled")} />

Но стоит появиться трём размерам и трём цветам, как в className начинается каша из условий. cva (class-variance-authority) помогает удобно описывать варианты стилей компонента — размеры, цвета, состояния. Внутри он использует clsx, так что это не замена, а надстройка над ним.

Основная идея

cva предлагает описать все варианты один раз и в понятном виде:
- variants — какие вообще варианты есть (размер, цвет и т.д.);
- defaultVariants — что ставить, если ничего не передали;
- compoundVariants — особые классы для конкретных сочетаний;
- VariantProps — готовые типы для пропсов компонента.

В ответ получаем функцию: передали в неё варианты — получили готовую строку классов. clsx при этом никуда не делся — cva склеивает классы через него.

Пример

import { cva, type VariantProps } from "class-variance-authority";

const button = cva("btn", {
variants: {
intent: {
primary: "btn-primary",
danger: "btn-danger",
},
size: {
sm: "btn-sm",
md: "btn-md",
},
},
compoundVariants: [
{ intent: "primary", size: "sm", className: "btn-uppercase" },
],
defaultVariants: { intent: "primary", size: "md" },
});

// выводим типы из описания вариантов
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof button>;

export function Button({ intent, size, className, ...props }: ButtonProps) {
return <button className={button({ intent, size, className })} {...props} />;
}


Частые ошибки


- Тянуть cva туда, где хватает одного-двух условий, — обычный clsx проще и легче.
- Забыть про defaultVariants — и в каждом месте вызова вручную передавать одни и те же варианты.
- Продублировать описание вариантов в нескольких компонентах вместо одного общего.

Итог

clsx отвечает на вопрос «добавить ли этот класс?», а cva — «как устроены все варианты компонента?». Если условий одно-два, clsx вполне хватает. 👉 Как только появились размеры, цвета, дефолты и сочетания — используем cva.

#js #javascript #typescript #frontend #фронтенд #разработка #dev #webdev #react
  • 🔥 2
Post #228 82
RBAC и permission-based проверки на frontend: как мы управляем доступом на проекте 🔐

В больших системах требуется гибкая и масштабируемая модель прав. Классическая проверка доступа строится вокруг ролей: пользователь получает одну или несколько ролей (например, admin, manager, viewer), и каждая роль содержит набор разрешений.

Однако при использовании такого подхода появляются проблемы:
- Роли начинают разрастаться и дублировать друг друга.
- Возникают “почти одинаковые” роли с минимальными отличиями.
- Сложно управлять точечными исключениями: если одному пользователю нужно дать доступ только к одной дополнительной кнопке, добавлять новую роль становится избыточно.

Чтобы решить эту задачу и избежать подобных проблем мы используем комбинацию RBAC (Role-Based Access Control) и permission-based подхода ⚙️

У нас есть два уровня:

1 уровень — группы пользователей (можно назвать их ролями: admin, manager, top-manager и т.д).

Это верхнеуровневая агрегация прав. Группа содержит набор доступных для неё permissions.

2 уровень — permissions (разрешение на выполнение действия)

Это атомарные флаги, которые описывают конкретное действие:
- user.edit
- order.create
- order.cancel
- feature.toggleX

Конечный пользователь в итоге получает список доступных permissions через включение его в группы + индивидуальные permissions.

Как это выглядит на frontend

После аутентификации backend возвращает список permissions пользователя. Frontend не работает напрямую с кодами групп/ролей — только с уже “развернутыми” permissions.

const canEdit = usePermission('user.edit');

return <Plate>{canEdit && <EditButton />}</Plate>;


Такой подход даёт баланс между управляемостью и гибкостью: роли упрощают администрирование, permissions позволяют точно контролировать поведение интерфейса, а изменение прав пользователей осуществляется без доработок front/back-сервисов ✨
  • 👍 5
  • 🔥 1
Post #227 114
Remotion: make videos programmatically 📹

Remotion — это программный фреймворк, который позволяет создавать видеоролики и моушен-графику с помощью кода, используя веб-технологии: React, HTML, CSS и JavaScript. Вместо традиционного монтажа вы описываете видео компонентами, а затем компилируете их в MP4 или GIF.

Говорят что аудитория инструмента — front-разработчики и команды, занимающиеся автоматизацией видеоконтента. Если вы уже умеете писать на React, кривая обучения получается почти нулевой: анимации задаются пропсами и хуками, а не перетаскиванием слоёв мышкой.

Немного поигрался в Remotion — скормил свой профиль в сетке через ИИ, вот что получилось ☝️
  • 🔥 3
Post #226 146
Выступил с лекцией в ITHub

В минувшую субботу в колледже информационных и креативных технологий IThub в Санкт-Петербурге прошел «профдэй» - в этот день специалисты из индустрии приезжают в колледж, чтобы рассказать студентам о профессии и решить вместе с ними разные кейсы.

Я выступил c лекцией о том, какой путь ждет студентов-разработчиков выходящих на рынок труда и поделился практическими советами для развития компетенции frontend.

Спасибо ITHub за приглашение! Каждый визит сюда - это погружение в атмосферу студенчества в сочетании с ИТ-технологиями!
  • 🔥 8
Post #225 167
Поздравляю прекрасных дам с 8 Марта!

Пусть весна цветет не только на улице, но и в душе!

Ну а чтобы сделать такой градиент+ascii-арт или прокачать ваши cli-скрипты прикладываю набор полезных npm-пакетов, в том числе, которые использую в работе:

1. Это база - различные утилиты для цветного текста в консоли:
https://www.npmjs.com/package/chalk

2. Для написания текста через ascii символы:
https://www.npmjs.com/package/figlet

3. Для окрашивания градиентом результатов вызова в консоль:
https://www.npmjs.com/package/gradient-string

4. Обводка текста рамкой (блоком):
https://www.npmjs.com/package/boxen

5. Готовая уведомлялка в консоль про выход новой версии вашего npm-пакета:
https://www.npmjs.com/package/update-notifier

6. Готовый лоадер в консоли для ваших скриптов с поддержкой смены статусов и текста:
https://www.npmjs.com/package/ora

7. Отображение красивых шрифтов в консоли:
https://www.npmjs.com/package/cfonts

8. Готовые шаблоны для вывода уведомлений об успехе, ошибках или предупреждениях:
https://www.npmjs.com/package/cli-alerts

👨‍💻 Ну и на последок - фреймворки для интерактивного взаимодействия вашего скрипта с пользователем через консоль:
https://www.npmjs.com/package/commander
https://www.npmjs.com/package/inquirer
https://www.npmjs.com/package/@clack/core
https://www.npmjs.com/package/@oclif/core

#js #javascript #typescript #frontend #фронтенд #разработка #dev #webdev #react #nodejs
  • ❤ 6
  • 🔥 1
Post #224 133
React.lazy — еще один полезный сценарий 🚀

Одни из самых популярных кейсов использования React.lazy + Suspense — динамическая загрузка отдельных страниц или тяжелых библиотек:

// code splitting по роутам
const Dashboard = lazy(() => import('./Dashboard'));

<Route path="/dashboard" element={<Suspense fallback={<Loader />}><Dashboard /></Suspense>} />

// code splitting для тяжелых библиотек
const ImageEditor = lazy(() => import('./ImageEditor'));

<Suspense fallback={<Loader />}><ImageEditor /></Suspense>


На нашем проекте все построено на микрофронтендах, отчего появились сценарии когда на странице может быть несколько модулей, подгружающихся с разных микрофронтов (remote-модули), но при этом экран загрузки нужен один, к тому же — в разных представлениях, в зависимости от текущей страницы.

👨‍💻 Для подобных сценариев можно собрать компонент-контейнер с Suspense+ErrorBoundary, который будет показывать процесс загрузки и отлавливать ошибки независимо от уровня вложенности remote-модулей. Итоговая структура выглядит так:

// контейнер для remote-модулей 
const ModulesContainer = ({ loadingView, errorView, children }) => (
<Suspense loadingView={loadingView}>
<ErrorBoundary errorView={errorView}>
{children}
</ErrorBoundary>
</Suspense>
);

// используем модули на любом уровне с одним лоадером:
<ModulesContainer
loadingView={<CustomLoader />}
errorView={<CustomError />}
>
<ComponentHeader>
<ComponentBody>
<RemoteModule2 value="a" />
</ComponentBody>
</ComponentHeader>
<RemoteModule1 value="b" />
</ModulesContainer>


P.S.: Не забываем логировать ошибки в ErrorBoundary! 📊

#react #microfrontends #lazy #js #javascript #typescript #frontend #фронтенд #разработка #dev #webdev #react #nodejs
  • 🔥 4
Post #223 128
TanStack Query — польза инструмента на практике

Более 2 лет назад мы стартанули с нуля разработку нашего платформенного проекта, много времени уделив анализу и подбору подходящих и актуальных библиотек и инструментов.

Для взаимодействия с серверными данными был выбран TanStack Query (ранее известный как react-query). Вот несколько практических примеров в реальных задачах 👇

1️⃣ Гибкая система инвалидации кэша

Есть у нас UI который рисует граф (дерево) сущностей. При обновлении одной точки или связей надо перерисовать точку и дочерние ветки. При правильном указании queryKey и запуске в нужный момент invalidateQueries ваш UI автоматически перерисуется в нужных местах.

// получаем данные
useQuery({
queryKey: [‘schema’, itemKey]
})

// инвалидируем после обновления
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [‘schema’, itemKey] });
},


💡 Еще лучше — когда ключи генерируются в одном месте (утилитой/фабрикой), чтобы со временем ключи не разъехались.

2️⃣ Не простой refetchInterval

refetchInterval может принимать функцию. Вот когда она может пригодиться: отображаем карточку сущности, которая имеет статусную модель. В определенном статусе надо совершать пуллинг (получать актуальный статус с сервера). Делаем это так:

useQuery({
queryFn: // получение данных
refetchInterval: (query) => {
if (query.state.data?.statusCode === STATUS_CODE.WAITING) {
return REFETCH_WAITING_INTERVAL;
}

return false;
},
})


Таким образом пуллинг будет выполняться только когда сущность в нужном вам статусе.

3️⃣ Всевозможные статусные состояния и refetch

useQuery и useMutation возвращает различные флаги: isLoading, isFetching, isError и т.д. Все это позволяет с точностью отображать загрузки/ошибки в нужном вам дизайне. В нашем случае таблица сперва загружается со скелетоном, а следующих апдейтах скелетон отображается только в строках таблицы. При ошибках загрузки остается только навешать refetch в нужную кнопку на UI.

👨‍💻 После реализации множества наших микрофронтов я бы сказал, что являюсь фанатом этой библиотеки :)

А ведь у TanStack есть еще router, store и прочие инструменты. А вы используете что-нибудь от TanStack?
  • 🔥 2
  • 👍 1
Post #222 139
Навайбкодился

В январе решил плотно повайбкодить в Cursor — генерил отдельные UI формы, тапалки, различные фабрики с поддержкой типизации - результаты реально впечатляют ✨👍

Но есть нюанс: лимит токенов закончился довольно быстро (подписка pro). Следующий шаг — разобраться, как именно расходуются токены 🤔: что съедает больше всего (промты/файлы в контексте), и как набить руку так, чтобы профит от использования остался высоким, а лимиты не сгорали за пару сеансов.

Если у кого-то уже есть практический опыт оптимизации расхода токенов — делитесь лайфхаками, будет интересно узнать 👀
  • 🔥 3
  • 😁 1
Post #220 171
Sourcecraft - сайт из репозитория за один клик

Поизучал Sourcecraft — платформу для разработки приложений от Яндекса. Основные возможности: хранение и аудит кода с помощью ИИ, полноценные CI/CD инструменты, интеграция с Yandex Cloud ☁️, анализ уязвимостей и плагины для популярных IDE.

Заметили, что Code Assistant из Sourcecraft уже встроен прямо в статьи на Хабре? Теперь можно попросить ассистента объяснить сложные участки кода из текста — удобно! 😎

Уже сейчас функционал выглядит мощно и перспективно. Думаю, со временем платформа будет набирать популярность.

А ещё есть Sourcecraft Sites — бесплатный хостинг статических сайтов прямо из репозитория за один клик! Вот эту штуку точно надо попробовать 👀.

А вам как Sourcecraft? Уже пробовали? 🤔
  • 🔥 1
Post #219 157
С Новым годом 🎉

Пусть в 2026 ваш код работал без багов, тесты покрывали все сценарии, пайплайны не падали, поставки были в срок, сервера выдерживали нагрузку, память не текла, соблюдались SLA, перевыполнялись планы и KPI, выполнялись все поставленные задачи, юзер стори и цели 🎯

Ну и по классике: счастья! Здоровья! Ура! 🎄 🎉🎅
  • ❤ 2
  • 🎉 2
  • ☃ 1
  • 🍾 1
Post #216 180
Приглашаю в Сетку - соц сеть для нетворкинга от hh.ru ⭐️

Пробил 500 подписчиков в сетке, а так же получил мерч за участие в новогоднем конкурсе! 🎁

Подписывайся, давай нетворкаться вместе )
  • 👍 3
  • 🔥 3
  • ❤ 1
Post #215 210
Post #214 212
🧑‍💻 Инкапсуляция контекста

На досуге решил поизучать как устроен Fastify - фреймворк для Node.js. Если вы еще не знакомы с ним - советую присмотреться повнимательнее: он обещает высокую производительность и гибкость благодаря минимальному оверхеду и продуманномой архитектуре.

Fastify использует систему плагинов для расширения функциональности и самое интересное началось когда я в одном из плагинов попыталя повесить хук на запросы, ожидая что он отработает на все запросы к серверу. Но данный хук отрабатывал только на маршруты внутри самого плагина. Пошел читать доку и наткнулся на фундаментальную особенность Fastify - инкапсуляция контекста.

🤔 Что такое инкапсуляция контекста?

Это способ организации кода таким образом, чтобы каждый хук/декоратор/плагин имел доступ лишь к нужным объектам данных, т.е. к нужному контексту (см. картинку). Это помогает избежать проблем с глобальными обработчиками, сплетением хуков/обработчиков/переменных внутри проекта. Фактически, это значит, что ваш код становится чище и проще в поддержке.

При этом, в случае необходимости, шаринг контекста легко можно реализовать через отдельную утилиту fastify-plugin - о чем описано в официциальной доке, и все это с понятными примерами. Интересный подход 🙂

Fastify документация:
https://fastify.dev/

Про инкапсуляцию:
https://fastify.dev/docs/latest/Reference/Encapsulation/

#fastify #nodejs #javascript #typescript #js #ts #frontend #webdev #context
  • 👍 1
Post #211 199
Выступил на A?.Frontend B-Day Meetup

Вчера прошел очень душевный митап, посвященный дню рождения сообщества разработчиков A?.Frontend 🎂

Уютный зал, полностью заполненный гостями, диджей с отличной музыкой , вкусные угощения, крутые и полезные доклады - все это оставило приятные впечатления. Рекорд регистраций был побит 🏆

Я выступал первым - запись выступления можно найти тут:
⚡️ YouTube
⚡️ VK

Спасибо нашей отличной команде организаторов 😎

#frontend #js #meetup
  • 🔥 9
  • 👍 3
Post #210 166
A?.Frontend B-Day Meetup

🎉 Уже завтра - 29 октября в Санкт-Петербурге пройдет frontend-meetup, где будем праздновать день рождения комьюнити A?.Frontend.

Приглашаю всех на событие: участвовать можно как офлайн, так и онлайн 🧑‍💻 .

На митапе выступлю с докладом, где расскажу про миграцию frontend-кода и покажу рабочие решения, которые позволяют нам избавиться от рутинных задач по обновлению библиотек на множестве проектов.

Зарегистрироваться и ознакомиться с полной программой мероприятия можно по ссылке:
https://digital.alfabank.ru/events/frontend-b-day-meetup
  • 🤩 4
  • ❤ 1
  • 👍 1
Older posts →

About this channel

How can I read @usyninis_dev without a Telegram account?
TGViewer shows the public web preview Telegram publishes for Frontend | Иван Усынин: recent posts, photos, videos and the subscriber count, with no app, login or account.
How many subscribers does Frontend | Иван Усынин have?
Frontend | Иван Усынин (@usyninis_dev) has 118 subscribers on Telegram, refreshed roughly every 30 minutes.
Does Frontend | Иван Усынин know I viewed it here?
No. Public channel previews carry no viewer identity, and TGViewer has no accounts or tracking of what you look up.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →