- Последний пост
- 4 апр. 2025 г.
- Последнее чтение
- 13 авг.
- Постов за неделю
- 0
- Всего постов
- 21
- Тип
- открытый
- Язык
- русский
- В каталоге с
- 13 авг.
- 1/24сутки в ленте
- —
- 1/48двое суток
- —
- 1/72трое суток
- —
Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.
Посты
Здравствуйте, а вы точно фронтендер? Сейчас занимаюсь исследовательской работой по утечкам памяти в NextJS, а именно пытаюсь найти дыру в кэше модуля оптимизатора картинок NextImage. Временное решение есть: мой коллега написал патч для NextJs, который отключает…
Очередная история глупости, про CI и регистрозависимость, почувствовал себя тупым, хехе. 🎧 Что произошло - У коллег в одном из проектов упала джоба ESLint на CI. - На тачке всё отлично. - На локальном ранере CI в докере тоже всё в порядке. Проблема 1. Сначала я подумал что дело в кэше ESLint, отключил его в джобе – дело не в нем. 2. Начал смотреть что могло быть не так с плагинами – может как-то повлияло обновление до ESLint 9. Но дело не в этом. 3. И тут я решил посмотреть что изменилось в МР более детально... Запустил билд и меня смутила ошибка Module not found: Can't resolve MySupername Решение Оказалось что в МР файлы MySuperName были переименованы в MySupername через VS Code и Git не зафиксировал изменение регистра. - Поэтому в регистронезависимой macOS всё работало и локально, и на локальном раннере CI в докере. - А на раннерах CI в регистрозависимом Linux ESLint не находил файлы по ожидаемым путям. Написал скрипт, который нашёл файлы с неправильным регистром и переименовал их через git mv. Закоммитил, пушнул, проблема исчезла. Вывод Неожиданный сайд-эффект скрасил мой день. Даааа, это классические тупые грабли, вот тут сборник решений. P.S. Пользуйтесь WebStorm, он автоматически такие вещи из коробки делает, в отличие от VS Code! 😆 P.P.S. Кстати, в молодости, когда писал код в блокноте использовал git config core.ignorecase false 😎
Обновлял тут Vitest до 3 версии. Орнул что теперь для fake timers нужно явно указывать Date (ссылка). Из-за этого могут возникать мелкие расхождения, как 0.001 vs 0.002 сек. Чтобы вернуть старое поведение, нужно добавить Date в список toFake. Ну и дурка. vi.useFakeTimers({ toFake: [ 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setImmediate', 'clearImmediate', 'Date', ], }); Не понимаю смысла/мотивации этого изменения. Типа они хотят повысить контроль над замоканными API? Якобы раньше всё подменялось автоматически, что могло вызывать "неожиданные эффекты". Какие? А теперь мы сами решаем, какие именно таймеры нужно мокать, и якобы это делает тесты более предсказуемыми и гибкими. А на мой взгляд это несет только лишние сложности.
Мне нравится изучать новые технологии и инструменты с целью просто потрогать для кругозора до потенциального внедрения в проект. Но как сделать осознанный выбор и минимизировать риски, где та грань между хайповостью и (не)стабильностью? 💅 Вариант 1. Можно сформировать техрадар, и выделить несколько уровней. - Adopt: Проверенные технологии, которые мы уверенно используем и которые работают в критичных проектах. - Trial: Эффективные инструменты, уже применяемые в MVP или менее нагруженных решениях. - Assess: Интересные идеи, которые мы пробуем в пет-проектах, но в прод пока не выводим. - Hold: Устаревшие технологии, которые мы поддерживаем для legacy, но больше не пишем на них. Вариант 2. Frontend Architecture Map – метод помогает выбирать инструменты, исходя из реальных User Story, а не модных трендов. Мне понравилась аналогия с напитками: энергетики дают быстрый «взлёт», но потом наступает спад, а вот вода (или пиво) – стабильный источник энергии. Как это работает на практике? Разбиваем путь пользователя на этапы и подбираем технологии, которые оптимально решают конкретные задачи. Попробуем на примере сайта банка. Что у нас есть? 1. Статичные разделы Для лендингов используем Gatsby, чтобы генерировать статику. Быстрая загрузка страниц и минимальная нагрузка на сервер. 2. Личный кабинет пользователя Страница с балансом, историей транзакций и графиками расходов. Первичная загрузка идёт через SSR в Next.js, а для динамичных обновлений используем клиентские запросы. Такой гибрид позволит сразу показать контент и поддерживать актуальность данных. 3. Чат с поддержкой Для связи с поддержкой банка используем веб-сокеты, чтобы пользователи получали ответы в режиме реального времени. ВЫ ВОДЫ: их нет, баланс между хайпом и стабильностью очень хрупок. Но было бы интересно обсудить с вами ваш опыт и критерии формирования стека технологий для проектов. 💅
Ты обновил Node.js? Я волнуюсь Поговорим об уязвимостях. Например, CVE-2023-32002, где уровень опасности критический из-за удаленного выполнения кода (RCE). Уязвимость была в функции Module._load(), которая отвечает за загрузку модулей что открывает большой простор для утечек, подмены данных и т.д. Версии с исправлениями Node.js: 16.20.1+, 18.17.0+ или 20.5.0+. Вижу несколько стратегий: - Почитывать Node.js vulnerability blog - Подписаться на рассылку nodejs-sec - Настроить DevSecOps-проверки вроде gemnasium - Подтюнить SonarQube, а именно Security Hotspot - Настроить регулярные обновления Renovate / Dependabot - Настроить базовый образ для CI, который всегда будет брать latest LTS - Ждать серьезных дядь из КБ которые заставят обновить ноду 😎 Расскажите, как у вас устроен процесс реагирования на CVE? 🚀
Оптимизатор Оптимизатора Дамы и господа! Вашему вниманию предоставляется уникальная возможность воспользоваться новой утилитой для экономии денежек при развёртывании NextJS! Встречайте: элегантный и миниатюрный скрипт по очистке кэша изображений модуля Image Optimizer, который вы можете запустить в отдельном контейнере вашего кубернетис (и не только) кластера, чтобы избавить ваш мониторинг ресурсов от неверных показателей! 💣 next-image-cache-cleaner 💣 Часть расследования «а зачем вообще потребовалось данное решение?» я описывал в предыдущих постах. И сейчас самое время подытожить, куда же *течёт на самом деле память фреймвока NextJS? Барабанная дробь… ответ: «никуда» 🥱 . Как бы странно это не звучало, но это горькая правда. Картина, которую мы с вами наблюдали - это ни что иное, как накопление файлового кэша в памяти ОС Linux. Как оказалось, при создании новых файлов/директорий ОС Linux в дополнение к файлу также создаётся index node (Inode - это метаданные о файле: права доступа, владелец, размеры, временные метки и прочее, подробнее на kernel.org) Далее записываемые данные попадают сначала в page cache — буфер памяти, управляемый ядром, для временного хранения данных, прежде чем они будут сброшены на диск. И этот буфер памяти будет поглощать место под кэш настолько много, насколько это возможно. Видите ли, таким образом достигаются оптимизации по чтению и записи (чтобы не дрочить ваш физический накопитель каждый раз, когда вы совершаете множество CRUD операций в файловой системе 😐 ). В обычном «домашнем» использовании, когда запущены десятки программ и сервисов, мы не ощущаем этого эффекта накопления на персональных компьютерах, потому что на оперативную память всегда оказывается конкурентное давление других процессов. А в кластере у нас чаще всего приложение изолировано и ничего не мешает ему раздуваться, картину портит ещё то, что контейнер видит всю память кластера, а не ту, которую вы указали в лимитах пода. Ну и представьте — что такое лишние 500-1000 Мб оперативы, когда в запасе ещё 100+ Гб? Да, в ядре есть флажки, которыми можно в хост-системе переопределить правила, как утилизировать этот кэш, но есть большая вероятность, что вы просто выстрелите себе в ногу этими экспериментами и жёстко уроните производительность всей тачки. 🔫 Подробнее про использование RAM в Линус можете прочитать в статье "Help! Linux ate my ram!" Дело закрыто! 🧑⚖️ Если эта информация вам было полезна, то расчехлите свою звёздочку на GitHub в моём репозитории со скриптом (если будут вопросы, как оно работает, приходите в комментарии, всё расскажу) Давайте продвинем эту тему и поможем бедолагам, которые столкнулись с такой же проблемой 🚀
В пятницу выступил на конференции Dump SPB с докладом про CI во фронтенде. Спасибо организаторам, всё прошло довольно лампово и мило. В последнее время я работал над курсом по инфраструктуре фронтенда (скоро анонс, кстати), и этот доклад – часть программы курса, смотрите, пользуйтесь, буду рад если кому-то пригодится мой опыт. Материалы: - Слайды - Демо - Запись выложу как только появится 💅
В этом канале я в основном пишу про инфраструктуру фронтенда — CI/CD, тестирование, архитектуру. При этом стараюсь держать руку на пульсе и следить за тем, что происходит в мире фронтенда. Один из способов — посещать профильные конференции. Одна из таких – это Podlodka React Crew, которая пройдет с 10 по 14 февраля. Вот некоторые из тем: - React 19 — что нового, что в итоге не завезли и что ждать в будущем. - React Server Components и Compiler — тренды, которые уже внедряют в продакшн. - OpenTelemetry и Observability — про метрики, логи и трассировки. Лично мне особенно интересно. - Ну и конечно тема AI в разработке — куда без этого? - Больше тем — в полной программе по ссылке. Формат удобный: доклады утром и вечером, можно совмещать с работой. Цена радует глаз, а промокод react_crew_2_WhogW0 со скидкой 500 рублей сделает её еще приятнее. 🔗 Регистрация: podlodka.io/reactcrew
Здравствуйте, а вы точно фронтендер? Сейчас занимаюсь исследовательской работой по утечкам памяти в NextJS, а именно пытаюсь найти дыру в кэше модуля оптимизатора картинок NextImage. Временное решение есть: мой коллега написал патч для NextJs, который отключает кэш, но сохраняет оптимизацию. Минус такого подхода: увеличенное потребление CPU, так как оптимизатор работает на каждый запрос изображения. Если у вас нет S3 корзинки - вашим денежкам на счёте в клауде кранты 🔫 (у нас корзинка есть, поэтому «хилимся — живём!») Кратко о механизме работы оптимизатора: прилетает GET запрос /_next/image*, картинку прогоняет через библиотеку Sharp, новая картинка сохраняется на диск с хитрым именем папки и файла и далее возвращается клиенту. Имя содержит срок жизни кэша, расширение и какой-то etag в формате base64. Это нужно, чтобы не держать в памяти процесса некста мапу ссылок на файлы. (URL на изображение у вас на сайте персистентный во времени, значит можно восстановится по значению ссылки через хэш-функцию). Звучит здраво, технологично, но эта мразь где-то течёт! Причём обычным Heap Profiler’ом вы эту утечку не поймаете. У меня на графике потребления ресурсов сожрало уже гигабайт, а куча (heap) как была 100 мегабайт, так и осталась. После нескольких суток безуспешных попыток собрать хоть какие-то полезные метрики, берём таймаут на вечер, чтобы прийти в себя, выпить пивка и признаться, что десятки часов были потрачены впустую и надо менять методику исследования. 🤨 Важно! Если вы уже на этом моменте столкнулись с отчаянием, напоминаю, что курьером сегодня можно заработать столько же, сколько мы получаем в айтишке, так что вы точно ещё пригодитесь этому миру и не помрёте с голода. Далее мы заходим внутрь докер контейнера, где запущен сервер и начинаем эксперименты по снятию дампов памяти в ОС Linux, а также с различными утилитами по типу htop, видим кучу непонятных значений, которые описывают состояние оперативной памяти. Среди них только одно значение растёт характерно нашим графикам и оно называется RES. RES/RSS (Resident Set Size) — это объём физической памяти (RAM), который процесс фактически занимает в данный момент. Он включает: 1. Страницы памяти, которые в настоящее время загружены в RAM. 2. Память, используемую разделяемыми библиотеками, при условии, что эти библиотеки всё ещё находятся в памяти. Это может означать, что ту память, которую я выделял для чтения и записи буфера на диск, могут использовать какие-то другие процессы, а не только сервер NextJs. (Напоминаю, что патч, сохраняющий оптимизацию, решает проблему утечек). Методом исключения можно предположить, что возможно у нас накапливаются незакрытые дескрипторы для оптимизированных файлов изображений, так как это не процессы. А если удалить папку с кэшем, то буквально через минуту график потребляемой памяти летит вниз до нормальных ожидаемых значений. 📉 История обрывается на самом интересном месте, потому что на текущий момент это всё что я могу рассказать, моих знаний сейчас недостаточно, чтобы быстро вкурить, как это всё работает на самом деле. 😠 Желаю вам всем хорошего дня, а я ушёл читать документацию и статьи о работе Linux систем! Клянусь, если я смогу разобраться, то подамся на все конференции в этом году, чтобы рассказать про этот инженерный ад! Может даже и pr в next сделаю, если получится фикс изящный придумать. Фух блять, а я ведь просто когда-то хотел красить кнопки и пить смузи из чертополоха… видите, я уже даже забыл, что там рядовые работяги употребляют на обеде 😐
Вышел Vitest 3.0. Что интересного в релизе? - Inline Workspace – ура, этого я прям ждал, потому что для монореп приходилось немного костылить. - Multi-Browser Configuration – круто, теперь можно запускать тесты сразу в нескольких браузерах в рамках одного Vitest-процесса. - Обновление репортера – просто стал меньше "мигать". Есть некоторые Breaking changes, подробности тут. Я люблю Vitest, т.к. мой developer experience поменялся в очень положительную сторону после миграции с Jest.
Как модель GPT-o1 помогла мне не суициднуться Бывает сталкиваешься с ситуацией, когда разработчики откровенно хуево поработали над документацией, а фичу с интеграцией их творения делать надо. Со мной такая история произошла в прошлую пятницу. Дело в том, что я столкнулся с интеграцией OIDC сервиса SberID. Вроде сайтик для разработчиков красивый, а толку – ноль. Поставляют только подключаемый скрипт со своего CDN в минифицированном виде и дают примеры с настройкой SDK под разные кейсы авторизации. Если вы делаете свою аппку на typescript, то никакой типизации вы не получите! Они оставили это дело в далёком 2023, когда забросили поддержку своего GitHub аккаунта, тогда старую версию можно было установить через npm (мы понимаем, по каким причинам это было сделано, но неужели не нашлось никакой площадки для размещения сорсов??? В конце концов можно было рядом с продакшен скриптом положить архив, и дать возможность загрузить их его по отдельной ссылке) Я до последнего не понимал какая у меня сейчас версия активна в приложении, в связи с чем не мог понять, что я делаю не так. Масла в огонь подлил их механизм обработки ошибок: вместо того, чтобы сообщить мне прямым текстом, что было не так с моим запросом, они мне дают код ошибки формата «73b800hwa871lop» и предлагают написать им на почту!!! 💩 «Ладно, хер с ним!» – подумал я, и мне в голову пришла авантюра: • Загружаем всё содержимое страниц документации в модель chat-gpt o1 • Загружаем содержимое минифицированного скрипта sdk Далее просим выступить в роли разработчика ПО и провести реверс-инжиниринг работы кода, после полученную информацию соотнести с содержимым документации, которую я ему предоставил. Первый раз анализ благополучно погиб через 7 секунд анализа (возможно у них был перегруз инфры и случилась внутренняя ошибка). Но дальше произошло невообразимое… Модель рассказала мне, как работает скрипт, какие есть потенциальные неточности в документации, и написала исправленные примеры использования. Я попробовал их, и, «о чудо!», у меня всё заработало! После я попросил оформить содержимое файла sberid.d.ts. Чат даже любезно расписал куда мне его добавить в конфиг, чтобы в IDE был автокомплит. Возможно, с нейронками мы деградируем со временем в ряде задач как специалисты, но подобные кейсы показывают, насколько эти инструменты могут быть полезны в работе! Это спасло мои нервные клетки, ведь теперь я смогу закрыть задачу почти в срок 🦍 Делитесь вашими историями в комментариях, какие нейронки используете и для чего, мб вы тоже были в похожей ситуации?
Нашел репозиторий со статистикой по долям ESM и CJS среди популярных npm-пакетов. Можно наглядно увидеть как продвигается переход на ESM. Но с оговоркой: данные приблизительные, есть неточности. Даны следующие категории: - ESM (например, type: "module" в package.json) - dual (одновременное использование import и require) - faux ESM (module в package.json, поддерживается старыми сборщиками) - CJS (всё остальное, кроме @types/*) На графике видно как CJS постепенно теряет долю, но лидирует с 63.7% в конце 2024 года по сравнению с 77.4% в 2021 году. ESM растёт – с 6% в 2021 году до 11.6% в 2024, но пока остаётся в меньшинстве. Dual-подход набирает популярность, увеличившись с 3.2% до 14.2%. Понятно что экосистема еще тормозит, например тот же Jest до сих пор не может в полноценную поддержку ESM. Но переход на ESM неизбежен. Если в проекте можно безопасно мигрировать, лучше начинать сейчас, чтобы не упереться в технический долг через пару лет. https://github.com/wooorm/npm-esm-vs-cjs
Потрогал аналог Statoscope – rsdoctor.dev Пока что Statoscope выглядит более зрелым решением. Но у rsdoctor есть несколько плюсов. 1. Он делается организацией Web Infra (они уже сделали rsbuild, modern.js, garfish), целью которой является создать открытую…
Посмотрел видео АйТи Синяка про кастомизацию компонентов в UI Kit. Итак, проблема – в UI-китах бывает очень много комбинаций компонентов (по типам, размерам, темам и нестандартным вариантам) что усложняет поддержку в будущем. Синяк предлагает использовать одно свойство variant для описания всех вариантов кнопок с объединением значений через тире чтобы сократить количество стилей и упростить поддержку, пример <Button variant='contained-10-primary' />. В целом, выглядит интересно, но я как мейнтейнер UI Kit в своей конторе вижу несколько проблем. Такой подход на корню убивает идею внешней стилизации. Ну и я не совсем понимаю как запоминать порядок аргументов – вижу семантическую проблему, но это мелочи. Вам необязательно зашивать в UI Kit все варианты дизайна. Как минимум это увеличивает нагрузку на платформенную команду, как максимум – ну какой смысл зашивать в ДС цвета для промо-лендинга розового цвета который будет жить квартал? В чем проблема, предоставить гибкую кастомизацию для потребителей? Скажем, такой base styless ui. Например, на промо-лендинге кнопка нужна вне цветов дизайн-системы — ок, прокинули кастомный стиль внутрь компонента и не запятнали ДС. Выглядеть это может примерно так. ⬇️
Мой тиммейт Вадим (@vadik_the_architect) записал видео про то как устроены серверные компоненты React (RSC) под капотом. Очень интересный формат, рекомендую к просмотру если хотели разобраться в хайповой теме. Подписывайтесь, ставьте лайки, будьте в модной теме. https://www.youtube.com/watch?v=hF3vx3yjC14
Возможно многие слышали мнение что Next.js идет не туда. Мне тоже есть что сказать по этому поводу, но стороны деплоя. На бекенде давно используются принцип универсальности сборок (или "build once, run everywhere") – когда один раз собиратся докер-образ, и на этапе деплоя подставляются необходимые переменные. Что же Next.js? А он не поддерживает этот принцип из-за особенностей работы с переменными окружения – например, переменные с префиксом NEXT_PUBLIC инлайнятся в клиентский код на этапе сборки. Возможно вы видели в своих докер-файлах тонны переменных окружения, которыми довольно сложно управлять. ARG NEXT_PUBLIC_BASE .... ARG NEXT_PUBLIC_CDN ARG NEXT_PUBLIC_LOG_LEVEL Проблема в том что для разных сред (development, staging, production) требуется пересборка проекта с соответствующими переменными окружения, что противоречит принципу универсальности сборок и замедляет время сборок. Вообще, рекомендую почитать это issue в Next – много боли. Так что же делать? В идеале из такого docker build -t app --build-arg NEXT_PUBLIC_BASE=test.com мы должны придти к docker run -e NEXT_PUBLIC_BASE=test.com app. Какие есть варианты? 1. Раньше был runtimeConfig, но подход устарел и не поддерживает Automatic Static Optimization, Standalone builds, React Server Components (RSC). 2. Судя по документации самого Next.js, можно использовать getServerSideProps или переходить на AppRouter. Но это всё равно не самое лучшее решение, т.к. требует некоторго оверхеда (писать мидлвари, ручку для отдачи ENV-переменных). 3. Недавно нашел библиотеку next-runtime-env и кажется, она закрывает все боли. По сути, она инжектит скрипт с переменными окружения в HTML на этапе рендеринга через свой кастомный компонент <PublicEnvScript />, таким образом появляется глобальный объект window['__ENV'] из которого можно получать значения. Это просто работает – не благодаря, а вопреки. Рекомендую попробовать – оверхед минимальный, внедряется очень просто. UPD: В комментах автор канала @unsleeping706 порекомендовал свою статью с с нюансами next-runtime-env. Спасибо! Нерешенные вопросы Со всеми этими решениями всё равно остается вопрос – а как быть быть со статическими настройками вроде assetPrefix для настройки CDN, который by design не может в рантайм? Если у вас есть идеи обходных путей, делитесь в комментариях. 🚀
У Gitlab Premium/Ultimate Edition есть классная фича контроля падения Coverage в МР. Для работяг с Enterprise Edition предлагаю такой хак – из отчета Cobertura достаем соотношение покрытых строк с непокрытыми, считаем процент и если он ниже целевого – фейлим джобу. Еще можно отправить коммент в МР через бота, кинуть алерт – это уже на вашу фантазию. variables: MIN_COVERAGE: 50 .coverage-check: script: - FILE="./coverage/cobertura-coverage.xml" - LINES_VALID=$(grep -o 'lines-valid="[^"]*"' "$FILE" | head -n 1 | sed -E 's/lines-valid="([^"]*)"/\1/') - LINES_COVERED=$(grep -o 'lines-covered="[^"]*"' "$FILE" | head -n 1 | sed -E 's/lines-covered="([^"]*)"/\1/') - COVERAGE_PERCENT=$(echo "scale=4; ($LINES_COVERED / $LINES_VALID) * 100" | bc) - IS_COVERAGE_FAILED=$(echo "scale=2; $COVERAGE_PERCENT < $MIN_COVERAGE" | bc) - | if [ "$IS_COVERAGE_FAILED" -eq 1 ]; then echo "Coverage упал ниже $MIN_COVERAGE%. Текущий уровень: $COVERAGE_PERCENT%"; exit 1; fi test: stage: check coverage: /^(?:Statements|Branches|Functions|Lines)\s*:\s*([^%]+)/ script: - yarn test:coverage - !reference [.coverage-check, script] Расскажите в комментариях, как вы следите за уровнем покрытия? #ci
Буду выступать на двух локальных конференциях. Тема: Быстрый, масштабируемый CI для фронтендера Описание: Расскажу как сократить код в CI, избежать дублирования и бойлерплейта. Особое внимание уделим ускорению джоб и стандартизации конфигураций. Тема будет полезна фронтенд-разработчикам и техлидам, желающим узнать больше о CI в специфике фронтенда. Ключевые вопросы: 📌 Как сократить код в CI? 📌 Как избежать дублирования и упростить поддержку пайплайнов? 📌 Как ускорить выполнение пайплайнов? 📌 Как стандартизировать конфигурации CI и масштабировать на разные проекты? Дата, место: - Краснодар, 26 октября: Krasnodar Frontend - Уфа, 9 ноября: UfaDevConf Буду рад видеть всех заинтересованных!
Мой коллега, Никита Любицкий, рассказал на прошедшем FrontendConf как мы в Звуке оптимизировали процесс код-ревью, с какими проблемами столкнулись и как пришли к своему мега-гига-боту (к разработке которого я причастен). Ждём видео, а пока можно полистать презентацию (прикреплена в комментах к посту Никиты). https://t.me/webambassador/29
Нашел имбовую штуку чтобы локально проверять пайплайны Gitlab CI. Кейс конечно специфичный, но может кому-то будет полезно. https://github.com/firecow/gitlab-ci-local