Веб-страница
22.2K subscribers
2.17K photos
559 videos
2 files
4.44K links
Всё по фронтенду, бэкенду и девопсу в одном месте

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Сайт: https://tprg.ru/site

Регистрация в перечне РКН: https://tprg.ru/64ai
Download Telegram
Firefox 155 добавил CSS-функцию progress() и Promise.allKeyed(), а на iOS браузер получил встроенный блокировщик рекламы

Для вёрстки главное: progress(value, start, end) возвращает долю от 0 до 1 между двумя границами, так что адаптивные размеры пишутся без ручного calc(); alpha() меняет прозрачность любого цвета; attr() теперь работает в любом свойстве, а не только в content; font-width заменил font-stretch, старое имя осталось псевдонимом.

В JavaScript появились Promise.allKeyed() и Promise.allSettledKeyed(): на вход объект с промисами, на выход объект с теми же ключами, без сопоставления по индексам. В сети добавили согласование QUIC v2 для HTTP/3, DevTools научились читать NDJSON построчно.

На iPhone у Firefox нет привычных расширений, поэтому Mozilla встроила блокировщик на Apple Content Blocker и EasyList прямо в настройки; выключен по умолчанию.

Примеры кода и список закрытых уязвимостей разобрали на сайте.

@tproger_web
❤3
Уберите тормозящую задержку из многоуровневого меню — её заменяет геометрия

Пользователь ведёт курсор по диагонали от пункта к подменю, задевает по дороге соседнюю строку, и содержимое переключается прямо под мышью. Обычное лечение — задержка перед сменой подменю, из-за которой интерфейс ощущается медленным. В большом меню Shop by Department на Amazon задержки нет, и промаха тоже.

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

Механизм разобрал Бен Кеймeнс в 2013 году и выпустил по мотивам плагин jQuery-menu-aim, который позже применили в меню Khan Academy. Приём описывает геометрию намерения пользователя, поэтому живёт дольше любой библиотеки.

#javascript #фронтенд
👍3❤1
Cloudflare начала отключать D1 на бесплатном плане после 5 млн прочитанных строк в сутки

С 1 сентября превышение дневного лимита на Workers Free больше не проходит незаметно: запросы к базе возвращают ошибки до полуночи UTC (03:00 МСК), данные не удаляются. Лимиты прежние: 5 млн прочитанных и 100 тысяч записанных строк в сутки, 5 ГБ хранилища. Изменился только режим: раньше мягко, теперь жёстко.

Ловушка в учёте: считаются строки, которые прошёл движок, а не строки в ответе. SELECT без индекса по таблице в 100 тысяч записей съедает 100 тысяч чтений за один вызов. Сколько реально прочитал запрос, D1 показывает в meta.rows_read.

Что сделать: пройтись EXPLAIN QUERY PLAN по частым запросам и добавить индексы там, где SCAN; кэшировать горячие ответы в KV; писать батчами, лимит записей в 50 раз меньше лимита чтений.

Тарифы платного плана и чек-лист собрали на сайте.

@tproger_web
❤2
Задайте источник света один раз, и все тени на странице посчитаются сами

Ambient CSS предлагает вместо ручных shadow-sm, shadow-md и shadow-lg описать свет: направление, интенсивность ключевого и заполняющего света, оттенок, высоту. Каждый элемент получает пятислойный box-shadow: тень, блики, фаски и внутренние затемнения, и все они согласованы между собой, потому что источник один.

У элемента задаётся только высота над поверхностью, elevation от 0 до 3, и толщина, thickness от 0 до 2. Пакет @ambientcss/css работает без зависимостей в любом HTML, есть отдельная обёртка для React. Автор выложил третью версию 1 сентября, на HN у неё 94 очка. В комментариях жалуются на мобильную версию демо, так что смотреть лучше с десктопа: ambientcss.vercel.app.

#css #фронтенд
🔥4❤1👍1
Август-сентябрь — сезон поиска работы, и в IT он сейчас особенно непростой. Не всегда понятно, в какую сторону расти, страшно менять профессию, а после нескольких неудачных собеседований начинает казаться, что дело в вас.

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

Куда двигаться:
Каких спецов сейчас не хватает
Куда расти, если не хочется в менеджмент
Как попасть в QA в 2026

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

Работа в новой компании и карьерный трек:
Что нужно знать про онбординг
Почему сеньоров не слышат
Как построить карьерный трек
Как определять грейды
Как измеряют вашу удовлетворённость работой
😁3
Manifest V2 закрыт окончательно: Google удалил из Chrome Web Store все старые расширения, включая uBlock Origin

