Утечки памяти в JS: почему фронтенд тормозит со временем
Долгоживущие вкладки часто тормозят из-за мелких ссылок, которые не дают сборщику мусора освободить память. В JavaScript объект живёт, пока на него остаётся ссылка, и удаление последней ссылки отправляет его в следующий проход сборщика мусора.
Чаще всего утечки дают забытые таймеры и обработчики событий, отсоединённые DOM-узлы, оставшиеся в массивах, и глобальные переменные без
Проверить проще, чем кажется: в Chrome DevTools вкладка Memory покажет снимок кучи и найдёт объекты, которые висят дольше положенного. А для метаданных объектов посмотрите на
Долгоживущие вкладки часто тормозят из-за мелких ссылок, которые не дают сборщику мусора освободить память. В JavaScript объект живёт, пока на него остаётся ссылка, и удаление последней ссылки отправляет его в следующий проход сборщика мусора.
Чаще всего утечки дают забытые таймеры и обработчики событий, отсоединённые DOM-узлы, оставшиеся в массивах, и глобальные переменные без
let, const или var. Замыкания тоже держат ссылки дольше, чем нужно.Проверить проще, чем кажется: в Chrome DevTools вкладка Memory покажет снимок кучи и найдёт объекты, которые висят дольше положенного. А для метаданных объектов посмотрите на
WeakMap: при удалении основной ссылки данные уйдут вместе с ней. Подробнее в азборе от Sharique Siddiqui.❤3
Выбираем менеджер пакетов
При десятке JS/TS-проектов вопрос — не «кто быстрее ставит», а «кто не раздует node_modules и не даст импортнуть левое». Автор сравнения оценил npm, Yarn, pnpm и Bun по этому критерию.
Разбор по ссылке.
При десятке JS/TS-проектов вопрос — не «кто быстрее ставит», а «кто не раздует node_modules и не даст импортнуть левое». Автор сравнения оценил npm, Yarn, pnpm и Bun по этому критерию.
Разбор по ссылке.
👍5❤2👎2
React не следит за фокусом — useFocus из @reactuses/core делает это за него
В React нет состояния, которое говорит, активно ли сейчас поле ввода.
Хук
Для подсветки рамки хватит CSS
Я бы сохранил его для форм и модалок, где фокус важен для UX, а не только для стилей. Разобрали в статье.
В React нет состояния, которое говорит, активно ли сейчас поле ввода.
document.activeElement показывает ответ, но не перерендеривает компонент при смене фокуса, а autoFocus стреляет один раз и не даёт вернуть фокус программно. Приходится вешать onFocus и onBlur вручную.Хук
useFocus из @reactuses/core сворачивает это в [isFocused, setFocused]: первая часть отражает реальное состояние элемента, вторая вызывает focus() или blur() по вашей логике. Например, при программном фокусе на поиске.Для подсветки рамки хватит CSS
:focus, но как только фокус начинает управлять JSX через подсказки, плавающие лейблы или паузу тикера, хук убирает шаблонный код.Я бы сохранил его для форм и модалок, где фокус важен для UX, а не только для стилей. Разобрали в статье.
👍6❤2👎1
JWT-аутентификация: лучшие практики
LogRocket разобрал, как не уронить безопасность аутентификации одним неверным решением. Их вывод простой: access короткоживущий и живёт в оперативной памяти, а refresh длинноживущий — прячется в httpOnly-куках, куда JavaScript не достаёт. Даже при XSS атакующий получит только короткий токен, а не ключ к бесконечному входу.
В статье есть и менее очевидные моменты. Если сейчас проектируете аутентификацию или проверяете текущую схему, рекомендую разбор по ссылке.
LogRocket разобрал, как не уронить безопасность аутентификации одним неверным решением. Их вывод простой: access короткоживущий и живёт в оперативной памяти, а refresh длинноживущий — прячется в httpOnly-куках, куда JavaScript не достаёт. Даже при XSS атакующий получит только короткий токен, а не ключ к бесконечному входу.
В статье есть и менее очевидные моменты. Если сейчас проектируете аутентификацию или проверяете текущую схему, рекомендую разбор по ссылке.
👍3❤1
Он не был в отпуске с того самого релиза, который «вот-вот стабилизируется». Пришло время отправить Типичного Программиста в отпуск!
В новой мини-игре нужно откопать разработчика, найти билет, сложить чемодан и подобрать гардероб, в котором не три одинаковые чёрные футболки. Спойлер: он всё равно попытается запихнуть ноутбук в чемодан. Ваша задача — чтобы шорты тоже влезли. Найдите все пасхалки от партнёров и помогите разрабу уйти в отпуск со спокойной душой!
Играть → https://tprg.ru/SEVh
В новой мини-игре нужно откопать разработчика, найти билет, сложить чемодан и подобрать гардероб, в котором не три одинаковые чёрные футболки. Спойлер: он всё равно попытается запихнуть ноутбук в чемодан. Ваша задача — чтобы шорты тоже влезли. Найдите все пасхалки от партнёров и помогите разрабу уйти в отпуск со спокойной душой!
Играть → https://tprg.ru/SEVh
❤1
Forwarded from Типичный программист
Делаем из плоского фото 3D-сцену со светом и тенями
В новом туториале Codrops Dominik Fojcik показывает, как обычное 2D-изображение начинает отбрасывать настоящие тени: без 3D-модели, одной текстурой. Берёте картинку, генерируете карту глубины и пропускаете свет через WebGPU-шейдер в Three.js.
Фишка в том, что готовые карты глубины обычно 8-битные, всего 256 градаций, и на гладких поверхностях свет ловит ступеньки. Автор же разбирает, как конвертировать карту в float, слегка размыть и сохранить в half-float, чтобы шум исчез.
Работает пока только где есть WebGPU. Пошаговый туториал на Codrops.
В новом туториале Codrops Dominik Fojcik показывает, как обычное 2D-изображение начинает отбрасывать настоящие тени: без 3D-модели, одной текстурой. Берёте картинку, генерируете карту глубины и пропускаете свет через WebGPU-шейдер в Three.js.
Фишка в том, что готовые карты глубины обычно 8-битные, всего 256 градаций, и на гладких поверхностях свет ловит ступеньки. Автор же разбирает, как конвертировать карту в float, слегка размыть и сохранить в half-float, чтобы шум исчез.
Работает пока только где есть WebGPU. Пошаговый туториал на Codrops.
❤2🤔2🔥1
Один Vue-фронтенд для десктоп, Android и веб
Одна кодовая база, а на выходе программа для Windows, macOS и Linux, сборка для Android и обычный сайт. Так автор и собрал клиент Reddit: Tauri заворачивает фронтенд в десктоп, Capacitor в Android, а он же открывается как сайт.
За таким решением прячутся четыре счёта. Собрать .msi на маке не выйдет: Tauri опирается на нативный тулчейн каждой системы. На старых Windows программа может открыться белым окном. Дефолтный release-бинарник Rust выходит толстым. А с авторизацией вышла отдельная боль: в браузере OAuth возвращает пользователя на callback-адрес, а в упакованном виде отвечать по нему некому.
Подробности на dev.to.
Одна кодовая база, а на выходе программа для Windows, macOS и Linux, сборка для Android и обычный сайт. Так автор и собрал клиент Reddit: Tauri заворачивает фронтенд в десктоп, Capacitor в Android, а он же открывается как сайт.
За таким решением прячутся четыре счёта. Собрать .msi на маке не выйдет: Tauri опирается на нативный тулчейн каждой системы. На старых Windows программа может открыться белым окном. Дефолтный release-бинарник Rust выходит толстым. А с авторизацией вышла отдельная боль: в браузере OAuth возвращает пользователя на callback-адрес, а в упакованном виде отвечать по нему некому.
Подробности на dev.to.
👍5😁4
Вместо списка из .btn-primary, .btn-secondary и .btn-danger в CSS появится один .btn-*
Чтобы задать общий стиль всем кнопкам, сегодня приходится перечислять классы через запятую или вешать в разметку лишний общий класс. На августовской встрече рабочей группы CSS в Берлине приняли Class Prefix Selector:
Но радоваться рано: фича живёт только в тексте спецификации, ни один браузер её пока не умеет, и до реализации синтаксис ещё поменяется.
#css
Чтобы задать общий стиль всем кнопкам, сегодня приходится перечислять классы через запятую или вешать в разметку лишний общий класс. На августовской встрече рабочей группы CSS в Берлине приняли Class Prefix Selector:
.btn-* цепляет любой класс, начинающийся с этого префикса. Идею предложила Лея Веру ещё в 2024 году.Но радоваться рано: фича живёт только в тексте спецификации, ни один браузер её пока не умеет, и до реализации синтаксис ещё поменяется.
#css
👍7❤3🤩3
Что делать, если участники команды видят только свой участок работы, десятиминутный дейли незаметно растягивается на час, а стопперы всплывают слишком поздно, чтобы успеть на них среагировать? В статье смотрим на работу команды и путь задач от бэклога до релиза, и думаем какие коммуникации действительно нужны в этом процессе.
Отдельно о том, что именно должен проверить разработчик перед первым коммитом и как устроены quality gates перед выпуском версии в прод.
Отдельно о том, что именно должен проверить разработчик перед первым коммитом и как устроены quality gates перед выпуском версии в прод.
❤3👍3
JPEG XL к концу года будет во всех браузерах
Firefox опубликовал intent to ship, Chrome тоже собирается включить формат, у Safari частичная поддержка с 2023 года. За флагом в Firefox JPEG XL жил с 2021-го, но 100 000 строк многопоточного C++ в декодере сочли опасной поверхностью атаки. Mozilla предложила Google Research написать декодер на Rust, так появился
Главный аргумент за формат, по Джейку Арчибальду, прогрессивный рендеринг: картинка в 135 КБ узнаваема после первых килобайт. В Safari этого нет.
По размерам картина смешанная. Фото в вебовском качестве: AVIF 116 КБ против 134 у JPEG XL при SSIMULACRA 2 = 62,8. Без потерь впереди JPEG XL: 1,45 МБ против 1,76 у AVIF и 1,55 у WebP; скриншот 92 КБ против 164. Старые JPEG пережимаются в JPEG XL без потери качества.
Я бы прогнал свой набор картинок через оба кодека. Демо работает в Firefox Nightly, разбор с примерами у Mozilla.
#браузеры #перформанс
Firefox опубликовал intent to ship, Chrome тоже собирается включить формат, у Safari частичная поддержка с 2023 года. За флагом в Firefox JPEG XL жил с 2021-го, но 100 000 строк многопоточного C++ в декодере сочли опасной поверхностью атаки. Mozilla предложила Google Research написать декодер на Rust, так появился
jxl-rs, на нём держится реализация в Firefox.Главный аргумент за формат, по Джейку Арчибальду, прогрессивный рендеринг: картинка в 135 КБ узнаваема после первых килобайт. В Safari этого нет.
По размерам картина смешанная. Фото в вебовском качестве: AVIF 116 КБ против 134 у JPEG XL при SSIMULACRA 2 = 62,8. Без потерь впереди JPEG XL: 1,45 МБ против 1,76 у AVIF и 1,55 у WebP; скриншот 92 КБ против 164. Старые JPEG пережимаются в JPEG XL без потери качества.
Я бы прогнал свой набор картинок через оба кодека. Демо работает в Firefox Nightly, разбор с примерами у Mozilla.
#браузеры #перформанс
👍3❤1
Chrome 152: закрыть диалог кликом по подложке без вычисления координат
Раньше для «закрыть модалку при клике мимо» ловили клик на
Вторая новинка — CPU Performance API: возвращает «tier» производительности процессора, чтобы снижать детализацию графики на слабых устройствах; работает в связке с Compute Pressure API. Пользователь и админ могут переопределить уровень (политика
Третья — заголовок
Рейчел Эндрю собрала релиз по пунктам; origin trial Connection Allowlists шёл с Chrome 148 по 151, в 152 заголовок включён по умолчанию.
#браузеры #javascript #безопасность
Раньше для «закрыть модалку при клике мимо» ловили клик на
dialog и сверяли getBoundingClientRect с курсором. Теперь CSSPseudoElement в JavaScript, кроме ::before, ::after и ::marker, отдаёт ::backdrop, ::scroll-marker и ::view-transition. Клик по подложке становится обычным событием.Вторая новинка — CPU Performance API: возвращает «tier» производительности процессора, чтобы снижать детализацию графики на слабых устройствах; работает в связке с Compute Pressure API. Пользователь и админ могут переопределить уровень (политика
CpuPerformanceTierOverride), так что значение не истина.Третья — заголовок
Connection-Allowlist: список URL-паттернов, куда документу и его воркерам разрешено ходить. Браузер сам режет остальные исходящие запросы, включая те, что делают сторонние скрипты.Рейчел Эндрю собрала релиз по пунктам; origin trial Connection Allowlists шёл с Chrome 148 по 151, в 152 заголовок включён по умолчанию.
#браузеры #javascript #безопасность
❤2👍2
Safari расширяет случайность в CSS: random-item() и random() в custom properties
Сегодня WebKit выложил Safari Technology Preview 251.
Из той же сборки стоит примерить:
В JavaScript главное
Полный список в заметках к релизу.
#браузеры #css #javascript
Сегодня WebKit выложил Safari Technology Preview 251.
random() в Safari уже есть со стабильной 26.2, а теперь добавились random-item() для выбора из списка значений, random() внутри custom properties и ключевые слова кеширования property-scoped и property-index-scoped. Разброс блоков в галерее и вариации анимаций описываются в CSS без скрипта с инлайн-стилями.Из той же сборки стоит примерить:
corner-shape (скошенные и вогнутые углы поверх border-radius), @supports at-rule(...) и popover=hint для подсказок, которые не закрывают другие поповеры.В JavaScript главное
import defer: модуль грузится сразу, а выполняется при первом обращении, это ускорение старта без ленивых import(). Плюс Iterator.zip(), chunks(), windows() и WebAssembly Memory64. Убрали процентное значение -webkit-line-clamp: если оно есть в вашем CSS, вёрстка поедет.Полный список в заметках к релизу.
#браузеры #css #javascript
👍2❤1
Строгий CSP и nginx без пары заголовков ломают WebAssembly на проде
Распознавание паспорта в браузере без отправки фото на сервер делается WASM-модулем. У Smart ID Engine четыре сборки (
Серверные ловушки:
Камера: документу нужно не меньше 120 DPI, оптимальный кадр 1600×1200, веб-камерам ноутбуков на А4 разрешения не хватает, на трёхкамерных iPhone основной модуль не фокусируется ближе 20 см. Android и iOS стартуют камеру в разной ориентации, сверяйте
Пошаговая интеграция с конфигами для
#wasm #браузеры
Распознавание паспорта в браузере без отправки фото на сервер делается WASM-модулем. У Smart ID Engine четыре сборки (
nosimd.nothreads, simd.nothreads, simd.threads, nosimd.threads), нужную выбирают на лету через wasm-feature-detect. SIMD без потоков работает в Safari 17.1+, Chrome 91+ и Firefox 89+.Серверные ловушки:
.wasm отдаётся с Content-Type: application/wasm и сжимается; строгая CSP блокирует JIT, нужна директива wasm-unsafe-eval; многопоточная сборка требует COOP: same-origin и COEP: require-corp.Камера: документу нужно не меньше 120 DPI, оптимальный кадр 1600×1200, веб-камерам ноутбуков на А4 разрешения не хватает, на трёхкамерных iPhone основной модуль не фокусируется ближе 20 см. Android и iOS стартуют камеру в разной ориентации, сверяйте
matchMedia.Пошаговая интеграция с конфигами для
getUserMedia, CSP и nginx.#wasm #браузеры
❤3
Бэкенд для приложения в одном исполняемом файле
PocketBase — это один бинарник, внутри которого сразу SQLite, авторизация пользователей, хранение файлов, REST API, подписки в реальном времени и админка. Ни отдельной базы, ни очереди рядом ставить не нужно: приложение живёт одним файлом на одной машине.
23 августа вышла версия 0.40.0: удаление логов через
В нашем канале «Инструменты программиста» разобрали подробнее, чем PocketBase берёт против Supabase и где ломается совместимость.
PocketBase — это один бинарник, внутри которого сразу SQLite, авторизация пользователей, хранение файлов, REST API, подписки в реальном времени и админка. Ни отдельной базы, ни очереди рядом ставить не нужно: приложение живёт одним файлом на одной машине.
23 августа вышла версия 0.40.0: удаление логов через
DELETE /api/logs, ограничение размера Log.Data примерно 16 килобайтами, Cross-Origin-Opener-Policy: same-origin в заголовках по умолчанию. Порог входа при этом поднялся до Go 1.27.В нашем канале «Инструменты программиста» разобрали подробнее, чем PocketBase берёт против Supabase и где ломается совместимость.
❤1👍1
Плавающий виджет поверх всех окон одним вызовом API
Firefox 151 включил Document Picture-in-Picture API, до этого он был только в Chrome. В отличие от PiP для видео,
CSS-Tricks разобрал API на примере тикера акций. Стили в новое окно не наследуются:
#браузеры #css #javascript
Firefox 151 включил Document Picture-in-Picture API, до этого он был только в Chrome. В отличие от PiP для видео,
documentPictureInPicture.requestWindow() открывает окно поверх вкладок и других приложений с любым HTML внутри: тикер, чат, таймер, заметки. Раньше это требовало расширения или Electron.CSS-Tricks разобрал API на примере тикера акций. Стили в новое окно не наследуются:
<style> и <link rel=stylesheet> клонируют через querySelectorAll() в createDocumentFragment() и одним append кладут в <head>. Ширину и высоту задают только парой, иначе размер выбирает браузер. Фокус уходит в PiP-окно, поэтому кнопка-переключатель закрывает его со второго клика.@supports не поможет: at-rule() есть только в Chrome, остаётся "documentPictureInPicture" in window и скрытие кнопки. Стили под окно пишут через @media (display-mode: picture-in-picture). Только десктоп, Safari мимо, в iframe не запускается.#браузеры #css #javascript
❤1👍1
WebGPU в Unity вышел из эксперимента
Начиная с версии 6000.6 WebGPU в Unity — полноценный графический бэкенд с обычной поддержкой, а не экспериментальная опция. Для браузера это вычислительные шейдеры, а с ними отсечение невидимого на GPU, апскейлер STP, VFX Graph на миллионы частиц и скиннинг на GPU: на WebGL 2 всё это было недоступно.
Ловушка при выкладке чисто веб-разработческая: WebGPU браузер отдаёт только в защищённом контексте, поэтому сборка, открытая по обычному HTTP или файлом с диска, молча откатится на WebGL 2.
В нашем канале «GameDev» разобрали подробнее, как его включить и почему WebGL 2 нельзя убирать из списка.
Начиная с версии 6000.6 WebGPU в Unity — полноценный графический бэкенд с обычной поддержкой, а не экспериментальная опция. Для браузера это вычислительные шейдеры, а с ними отсечение невидимого на GPU, апскейлер STP, VFX Graph на миллионы частиц и скиннинг на GPU: на WebGL 2 всё это было недоступно.
Ловушка при выкладке чисто веб-разработческая: WebGPU браузер отдаёт только в защищённом контексте, поэтому сборка, открытая по обычному HTTP или файлом с диска, молча откатится на WebGL 2.
В нашем канале «GameDev» разобрали подробнее, как его включить и почему WebGL 2 нельзя убирать из списка.
❤3
Разница между «у нас есть бэкап» и «мы готовы к аварии» — примерно как между наличием огнетушителя и умением им пользоваться при пожаре. Первое не гарантирует второе, а узнают об этом обычно в момент, когда сервис лежит у всех на глазах, включая руководство и клиентов. На самом деле готовность инфраструктуры к сбою определяет не факт хранения копий, а расчёт допустимого времени простоя, структура плана восстановления и техническая настройка репликации, которую проверяют заранее регулярными учениями переключения на резервную площадку. Будет полезно инфраструктурным инженерам, техлидам и руководителям, которые хотят сделать свои системы реально устойчивыми к авариям.
Больше об аварийном восстановлении:
1. Почему бэкап есть, а восстановиться не получится: разбор точек отказа
2. Как должен выглядеть DR-план, который сработает в аварию
3. Аварийное восстановление до аварии: как настроить DRaaS, пока ничего не упало
Больше об аварийном восстановлении:
1. Почему бэкап есть, а восстановиться не получится: разбор точек отказа
2. Как должен выглядеть DR-план, который сработает в аварию
3. Аварийное восстановление до аварии: как настроить DRaaS, пока ничего не упало
❤1