Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 2 weeks, 2 days ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month ago
Крутой внутренний продукт вышел на публику - https://t.me/unidrawio
Пользуюсь регулярно, в том числе проектировал в нем Microfrontends Platform (о котором уже рассказывал в этом канале), приятно порекламировать.
Возможно будет история еще об одной утечке, связанной с Async Local Storage, но как минимум хочу рассказать про интересный кейс, связанный с отладкой этой проблемы.
Мы используем Fastify в качестве веб-сервера для Tramvai, разбираясь с утечкой поставил логи на хуки onRequest и onResponse.
Даю нагрузку на приложение через autocannon, обнаружил что onResponse логов меньше чем onRequest, хотя ответы от приложения приходят все.
Хорошо (хоть и поздно) заметил что не хватает ровно столько onResponse сколько запросов к параллельному вызову я указал для autocannon, условные 10 последних из 100 отправленных.
Похоже, autocannon не дожидается последнюю пачку запросов до конца, и прерывает их до того как стрим ответа будет завершен.
Обнаружил это через подписку на события finish
и close
объекта Request - оказалос что finish так же не вызывается эти 10 раз, а последние 10 close прилетают пачкой одновременно.
app.addHook('onRequest', async (request, reply) => {
request.raw.on('finish', () => { ... });
request.raw.on('close', () => { ... });
})
Понаставил логов в fastify, посмотрел исходники, и оказывается хук onResponse
вызывается как раз на событие finish
.
И это получается дефолтное поведение в Node.js, если Request был отменен клиентом (request.aborted), событие finish не срабатывает, даже когда reply.send(...) будет вызван после отмены и фактически завершит стрим.
Это кстати можно мониторить, есть гайд у fastify - https://fastify.dev/docs/latest/Guides/Detecting-When-Clients-Abort/#detecting-when-clients-abort
Вот такой вот случайно обнаруженный сайд-эффект из-за нюансов работы autocannon, который в теории может воспроизводиться и на продакшене, и получается onResponse не самый надежный вариант для очистки чего-либо после завершения запроса.
Итак, а что же утекает?
Дело в том, что для предотвращения лишних запросов за серверным кодом микрофронтов и экономии на парсинге строки в код, результаты работы этого загрузчика кэшируются в LRU-кэше.
И вот эта маленькая и безобидная стрелочная функция со всем своим богатым Closure сохраняется в памяти приложения практически на все время его жизни.
В приложениях могут быть сотни страниц, на которых используются десятки разных микрофронтов.
А в Tramvai есть модуль прогрева кэшей, который на старте сервера делает запросы к каждому роуту приложения.
Таким образом сразу после релиза, кэши прогреты, приложения работают быстрее, но и потребление памяти растет сразу при наличии утечки.
Интересно, что у нас есть тест на утечки памяти который недавно актуализировали - но такую комбинацию модулей и большого количества страниц и микрофронтов как у проблемного приложения мы вряд ли воспроизведем в этом тесте.
Также, не до конца понятно на каких уровнях надо чинить утечку.
С одной стороны не хочется трястись над каждым замыканием и бояться создавать новые функции (а как мы видим это и тулинг может сделать без нашего участия).
С другой стороны хочется предотвратить возможность выстрела в ногу, и исправить такие места как createCache
с ссылкой на commandLineExecutionContext
.
В общем есть о чем подумать, интересны ваши мысли и опыт исправления таких вещей.
Также, очень приятно видеть в твиттере много довольных мейнтейнеров open source проектов - Microsoft поддержал финансово внушительный список проектов - https://x.com/jeffwilcox/status/1801794149815095495?s=19
Вдохновляет ❤️
Не так давно писал про интересное изменение в React 19 - последовательная загрузка компонентов в рамках Suspense границ - https://t.me/super_oleg_dev/181
Как я понимаю это сильно ударило по перфу SPA приложений, где нет возможности предзагрузить ассеты и данные параллельно как это делают при SSR.
В итоге будут искать более удачное / универсальное решение:
- https://github.com/facebook/react/issues/29898
- https://x.com/sophiebits/status/1801663976973209620?s=19
Telegram
SuperOleg dev notes
Парочка интересных кейсы из беты React 19, которые особо не освещались: - Прощай useIsomorphicLayoutEffect, больше нет варнинга на сервере - https://github.com/facebook/react/pull/26395 - Если вы используете throw promise или либы с поддержкой Suspense…
Про "все-в-React" или "все-в-компоненте" и декларативность.
Что мы видели интересного в коде компонентов:
- <Route>
и <Redirect>
из React Router
- <Script>
из Next.js и <Scripts>
из Remix
- useQuery
из React Query или Apollo
- useForm
из React Hook Form
- не могу не вспомнить <FormSpy>
из Formik
Компоненты и хуки из списка объединяет то, что это либо обернутые в компонент сайд-эффекты, либо размазанная по компонентам логика, которой не возможно управлять централизованно.
Это не примеры абсолютного зла - так как плюсы без сомнения есть, в очень гибком роутинге, либо в умном механизме запросов без бойлерплейта, либо в минималистичной абстракции логики фреймворка от пользователя.
Но в масштабе, проблемы есть.
Хранить список роутов в компонентах - не масштабируется, подход с заранее объявленными роутами гораздо легче развивать и поддерживать.
Но декларативность в React мире доходит до того, что например в React Router вообще нет такой цельной сущности как Router! Есть только набор хуков, а сделать что-то с роутингом вне компонентов мы просто не имеем возможности.
Например (императивно) создать const router = new Router()
, предзаполнить router.addRoute(...)
, в лоадере/экшены выполнить router.redirect(..)
, передать в <Router.Provider router={router} >
и так далее.
Отсутствует жизненный цикл, настолько RR связан с реактом. Механизм loader'ов добавил хотя бы один этап жизненного цикла. Но для какой-нибудь авторизации разработчики все-равно будут создавать всякие <Auth>
и <ProtectedRoute>
компоненты.
Наглядный пример в этой статье - https://blog.logrocket.com/authentication-react-router-v6/. Хороший гайд, все аккуратно, react way, но насколько же сильно размазана аутентификация по компонентам, и не существует снаружи.
Просто сравните с Angular, где через DI предоставляется отдельный сервис для аутентификации, используемый и в UI и в гуарде роутера.
React Query большие молодцы, выделяют логику в отдельные сущности, и с ними можно работать где угодно, например QueryClient. Такие вещи очень упрощают интеграцию для SSR фреймворка.
Но и тут есть проблемы, возьмем сами квери. Как отдельной сущности их просто нет, есть набор параметров вида const query = useQuery({ queryKey: ['todos'], queryFn: getTodos }), и только через queryKey возможна связь для одной и той же квери между использованием в компоненте и прямой работой через QueryClient в других местах.
Сложно делать расширяемые и переиспользуемые query, параметры считываются и сохраняются сразу при рендере хука - нельзя сделать queryKey
функцией, на момент рендера useQuery
надо иметь все параметры для формирования массива ключей.
Используя React Query и React Hook Form, можно делать хороший UX и писать мало кода на сложные кейсы, но очень сложно явно выделить сущности / модели / бизнес-логику, что опять-таки может выстрелить в ногу в масштабе, и уж точно не поможет сделать архитектуру "кричащей".
По поводу таких кейсов как Scripts
в Remix, или поддержка метаданных и стилей в React 19.
Реакт или Ремикс не дает нам условный AssetsManager
, в который мы смогли бы добавить ресурс явно по конкретному условию, например:
if (analyticsEnabled) {
assetManager.addScript({ src: anaylicsScript, async })
}
Нам предлагается явно рендерить нужный скрипт в компоненте (прямо или косвенно). И хотя для RSC и стриминга понятно почему важно поддержать эти механизмы, выбранный путь мне совершенно не нравится.
Если подвести итог, эта псевдо-декларативность в React и экосистеме, как и явно обозначенная ограниченная область ответственности React (не фреймворк, а библиотека!), напрямую влияет на то как сообщество пишет приложения, на образ мышления новых разработчиков, и как мне кажется влияет негативно.
Получается для меня, главная проблема React это точно не лишние ререндеры, а архитектурные вопросы. И вряд ли экосистема в этом плане заметно поменяется, а область ответственности React только расширяется. Скорее всего в будущем при поддержке RSC и прочих современных возможностей, остро встанет вопрос что мета-фреймворк либо будет написан в react way стиле, либо останется в стороне.
GitHub
Add useRouter Hook · Issue #6430 · remix-run/react-router
Hi guys, at current React Conf Hooks have been announced for React v16.7. What's the plan for supporting them? Will there be a useRouter() any time soon? https://reactjs.org/docs/hooks-faq.html...
Собрал для вас в одну папку авторов, ведущих блоги по фронтенду, веб-разработке и вокруг неё.
? https://t.me/addlist/Z6Efi4jXwe9lODcy
Специально отобрал именно ламповые авторские блоги, а не перепосты ссылок, документации или тексты не про код.
Для меня это хороший способ следить за реакциями о событиях индустрии. Например, конференции проходят не так часто, и контент с них становится общедоступным не сразу. Кроме того, там обычно рассказывают о чём-то эпичном, не сиюминутном, так как формат обязывает. А вот в авторских бложиках (и комментариях к постам) можно собрать цельную картинку происходящего в рутине, и не просто факты, а именно авторскую интерпретацию и комментарии.
Надеюсь, будет полезно ✌️
Парочка интересных кейсы из беты React 19, которые особо не освещались:
- Прощай useIsomorphicLayoutEffect, больше нет варнинга на сервере - https://github.com/facebook/react/pull/26395
- Если вы используете throw promise или либы с поддержкой Suspense, в рамках одного Suspense загрузка данных в параллельных компонентах начнет происходить последовательно - https://github.com/facebook/react/pull/26380
Пример кода где будет водопад запросов при использовании условного useSuspenseQuery:
const Root = () => {
return <>
<Suspense>
<CmpWithUseSuspenseQuery />
<CmpWithUseSuspenseQuery />
</Suspense>
}
В релизе очень порадовало улучшение ошибок гидрации, и централизованная обработка ошибок Error Boundaries.
Также я никак не пойму в какой версии удалили или удалят 421 ошибку гидрации - https://github.com/facebook/react/issues/24959#issuecomment-1317309116
Ошибка происходит при ререндере Suspense компонента, поддерево которого не завершило гидрацию, и приводит к деоптимизации - клиентский рендер вместо гидрации.
Очень легко словить такую ошибку используя useSyncExternalStore.
Потратил часы на разборы таких ошибок, а ситуация в итоге странная - ошибку выпиливают, а деоптимизация остаётся.
Наверное мне стоило более тщательно подойти к замеру разницы в перформансе при деоптимизации, может проблема и не такая значительная, раз ее просто можно заглушить?
GitHub
Remove layout effect warning on the server by rickhanlonii · Pull Request #26395 · facebook/react
Overview This PR unfortunately removes the warning emitted when using layout effects on the server: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server...
Подведу некий summary:
- Round Trip Time важен на каждом из многочисленных этапов загрузки HTML, в идеальном мире точка входа в приложение - это CDN
- Редиректы не бесплатные как для клиента, так и для приложения, лучше их не делать или делать поближе к пользователю, например на уровне балансера
- Service Worker может как ускорить, так и замедлить ваше приложение - измеряйте все что можете, пробуйте Navigation Preload, не используйте SW для "галочки" - браузер и так отлично все кэширует
- Раздутый HTML и плохой интернет - это значительная проблема для SSR, которую трудно исправить малыми усилиями
Круто, что есть много браузерных API для мониторинга таких деталей.
Про разработку.
Запланированные процессы такие:
- один разработчик пишет бэк, один фронт- до разработки, создается задача на конкретный небольшой функционал
- бэк пишет Open API схему и тест кейсы до реализации, на этом этапе асинхронно ревью/приемка заказчиком
- фронт накидывает мокапы и тест кейсы до реализации, на этом этапе асинхронно ревью/приемка заказчиком
- фронт получает сгенерированные API клиенты + моки от бэка до реализации
- реализация обязательно с тестами (Mostly integration!)
И если с тестами нам очень помогают коллеги, в том числе QA-инженер (отсутствует в нашей команде), сильно недооценили работу по дизайну, делать хорошие мокапы сложно даже при наличии кита и каких-то гайдлайнов, поэтому в асинхронном режиме будем привлекать дизайнера (отсутствует в нашей команде).
Также, большой объем работы потребовался на изначальную настройку инфраструктуры, это и тестовое окружение, Allure, генераторы клиентов и моков, CI/CD, и многое другое.
Поэтому процессы еще совсем не прошли проверку временем.
История далека от завершения, но очень надеюсь в следующих постах затронуть сторонние темы, и возвращаться тут к MF Platform по мере возникновения интересных инсайтов, точно будет что рассказать по SRE (платформу будут использовать критичные сервисы, что подразумевает высокие требования к доступности и поддержке).
Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 2 weeks, 2 days ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month ago