Для авторов расширений новость не про блокировщик, а про режим совместимости: закончился период, когда V2-сборки у клиентов можно было обновлять. Chrome 138 был последней версией с корпоративным ключом ExtensionManifestV2Availability, в 139 его убрали, 31 августа расширения исчезли из магазина.

Чек-лист переезда, если он ещё не завершён: сетевую фильтрацию на declarativeNetRequest со статическими правилами в JSON; фоновую страницу на service worker с состоянием в chrome.storage, а не в переменных; никакого удалённо загружаемого кода; проверка того же пакета в Edge и Firefox, у них свои отличия в поддержке V3.

Что произошло с uBlock Origin и куда переехать пользователям разобрали на сайте.

@tproger_web
🤯2💩1
Safari наконец починил top-level await: WebKit переписал загрузчик модулей с нуля

Если модуль с await на верхнем уровне падал у вас в Safari с «Cannot access ... before initialization», это не ваш баг. WebKit сегодня рассказал, почему так было: загрузчик модулей Safari написали по черновику WHATWG Loader, заброшенному в январе 2016 года, ещё до появления async/await в языке. Top-level await из ES2022 прикрутили поверх него, и годы точечных правок проблему не закрывали.

В январе 2026-го команда удалила старый загрузчик целиком и переписала его на C++ по алгоритмам спецификации ECMAScript. В примере из блога один модуль с задержкой импортируется три раза: старый Safari завершал импорты в порядке 2, 3, 1, и два из трёх падали на неинициализированных экспортах, новый выдаёт 1, 2, 3. Проверяли тест-кейсами от команды Bun (тот же JavaScriptCore, те же баги), фаззером графов модулей со сравнением вывода с другими движками и полным набором модульных тестов test262.

Исправление уже в Safari Technology Preview 251 и бете Safari 27, в стабильный придёт с релизом 27. Обходные пути для Safari пока не убирайте, старые версии никуда не денутся. Что именно ломалось и как это чинили, разобрали подробнее.
❤3
Интерпретатор Wasm стал в 2,2 раза быстрее, и это важно там, где V8 не поможет

В браузере WebAssembly исполняет JIT, и про интерпретаторы фронтендеры обычно не думают. Но как только Wasm выходит за пределы вкладки, в плагины, edge-функции, iOS-приложения и песочницы, JIT либо запрещён, либо не помещается в память. Там живёт Wasmi, интерпретатор на Rust, и версия 2.0 по замерам проекта в 2,2 раза быстрее 1.0 по геометрическому среднему.

Внутри четыре режима dispatch вместо одного switch-loop, новое IR с аккумуляторными регистрами и структура CodeMap, где вызов функции не делает ни одного lookup. Включение SIMD больше не замедляет обычный код: в 1.0 это стоило около 8%.

Бенчмарки можно повторить из репозитория wasmi-benchmarks; сравнение с Wasm3, WAMR и Wasmtime Pulley, а также историю про Rust 1.92, который уронил CoreMark на треть, разобрали на сайте.

#wasm #перформанс
❤4
Chrome 154 beta: WebSocket в локальную сеть, постквантовые ключи в Web Crypto и табы на чистом CSS

Три вещи из беты, которые меняют код. Первая: new WebSocket(url, { protocols: "soap", targetAddressSpace: "local" }) открывает сокет к устройству в локальной сети со страницы на HTTPS, если пользователь дал разрешение Local Network Access, а имя хоста резолвится в локальный IP. Раньше это было запрещено без обходных путей.

Вторая: в crypto.subtle появились ML-KEM 768/1024, ML-DSA 44/65/87, ChaCha20-Poly1305 и гибрид X-Wing. Сквозное шифрование в веб-приложении можно строить на постквантовых алгоритмах без сторонних библиотек. Третья: scroll-marker-group: tabs делает из CSS-карусели настоящий tablist для скринридеров, активный маркер единственный останавливается по Tab, а контент неактивных панелей скрыт из дерева доступности.

Что сломается: Background Fetch начал применять CORS, AbortController передаёт reason в Response и ReadableStream. Полный список на сайте.

#браузеры #css
❤1
Ваш код не медленный, он просто держит главный поток

Скролл подёргивается, кнопка отвечает с задержкой, буквы в поиске появляются на полтакта позже. Первый рефлекс: искать медленный алгоритм. Автор разбора показывает, что чаще проблема не в скорости кода, а в том, что он занимает единственный поток, где живут и JavaScript, и стили, и layout, и paint.

Бюджет на кадр при 60 Гц около 16,6 мс, из которых практически доступны примерно 10; на 120 Гц вдвое меньше. Функция на 200 мс замораживает экран на 200 мс, и никакой бандл-оптимизацией это не лечится. Отсюда четыре приёма на самом потоке: делить длинные задачи, группировать частые, расставлять приоритеты, откладывать необязательное. И три способа увести работу с потока: на композитор, в worker, или не делать её вовсе.

Внутри интерактивные демо: чат, куда прилетают сотни сообщений в секунду, и разница между «рисовать сразу» и «отдавать поток каждые 20 сообщений». Yield не делает работу быстрее, но возвращает интерфейсу отзывчивость. Я бы прошёл этот текст перед следующим разбором INP. Разбор в блоге kciter.

#перформанс #javascript
👍5❤2
Три попытки собрать текстовый редактор в браузере: Canvas, contenteditable и textarea

Дэвид Бушелл решил написать свой редактор и прошёл все грабли по очереди. Canvas даёт полный контроль над отрисовкой и ничего бесплатно: ни выделения, ни undo, ни вставки нескольких строк, ни прокрутки, а курсор и стрелки пришлось программировать с нуля при заметной нагрузке на CPU.

Второй заход: contenteditable="plaintext-only" с отключёнными autocapitalize, autocorrect, spellcheck и translate. Проверка орфографии давала скачки задержки ввода. Но на длинном тексте выяснилось, что обычный <textarea> заметно производительнее. Итоговая схема: textarea принимает ввод, отдельный слой сверху рисует подсветку синтаксиса, а Tree-sitter обрабатывает только видимые строки, потому что слишком много CSS Highlights само становится узким местом.

Бонус для тех, кто считает символы: "🍋‍🟩".length даёт 5, spread даёт 3, а Intl.Segmenter честно видит один графем. Разбор у автора.

#javascript
🤯3
Задержка анимации по номеру элемента теперь одна строка CSS, без --i и без JavaScript

sibling-index() возвращает позицию элемента среди соседей (с 1), sibling-count() общее число детей у родителя, обе работают в calc(). С Firefox 154, вышедшим 18 августа, их поддерживают все три движка: Chrome с 138, Safari с 26.2.

li { animation-delay: calc(sibling-index() * 80ms); }
.cards > * { flex-basis: calc(100% / sibling-count()); }

Оговорки, на которых можно споткнуться: считается дерево DOM, а не flat tree, поэтому слоты и Shadow DOM ведут себя иначе, а на границе теневого дерева функция может вернуть 0. Учитываются все соседи, включая скрытые; форма с фильтром of пока только обсуждается в CSSWG. Для декоративных задержек можно использовать сразу: в старом браузере правило просто не применится. Для раскладки я бы завернул в @supports. Даты по браузерам и примеры на сайте.

#css
❤2
Action в React 19 это любая функция, вызванная внутри startTransition, и всё

Четыре API, useActionState, useOptimistic, useFormStatus и useTransition, обычно объясняют по отдельности, и остаётся ощущение, что нужно выбрать один. Шубхра Похария показывает, что это четыре входа в один механизм: функция становится Action, когда вызвана внутри startTransition, и это весь критерий.

Дальше роли простые. useActionState хранит результат и pending; ошибка попадает в состояние, только если action сам её вернёт, иначе это обычное исключение. useOptimistic показывает предполагаемый результат до ответа сервера. useFormStatus читает pending ближайшей формы. useTransition для Action вне формы. Функция в <form action={fn}> получает FormData, preventDefault не нужен, отправка всегда POST независимо от атрибута method.

Две ловушки. React 19 разрешил async внутри transition, но всё после await нужно оборачивать во вложенный startTransition. И useTransition не гарантирует порядок завершения конкурентных Actions, порядок держат только <form action> и useActionState. В конце квиз на 15 вопросов, чтобы проверить себя. Разбор на dev.to.

#react
❤1
Автор ESLint-плагина прогнал свои правила по тестам конкурента и проиграл 51 к 71

Офри Перец вытащил из npm-пакета eslint-plugin-security 84 негативных примера и прогнал их через оба плагина. Конкурент поймал 71, его eslint-plugin-node-security 51, честные 61% покрытия. 29 из 33 промахов пришлись на одно правило, detect-buffer-noassert, которое ловит аргумент, удалённый из Node.js ещё в версии 10: в Node 24 readUInt8(0, true) просто игнорирует его.

Без этого правила счёт 51 из 55, то есть 93%. Обратная сторона: конкурент пропустил 13 примеров, которые поймал автор, а вместе два плагина закрывают 84 из 84. Но на 61 файле обычных automation-скриптов автор получил 279 срабатываний, и все проверенные оказались ложными.

Метод на 40 строк можно повторить для любой пары линтеров, а вывод универсален: «кто цитирует одно число, цитирует то, которое ему выгодно». Замер от 12 августа на eslint-plugin-security 4.0.1 и ESLint 9.39.2. Разбор на dev.to.

#безопасность #javascript
❤1👍1
Подсказки автодополнения приходят раньше, чем пользователь отпустил клавишу

Wirewiki ищет среди 240 миллионов доменных имён, и автор сервиса добился p99 в 0 мс: запрос уходит на keydown, сервер готовит варианты для всех допустимых следующих символов, а интерфейс показывает результат на keyup. В бюджет попадают длительность нажатия и пауза до следующей клавиши, для 60 Гц это несколько кадров. Перерасход трафика ограничен алфавитом: до 312 имён в ответе, около 2,5 КБ после сжатия.

В нашем канале «Сохранёнки программиста» разобрали подробнее.

#перформанс
🤔3
pnpm 12.3.1: быстрее в монорепозиториях, нативные shim и секреты, которые больше не утекают в логи

Если у вас workspace на десятки пакетов, pnpm install в 12.3 должен стать быстрее без настроек: lockfile читается во время обнаружения проектов, граф строится один раз вместо копирования lockfile целиком. Цифр команда не приводит, эффект тем больше, чем толще lockfile.

Глобальные команды node, deno, bun и shim из pnpm shim add стали нативными исполняемыми файлами, в Windows .exe вместо .cmd и .ps1. Именно эта миграция сломалась при self-update с 12.2, поэтому через несколько часов вышел 12.3.1; обновляйтесь сразу на него. Ещё: trust-флаги теперь и у remove с update, учётные данные из URL реестров скрываются в ошибках fetch, recursive run больше не зависает с --filter, а системный резолвер на Linux перестал молча ходить в Google Public DNS. Подробнее на сайте.

#nodejs
❤1
Языковая модель во вкладке: WebLLM считает на видеокарте пользователя через WebGPU, сервер не нужен

Библиотека от команды MLC AI (18,8 тыс. звёзд, Apache-2.0) скачивает модель один раз, кладёт в Cache API, IndexedDB или OPFS и запускает инференс прямо в браузере. API повторяет OpenAI: engine.chat.completions.create({ messages, stream: true }), так что фронтенд чата переносится почти без правок. Тяжёлую работу можно вынести в Web Worker или Service Worker, чтобы не вешать интерфейс.

Что это стоит пользователю: предсобранные модели просят от 0,7 ГБ видеопамяти (gemma3-1b) до 6,4 ГБ (Qwen3.5-9B), первый запуск ждёт скачивания весов, а без WebGPU ничего не заработает. Зато промпты не уходят с устройства, а инференс не стоит вам ни копейки. Попробовать без кода можно на chat.webllm.ai. Установка, код, замеры скорости против нативного запуска и FAQ на сайте.

#javascript #ии
❤1
Ваш веб-компонент приезжает клиенту пустым, и серверный рендер тут ни при чём

У Shadow DOM не было способа отрендериться на сервере. Не «трудно», а структурно отсутствовало: сколько ни настраивай серверный рендер, веб-компонент уезжает клиенту пустой коробкой и наполняется, только когда доедет и отработает JavaScript.

Увидеть это можно за минуту: curl по собственной странице с аккордеоном или табами и поиск по тексту изнутри компонента. В ответе кастомный элемент без содержимого и тег <template> рядом, который ничего не делает. На медленном соединении пользователь видит ту же пустую коробку, которая потом схлопывается.

Поэтому и привычные лечения мимо: инлайн критического CSS не спасает, ведь содержимое теневого дерева не «без стилей», его вообще нет. Что теперь писать в разметке, показано в разборе.

#фронтенд
❤2
Каждая цепочка filter и map создаёт два лишних массива

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

Методы массивов жадные: выполняются сразу и возвращают новый полностью заполненный массив. Iterator helpers ленивые: тянут значения по одному и ровно столько, сколько попросили. Для потоков и бесконечных последовательностей это разница между работающим кодом и упавшей вкладкой.

Приятная часть: это уже нативно, без библиотек, полифилов и шага сборки. Chrome 122, Firefox 131, Safari 18.2. Разбор с примерами.

#javascript
❤5
Подсветка фрагментов текста без единого лишнего span в разметке

Люди страницу не читают, а сканируют, поэтому подсветка нужных кусков работает. В CSS для этого целое семейство псевдоэлементов: ::selection для выделенного мышью текста, ::target-text для перехода из поиска и самый гибкий из них, ::highlight(), который красит произвольный фрагмент по вашему выбору.

Подкупает то, что оборачивать текст в разметку не надо: диапазон задаётся в JavaScript, а стили живут в CSS. В DOM не появляется ни одного лишнего узла, а значит, ничего не ломается ни в вёрстке, ни в доступности.

Поддержка пока не везде, поэтому Сюнками Фафовора показывает, как включать это через progressive enhancement: браузер без поддержки просто не покрасит, и страница останется рабочей.

#css
🔥5