frontendhubvk | Unsorted

Telegram-канал frontendhubvk - Frontend VK Hub

1119

Комьюнити VK для фронтендеров. Кто и что стоит за интерфейсами, которыми пользуются миллионы пользователей, — от Почты Mail до VK Teams — рассказываем здесь 🤘

Subscribe to a channel

Frontend VK Hub

Frame-sizing в Chrome 154: iframe сам подстраивает высоту под контент

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

Chrome 154, вышедший 22 сентября, справляется без скриптов. Нужны две вещи: CSS-свойство frame-sizing на стороне хоста и метатег с согласием в документе внутри фрейма.

.embed {
width: 100%;
height: 500px; /* для браузеров без поддержки */
}

@supports (frame-sizing: content-height) {
.embed {
height: auto;
frame-sizing: content-height;
max-height: 80vh;
}
}

Встраиваемая страница должна разрешить это явно, иначе хост её размер не получит:
<meta name="responsive-embedded-sizing"
content="allow-origins=https://publisher.example">

Решение принимает встраиваемая сторона: в allow-origins через пробел перечисляются домены, которым можно сообщать размер, либо ставится *. Схема работает и для фреймов с другого домена и дополняет frame-ancestors из CSP. Тег должен быть в документе с самого начала, добавить его скриптом после загрузки не выйдет.

Кроме content-height, у свойства есть content-width, логические content-inline-size и content-block-size, а также auto, которое оставляет прежнее поведение. Для виджетов, растущих вниз, подходит content-height.

Размер браузер берёт после загрузки и дальше за каждым изменением вёрстки не следит. Если содержимое поменялось, например подгрузились новые комментарии, документ сам просит пересчитать размер:
if ("requestResize" in window) {
window.requestResize();
}

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

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

Старый мост на postMessage пока выбрасывать рано, потому что в Firefox и Safari поддержки нет. Зато метатег во встраиваемые страницы можно добавлять уже сейчас, а на хосте включать frame-sizing под @supports и оставить прежний код запасным путём.

А вы сейчас подгоняете высоту iframe через postMessage или живёте с фиксированной?

#frontendvkhub #chrome #css

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

Frontend VK Hub

🔵STP 252: @supports научился проверять сами условия

11 сентября в Safari Technology Preview 252 добавили CSSConditionRule.supports и named-feature() в @supports — проверку поддержки фич без детектируемого синтаксиса, например anchor positioning. Заодно распрефиксовали user-select — теперь это стандартное свойство без -webkit-.

🔵Safari 27 — новые возможности CSS и HTML

14 сентября вышел Safari 27 с кастомизацией <select>, псевдоклассом :heading, sizes="auto" и расширениями color-mix(). WebKit также обновил загрузчик ES-модулей, улучшив поддержку top-level await.

🔵Node.js 26.9 — быстрые Worker Threads и FFI

16 сентября Node.js ускорил запуск Worker Threads до 2 раз и снизил их потребление памяти. Экспериментальный node:ffi теперь включён по умолчанию — вызывать функции нативных библиотек можно без отдельного модуля C++.

🔵Chrome 154: браузер переходит на двухнедельный релиз-цикл

22 сентября вышел Chrome 154 — первый релиз по новому двухнедельному расписанию вместо прежнего четырёхнедельного. Из фич для вёрстки:

• scroll-marker-group получил режимы links/tabs, которые задают фокус-порядок и ARIA-семантику для ::scroll-marker-group

• iframe теперь можно сделать самоподстраивающимся под контент через frame-sizing: content-height — без ручного измерения высоты и postMessage

🔵Next.js: серия security-апдейтов закрывает критическую уязвимость в апстриме

22 сентября Vercel выпустил внеплановый патч 16.3.6 и 15.5.26 из-за критической уязвимости в сторонней зависимости. А 30 сентября — плановый сентябрьский security-релиз 16.3.8 и 15.5.27, закрывающий ещё 7 уязвимостей: 1 высокой степени критичности, 5 средних и 1 низкую. Если вы ещё не обновили проект на Next.js — не откладывайте это.

🔵Safari Technology Preview 253: sibling-index() добрался до @container

23 сентября в STP 253 sibling-index() и sibling-count() стало можно использовать прямо в условиях @container. То есть раскладка контейнера теперь может зависеть не только от его размера, но и от позиции элемента среди соседей. WebKit также обновил безопасное выравнивание (safe/unsafe) для абсолютно позиционированных боксов, чтобы они не вылетали за пределы исходного содержащего блока.

#frontendvkhub #дайджест

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

Frontend VK Hub

URLPattern: маршруты, которые не нужно переписывать в регулярки

В любом приложении со своей маршрутизацией рано или поздно заводится файл с регулярками. /^\/users\/(\d+)\/posts\/([\w-]+)$/ работает, но читается тяжело, номера групп приходится помнить наизусть, а проверка домена и протокола живёт отдельным условием рядом. Обычный выход состоит в том, чтобы притащить path-to-regexp и получить ещё одну зависимость ради разбора адреса.

Разбирать адреса умеет сама платформа. URLPattern принимает шаблон в знакомом по роутерам синтаксисе и сопоставляет с ним URL целиком, а не только путь:

const route = new URLPattern({ pathname: "/users/:id/posts/:slug" });

route.test("https://app.example.com/users/42/posts/hello"); // true

const match = route.exec("https://app.example.com/users/42/posts/hello");
match.pathname.groups; // { id: "42", slug: "hello" }

Группы именованные, так что возиться с их порядком не нужно. Кроме :name, доступны звёздочка для любого остатка, модификаторы ? и +, фигурные скобки для необязательных кусков пути и собственные регулярки прямо внутри шаблона: /v:version(\\d+)/ поймает только числовую версию.

Шаблон покрывает все части адреса сразу, и на этом удобно строить таблицу маршрутов в Service Worker или в edge-функции:
const routes = [
[new URLPattern({ pathname: "/api/v:v(\\d+)/*" }), handleApi],
[new URLPattern({ hostname: "cdn.example.com" }), handleAssets],
];

self.addEventListener("fetch", (event) => {
const route = routes.find(([pattern]) => pattern.test(event.request.url));
if (route) event.respondWith(route[1](event.request));
});

Главная разница между двумя формами записи проявляется как раз тут. В объектной форме всё, что не указано, считается звёздочкой: шаблон выше совпадёт с любым протоколом и любой строкой запроса. В строковой форме, new URLPattern("https://example.com/books/:id"), пропущенные части приравниваются к пустой строке, поэтому адрес с параметрами мимо такого шаблона пройдёт, пока не дописать ?*#* вручную.

Дальше идёт мелочёвка. Двоеточие внутри литерала экранируется обратным слешем, иначе парсер примет его за начало группы. Юникод в регулярных группах придётся кодировать процентами самостоятельно: автоматически платформа этого не делает. Регистр по умолчанию учитывается, а выключается опцией ignoreCase.

С сентября 2025, когда поддержку закрыл Safari 26, API считается Baseline и работает в том числе в воркерах. Для старых браузеров есть официальный полифилл urlpattern-polyfill, он же закрывает Node без экспериментальных флагов.

Смысл переезжать есть там, где роутер только сопоставляет адреса и достаёт из них параметры: слой регулярок или path-to-regexp в этом случае удаляется целиком. Если поверх маршрутизации навешаны вложенные layout-компоненты, middleware и ленивые импорты, URLPattern занимает нижний уровень, а остальное остаётся вашим кодом.

#frontendvkhub #javascript #urlpattern

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

Frontend VK Hub

Архитектурные векторы: альтернативы

В предыдущем посте мы рассмотрели мейнстримную линейку: от серверных шаблонов до серверных компонентов. Параллельно с ней живут подходы, которые отвергают само допущение, что веб-приложение обязано быть JS/TS SPA с клиентским состоянием и JSON API. Разбираем в карточках альтернативные архитектурные подходы к фронтенду.

#frontendvkhub #обзор #эволюция_веба

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

Frontend VK Hub

Архитектурные векторы: мейнстрим

Сегодня в продакшене одновременно работают разные архитектурные подходы: серверные шаблоны, jQuery, SPA, SSG, SSR, islands и Server Components. Эволюция веба — это не смена победителей, ведь каждая модель отвечала на свои вызовы. Разбираемся, как происходило развитие архитектур веба.

#frontendvkhub #обзор #эволюция_веба

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

Frontend VK Hub

Customizable select: нативный дропдаун, который наконец стилизуется

<select> больше двадцати лет оставался чёрным ящиком. Шрифт поменять можно, иногда — фон, дальше начинается территория операционной системы: своя стрелка, свои отступы, свой список опций, который рисуется вне окна браузера и никакому CSS не подчиняется.

Дизайнер просит фирменный шеврон и скруглённые опции — разработчик идёт за Choices.js или Select2. Библиотека выкидывает нативный элемент и собирает вместо него стопку из div, после чего клавиатурную навигацию, ARIA-атрибуты и работу со скринридерами восстанавливают вручную. Тридцать килобайт и постоянная поддержка — цена за одну стрелку.

Customizable select убирает этот обмен. Команда Safari показала его на WWDC 2026, работает он в Safari 27 и Chrome 135, Firefox прототипирует за флагом.

Включается одним значением, но объявить его нужно дважды — на самом элементе и на выпадающем списке:

.custom-select {
&,
&::picker(select) {
appearance: base-select;
}
}

После этого браузер перестаёт рисовать виджет средствами системы и превращает <select> в обычное дерево элементов. Список опций уезжает в top layer, как поповер, и позиционируется через anchor(), а значит, больше не обрезается родителем с overflow: hidden.

Открывается доступ к внутренностям, которых раньше не существовало. ::picker(select) — сам список, ::picker-icon — стрелка, ::checkmark — галочка у выбранной опции, :open — состояние раскрытого списка, :checked — текущая опция. Обычные селекторы, к которым применяются переходы и анимации.

Отдельно стоит <selectedcontent> — он зеркалит содержимое выбранной опции внутрь кнопки. В той же опции теперь можно класть настоящую разметку: флаг картинкой, иконку, вложенный span с описанием. Раньше <option> принимал только текст, остальное браузер молча выбрасывал.
<select class="custom-select">
<button>
<selectedcontent></selectedcontent>
</button>
<option value="ru">
<img src="/flags/ru.svg" alt=""> Россия
</option>
</select>

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

При всём этом в базовом режиме список не рендерится за пределами окна браузера и не вызывает системные компоненты выбора на мобильных — вместо привычного колеса iOS пользователь увидит ваш список. Включение к тому же меняет разбор содержимого <select> парсером, и на старой разметке это может дать неожиданный результат. Chrome держит фичу под управляемым экспериментом на случай быстрого отката.

До Baseline пока далеко, но браузер без поддержки игнорирует незнакомое значение и рисует обычный <select>. Фолбэков писать не нужно, а если хочется явно развести стили — есть проверка через @supports (appearance: base-select).

#frontendvkhub #css #select

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

Frontend VK Hub

Подсветка текста, которая не трогает DOM

Задача звучит просто: подсветить найденные слова на странице. Реализация традиционно упирается в то, что подсвечивать в вебе можно только элемент. Значит, нужно найти текстовый узел, разрезать его, обернуть кусок в <mark>, а при следующем запросе всё это разобрать обратно.

Ломается такой подход быстро.  Range.surroundContents() бросает исключение, если диапазон пересекает границы тегов, а найденная фраза запросто начинается в <em> и заканчивается снаружи. Обработчики, повешенные на исходные узлы, теряются вместе с этими узлами.

Виртуализованный список перерисовывается и уносит подсветку. Получается, что мы работаем с DOM ради того, что к структуре документа отношения не имеет. 

Custom Highlight API решает это иначе — диапазон описывается, но в разметку не попадает:

const range = new Range();
range.setStart(textNode, 10);
range.setEnd(textNode, 25);

CSS.highlights.set('search', new Highlight(range));

::highlight(search) {
background-color: oklch(90% 0.15 100);
color: black;
}

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

Одна подсветка может содержать сколько угодно диапазонов. Зарегистрировать можно сколько угодно именованных подсветок — каждая со своим ::highlight(name) и своими стилями. Для совместной работы это то, что нужно: выделение каждого участника получает своё имя и свой цвет, а снимается всё через CSS.highlights.delete('name') или разом через clear().

Набор доступных свойств намеренно узкий: color, background-color, text-decoration, text-shadow и обводка. Геометрию поменять нельзя, background-image игнорируется. Ограничение осмысленное: раскладка от подсветки не зависит, поэтому браузеру не нужно пересчитывать её при каждом изменении диапазонов.

По поддержке история долгая: Chrome и Edge закрыли её ещё в 105-й версии в августе 2022, Safari подключился в 17.2 в декабре 2023, Firefox замкнул круг позже, и с марта 2026 фича считается Baseline. На 2026 год она попала в фокус Interop.

Механизм полностью зависит от JavaScript и молча ничего не делает там, где не поддерживается. Отсюда рабочая схема — оставить в разметке настоящий <mark> со стилями по умолчанию, а поверх включить ::highlight() через @supports selector(::highlight(search)). Читатель без поддержки видит семантическую подсветку, остальные — динамическую, и никто не остаётся с пустой страницей.

А вы у себя чем подсвечиваете поиск по странице? Делитесь в комментах — интересно, кто уже выкинул обёртки в <mark>.

#frontendvkhub #javascript

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

Frontend VK Hub

Функции и условия в CSS без препроцессора

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

Теперь CSS умеет это сам. @function описывает функцию с аргументами и типами, if() возвращает разные значения по условию — и то и другое работает во время выполнения, с живыми значениями переменных.

#frontendvkhub #css

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

Frontend VK Hub

Promise.withResolvers() — deferred без танцев с замыканиями

Есть паттерн, который в JS годами делали руками: получить промис плюс функции resolve и reject, чтобы дёрнуть их снаружи. Каждый раз конструкция с замыканием. С 2024 есть Promise.withResolvers(): три сущности одной строкой. Baseline: Chrome 119, Safari 17.4, Firefox 121, Node 22+.

Как это выглядит

Раньше было так:

let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});

// а дальше где угодно
button.addEventListener('click', () => resolve('clicked'));

Теперь короче:
const { promise, resolve, reject } = Promise.withResolvers();

button.addEventListener('click', () => resolve('clicked'));

Кажется мелочью, но паттерн возникает часто. Рассмотрим три кейса.

Конвертация event-based API в await

Ждём одно событие и продолжаем:
async function waitForClick(button) {
const { promise, resolve } = Promise.withResolvers();
button.addEventListener('click', resolve, { once: true });
return promise;
}

const evt = await waitForClick(saveButton);

Раньше — new Promise с замыканием, теперь одна строка настройки и return promise.

Промис, которым управляют извне модуля

Экспортируем промис, резолвящийся при готовности: инициализация SDK, авторизация, connection ready:
const { promise: ready, resolve: markReady } = Promise.withResolvers();

export function initSDK(config) {
setup(config).then(() => markReady());
}

export { ready };

Другие модули просто await ready перед использованием SDK. Без withResolvers пришлось бы либо экспортировать промис отдельно, либо городить lazy-инициализацию.

Обёртка над колбэками

Много старых API отдают результат через колбэк, обёртка с withResolvers чище:
function toPromise(fn) {
const { promise, resolve, reject } = Promise.withResolvers();
fn((err, result) => {
if (err) reject(err);
else resolve(result);
});
return promise;
}

const data = await toPromise(cb => oldApi.load(cb));

То же, что делает util.promisify в Node, только локально и без зависимостей.

Один нюанс с TypeScript. Раньше тип для deferred писали руками. С withResolvers TypeScript выводит тип автоматически, дженерик указывается при вызове:
const { promise, resolve } = Promise.withResolvers<string>();
resolve('hello'); // ok
resolve(42); // error

Promise.withResolvers() создаёт промис, у которого resolve и reject доступны снаружи. Удобно, но может быть опасно: любой, кто получил ссылку на resolve, может завершить промис из произвольного места. Не пробрасывайте эти функции наружу модуля без нужды — держим их приватными, отдаём только сам промис.

Если в кодовой базе есть паттерн let resolve; new Promise(r => resolve = r) — время заменить на Promise.withResolvers. Одна строка, читается очевидно, TypeScript выводит типы сам.

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

Frontend VK Hub

🔵Chrome 150: новые возможности CSS

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

text-fit автоматически подгоняет размер шрифта под ширину контейнера — до сих пор это делалось через ResizeObserver с пересчётом font-size на каждый resize, теперь одна строка CSS.

background-clip: border-area наконец сделал возможными градиентные и image-fill бордеры без псевдоэлементов и хитрых box-shadow — фичу ждали примерно с эпохи CSS Gradients.

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

🔵Chrome 151: доступ к анимациям упростили

Через несколько дней после 150 подоспел 151 в бете. animation теперь доступен прямо на AnimationEvent и TransitionEvent: раньше в обработчике звали getAnimations() и матчили нужное по имени, теперь объект достаётся из ивента. Плюс ruby-overhang для CJK. Из breaking — 151 больше не запустится на macOS 12, минимум теперь 13, так что если пользователи на старых Mac ещё есть, стоит глянуть свою статистику.

🔵Firefox: AI-ассистент в широком доступе и нативная поддержка Containers

Firefox параллельно занят пользовательским опытом. 152.0.6 от 14 июля докатил Smart Window до широкого rollout: выделили текст на странице, всплывает встроенный AI-ассистент с опциями summarize, explain, rewrite. То, что раньше делали сторонние расширения, теперь встроено. А 21 июля вышел 153 ESR с превью нативных Containers — вместо Multi-Account Containers extension теперь родная функциональность. Плюс частичная поддержка ::-webkit-scrollbar в CSS для web compat со старыми сайтами.

🔵Vue: патчи для hydration, reactivity и SSR

Vue шёл по мелким патчам — hydration edge cases, reactivity в scope stop, preserving textarea resize, deferred mount для teleport. Ничего headline-фичного, но если проект на Nuxt и SSR-heavy, свежую минорку стоит поймать.

#frontendvkhub #дайджест

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

Frontend VK Hub

Форматирование и локали в платформе Intl

Intl — встроенный набор классов для форматирования и сравнения с учётом локали. Большинство фронтов тащит date-fns ради «2 дня назад», lodash для сортировки, ручные функции для денег и процентов. Почти всё это уже есть в браузере, причём заметно мощнее, чем кажется.

В карточках рассмотрим шесть классов — каждый со своим случаем, и почти каждый поднимает вопрос «А что, так можно было?»

#frontendvkhub #intl

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

Frontend VK Hub

🔵 Спецификация современного сайта
Вышел чек-лист из 128 пунктов для аудита современных веб-приложений: производительность, доступность, безопасность, SEO и готовность к работе с AI-агентами. Хороший ориентир для оценки зрелости продукта и инженерных процессов.

🔵Chrome 150 Beta
Новая бета-версия Google Chrome продолжает расширять возможности веб-платформы. Традиционно именно такие релизы задают направление развития браузерных API на ближайшие месяцы.

🔵WebGPU продолжает развиваться
Обновления в WebGPU для Chrome 149–150 расширяют возможности высокопроизводительной графики и вычислений в браузере. Технология постепенно становится реальным фундаментом для сложных визуализаций, редакторов и AI-задач на клиенте.

🔵CSS @function — движение к программируемому CSS
Новый механизм позволяет создавать переиспользуемые функции прямо в CSS, уменьшая зависимость от препроцессоров и JavaScript. Ещё один шаг к тому, чтобы логика интерфейса оставалась внутри платформы.

🔵State of CSS 2026
Ежегодный опрос остаётся одним из главных индикаторов того, какие возможности CSS реально используются в индустрии и куда смещается внимание фронтенд-сообщества.

🔵React Compiler меняет подход к оптимизации
Автоматическая мемоизация постепенно снижает необходимость в useMemo, useCallback и React.memo для многих сценариев. Это может заметно повлиять на практики разработки и код-ревью в React-проектах.

#дайджест #frontendvkhub

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

Frontend VK Hub

Самая недооценённая штука в современном JS

У итераторов в JavaScript теперь есть .map, .filter, .take и ещё десяток методов — те же, что у Array, но ленивые. Никаких промежуточных массивов, никакой материализации. Спецификация ES2025, поддерживается везде с весны 2025: Chrome 122, Firefox 131, Safari 18.4, Node 22+. Большинство фронтов про них не знают.

Зачем это вообще нужно

Array-методы материализуют каждую промежуточную коллекцию:

// Каждый шаг создаёт новый массив
const result = bigArray
.filter(x => x.active) // массив N байт
.map(x => x.id) // ещё один
.slice(0, 10); // и ещё, хотя нужны 10 элементов


Iterator-методы работают лениво и не аллоцируют ничего лишнего:

const result = bigArray.values()
.filter(x => x.active)
.map(x => x.id)
.take(10)
.toArray();


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

Бесконечные потоки наконец работают

С генераторами разница совсем резкая:

function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}

const first10Even = fibonacci()
.filter(n => n % 2 === 0)
.take(10)
.toArray();


С Array.from(fibonacci()) это бы повисло — массив бесконечный. С итератором .take(10) дёргает источник ровно до десятого совпадения.

Iterator.from превращает что угодно в итератор

Любой iterable можно обернуть и получить доступ к хелперам:

const tags = new Set(['react', 'vue', 'svelte']);

const upper = Iterator.from(tags)
.map(t => t.toUpperCase())
.toArray();
// ['REACT', 'VUE', 'SVELTE']


То же работает с Map.entries(), NodeList, генераторами, async iterables. NodeList особенно приятно:
document.querySelectorAll('li').values().filter(...).take(5) — без обхода всего DOM.

Когда выигрывают, а когда нет

Большие коллекции, из которых берём небольшой кусок — выигрывают. Генератор или бесконечный поток — выигрывают. Потоковая обработка ReadableStream — выигрывает.

А для обычного массива на 50–100 элементов разницы почти нет, Array-методы даже чуть быстрее за счёт оптимизаций движка.

В итоге Iterator helpers — это про память и про возможность не материализовать промежуточные результаты. Если в коде встречаются цепочки вида .filter().map().slice() на больших данных или ручные циклы для досрочного выхода из обработки — это первые кандидаты на переписывание через .values().

А вы где используете итераторы, кроме for...of? Делитесь кейсами в комментариях..

#frontendvkhub #javascript

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

Frontend VK Hub

Несколько лет работа с React выглядела шаблонно: открыть компонент, обвесить значения useMemo, функции — useCallback, «ребёнка» завернуть в React.memo. Половина обвесов стояла на всякий случай, другая не работала из-за inline-объекта в пропсе. Ревью часто перерастало в спор о стабильности ссылок.

React Compiler 1.0 вышел в октябре 2025 и закрыл эту тему. К 2026 году он стабилен в Next.js 16 и Vite. От разработчика требуется только включить флаг.

Корень проблемы в каскадном ре-рендере. Меняется состояние родительского компонента, React по умолчанию рендерит и его, и всё поддерево, даже если пропсы «детей» не изменились: корректность важнее производительности. Три классических escape hatch — useMemo, useCallback, React.memo — держались на одной хрупкой штуке, идентичности ссылки. Inline-объект в пропсе или забытая зависимость — и мемоизация молча обнулялась.

Компилятор подходит с другой стороны. Это build-time tool на babel transform: разбирает компонент целиком, строит граф зависимостей и там, где они стабильны, сам подставляет эквивалент useMemo, useCallback и React.memo. На выходе — обычный JS, runtime-кода не прибавляется.

В Next.js 16 компилятор включается одним параметром:

import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
reactCompiler: true,
}

export default nextConfig

С Next.js 16 reactCompiler перешёл из разряда экспериментальных в стабильную top-level-настройку. По умолчанию он выключен, команда next.js собирает данные о времени сборки. Дополнительно ставится babel-plugin-react-compiler, в Vite та же связка выполняется через babel-конфиг. Отдельно eslint-plugin-react-compiler — он подсветит места, где компилятор откажется работать.

Откажется там, где код нарушает Rules of React: мутация объекта во время рендера, чтение mutable external store без useSyncExternalStore, неидемпотентная логика, динамический property access. В таких компонентах оптимизации просто не будет. Поэтому ESLint-плагин — обязательный первый шаг: без чистки нарушений компилятор молча обойдёт половину компонентов.

useMemo и useCallback при этом не исчезают. Они остаются как escape hatch для явного контроля: например, если мемоизированное значение идёт с зависимостью useEffect, и эффект не должен пересрабатывать на каждое перевычисление. Эвристики компилятора иногда мемоизируют чуть шире или чуть уже, чем нужно конкретному эффекту.

В новых проектах компилятор включают с первого коммита и не разбрасывают useMemo заранее. В существующих кодовых базах порядок другой: сначала прогон ESLint-плагином, фикс нарушений Rules of React, потом флаг, и наконец постепенная зачистка избыточных мемо. Главное изменение в практике: идентичность ссылок перешла в детали реализации компилятора, и обсуждать её на ревью больше не имеет смысла.

#frontendvk #react

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

Frontend VK Hub

🔹 Любой фронтендер может сделать приложение для VK Mini Apps и заработать на нём. Без команды, без инвестиций, в одиночку.

Дима Сединкин рассказал Коду Дурова, как запустил конструктор лид-форм для сообществ ВКонтакте. Доход растёт в среднем на 110% в месяц, среди клиентов — федеральные фитнес-сети и клиники по всей России.

В статье Дима подробно разбирает путь от универсального конструктора форм к узкой нише, почему «мыслить как разработчик» оказалось ловушкой, и какие возможности VK Mini Apps реально конвертят в выручку — автозаполнение, фиксация упущенных лидов, подписка на сообщество из формы.

🔹 Читайте кейс целиком: https://kod.ru/kak-frontend-developer-zapustil-svoi-pervyi-business

#frontenvkhub #miniapps

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

Frontend VK Hub

Vite+ — не новая версия Vite и не его замена. Это отдельная утилита, которая объединяет инструменты вокруг Vite в один CLI: Vite 8, Vitest 5, Oxlint, Oxfmt, Rolldown и tsdown.

28 сентября VoidZero выпустила первый стабильный релиз. Разбираемся вместе с Петром Гилевичем, руководителем веб-разработки контентных сервисов ВКонтакте, как там всё устроено.

В чём идея

Фронтенд-проект требует набор инструментов: сборщик, тесты, линтер, форматтер, сборка npm-пакетов. Каждый обновляется сам по себе, у каждого своя конфигурация, а локальное окружение и CI расходятся — привет, worked on my machine.

Заявленные кратные ускорения касаются линтинга и нового ядра сборки в Vite 8. Версии всех инструментов подобраны и протестированы вместе, обновляются одной командой и гарантированно работают в связке.

Как устроено

Глобальная утилита vp — отдельная программа, ставить через npm не нужно. Она смотрит, какая версия Node.js нужна проекту, скачивает её и переключает при переходе между проектами.

В самом проекте вместо отдельных Vite, Vitest и Oxlint в зависимостях остаётся один пакет vite-plus — версии инструментов зашиты в него. Есть нюанс: если доставить какой-то инструмент отдельно, можно случайно получить вторую его копию и сломать связку — документация предупреждает об этом.

Vite Task в монорепозитории и кеширование сборки

Если вы разрабатываете несколько пакетов в одном репозитории, рутину — прогоны тестов и другие пайплайны — берёт на себя движок Vite Task. Он умеет то, ради чего раньше отдельно ставили Turborepo.

Во-первых, он видит, какой пакет от какого зависит, и запускает сборки в правильном порядке: сперва библиотека, потом зависящее от неё приложение. Внутри одной сборки порядок модулей и так определяет сборщик — а вот очерёдность сборок между пакетами одного репозитория как раз зона ответственности Vite Task.

Во-вторых, он кеширует сборки: vp run build --cache снимает fingerprint зависимостей модуля. Запустите команду снова, не меняя код, — сборка полностью пропустится, и результат мгновенно вернётся из кеша. Пока кеш хранится локально, но у Vite+ в планах удалённый — как у конкурентов, в том числе для использования на CI.

Как Vite+ стал открытым

Изначально Vite+ планировали сделать платным. Но до публичного релиза от платной модели отказались: код открыли под MIT. Почему передумали — в секции MIT License на сайте VoidZero прокомментировали: «Мы устали спорить, какие функции должны быть платными и как их ограничивать». Летом 2026 Cloudflare купила VoidZero — инструменты остаются открытыми.

Что в итоге

Получаем управление всей экосистемой вокруг Vite одной командой: один апгрейд вместо синхронизации пяти инструментов.

Из коробки есть миграция: vp migrate пытается влить все конфигурации — линтера, форматтера, тестов — в один vite.config.ts, переписывает скрипты package.json на vp-команды и перед изменениями показывает план. Миграция рассчитана на свежие Vite 8+ и Vitest 4.1+; прехуки на Husky (утилита для Git-хуков) остаются как были — их подключают к Vite+ вручную.

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

Старт мощный: 2,4 млн скачиваний в неделю на начало октября, мейнтейнер с мировым именем. Небольшим проектам, которые уже на Vite, пробовать можно. Крупным, вероятно, надо повременить: недавно Vite сменил ядро сборки на Rolldown, и это был очень серьёзный апдейт. 

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

#frontendvkhub #vite #что_нового

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

Frontend VK Hub

CSS в 2026 году: где JavaScript уже не обязателен

Открыть поповер, подсветить карточку с выбранным чекбоксом, растянуть textarea под текст — раньше на каждую такую мелочь заводился скрипт, состояние и подписка на события. За два года CSS забрал у JavaScript целый пласт таких задач, и часть фич уже прошла порог Baseline.

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

➡️В карточках — короткая версия с актуальными статусами поддержки. А подробнее читайте на Хабре.

#frontendvkhub #css

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

Frontend VK Hub

Как поделиться данными с воркером и не копировать их

Воркер получает данные через postMessage, и браузер по умолчанию копирует всё, что вы туда положили. На массиве в 100 МБ копирование само по себе подвешивает главный поток — ровно там, где воркер должен был его разгрузить.

Обойти это можно двумя путями. Первый — отдать буфер воркеру насовсем: делается одной строкой и работает везде. Второй — открыть память, в которую оба потока пишут одновременно.

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

#frontendvkhub #воркер

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

Frontend VK Hub

VK Frontend Meetup SPB — про веб-анимации, AI и автоматизацию

30 сентября в Санкт-Петербурге встречаемся с фронтенд-разработчиками на VK Frontend Meetup SPB. В этот раз разберём три слоя фронтенда: то, что видит пользователь, то, как мы создаём интерфейсы, и то, как масштабируем разработку.

Поговорим о практических задачах, которые возникают в больших продуктах: как стабильно рендерить много анимаций, как научить AI верстать по правилам проекта, а не «примерно похоже», и как автоматизировать типовые задачи, чтобы запускать сотни промо без постоянного участия разработчиков.

В программе:

🔵Артем Стукалов, МАХ — слой интерфейса и производительности. Расскажет, как команда пришла к собственной архитектуре для веб-анимации стикеров. Разберём, почему одного Lottie оказалось недостаточно, что изменилось после перехода на собственное решение и как удалось стабильно рендерить большое количество анимаций без лагов.

🔵 Эмиль Янгиров, Одноклассники — слой создания интерфейсов и AI. Поговорим о том, почему AI пока не умеет по-настоящему верстать production-код. Обсудим, как подготовить Figma и дизайн-систему к работе с AI-агентом, передать ему правила проекта, не дать выдумывать компоненты и автоматически проверять адаптивность, доступность и визуальное соответствие.

🔵 Александр Сарафанников, Почта Mail — слой масштабирования и автоматизации. Покажет, как запускать 300 промо в год за 10 минут. Это история о том, как команда прошла путь от единого места с коммуникациями и ручной работы разработчика до платформенного решения, которое позволяет запускать типовые промо сразу в нескольких проектах — без отдельной задачи для разработчика.

Митап полностью офлайн — записей докладов не будет. Зато после основной программы останемся на фуршет и неформальное общение: можно будет задать вопросы спикерам, обсудить доклады и обменяться опытом с коллегами.

Митап бесплатный, но для участия обязательна регистрация.

Приходите — разберём фронтенд слой за слоем.

#frontendvkhub #митап

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

Frontend VK Hub

🔵18 августа вышел Firefox 154 — самый заметный для вёрстки релиз месяца.

Появились text-box-trim, text-box-edge и шорткат text-box. Проблема, которую они решают, знакома любому, кто верстал заголовки по макету.

Шрифт несёт с собой пространство над и под строкой, причём у каждой гарнитуры своё: у одной сверху остаётся два пикселя, у другой шесть. Дизайнер в Figma видел текст, посаженный по оптическому краю, а в браузере тот же блок съезжал. Фиксилось это отрицательными марджинами, подобранными вручную, а при смене шрифта подбор начинался заново. Новые свойства срезают лишнее на уровне движка, и блок встаёт туда, где его нарисовали.

Вторая пара — sibling-count() и sibling-index(). Первая возвращает число соседних элементов вместе с самим элементом, вторая — порядковый номер, счёт с единицы, а не с нуля.

Раньше для стилизации по позиции шаблонизатор или скрипт проставлял каждому элементу инлайновый --index, от которого уже считались задержка анимации, толщина, прозрачность — список из полусотни карточек означал полсотни инлайновых стилей в разметке. Теперь это делает сам CSS, без nth-child-арифметики.

🔵Что зреет за флагами

line-clamp заработал без вендорного префикса, правда пока без значения no-ellipsis, то есть обрезка с многоточием работает, а без многоточия ещё нет. Функция progress() считает значение по положению между минимумом и максимумом — заготовка для плавных зависимостей без акробатики с вложенными clamp().

В Nightly отдельно подъехала CSS Typed Object Model: работа со стилями из JS через типизированные объекты вместо разбора строк. До стабильной ветки ей далеко, но направление понятное.

🔵25 августа Chrome 152 ушёл в стейбл.

::backdrop, ::scroll-marker и ::view-transition теперь доступны как полноценные объекты CSSPseudoElement, а не только  как селекторы — закрыть диалог по клику на фон можно без ручного сравнения координат. Плюс появился relative alpha colors (alpha() из CSS Color 5) для точечного управления прозрачностью существующего цвета.

Свойство window-drag размечает области установленного веб-приложения, за которые окно двигается как за заголовок. Кастомный тайтлбар в PWA перестал требовать возни с обработчиками мыши и вычислением дельты курсора.

#frontendvkhub #дайджест

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

Frontend VK Hub

Speculation Rules: как готовить страницу до того, как по ней кликнули

Между кликом по ссылке и появлением новой страницы всегда есть пауза. Сервер может ответить за 30 миллисекунд, но дальше браузеру предстоит разобрать HTML, дотянуть стили и шрифты, выполнить скрипты — и человек всё это время смотрит на старую страницу.

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

В карточках — чем prefetch отличается от prerender, как настраивается момент срабатывания, какие лимиты держит Chrome и что делать с аналитикой, которая успевает выстрелить раньше визита.

#frontendvkhub #html #speculation_rules

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

Frontend VK Hub

Как приоритет слоёв побеждает специфичность в CSS

Каскад выбирает победителя по цепочке шагов: важность, origin, слой, специфичность, порядок объявления. На большой кодовой базе первые шаги обычно не используются, и всё сводится к гонке специфичности: reset с нулевой, дизайн-система со средней, продукт с высокой. Потом приходит правило вида .button.primary.active, и структура рассыпается.

@layer добавляет шаг, который стоит выше специфичности. Слои объявляются один раз, от менее приоритетного к более:

@layer reset, base, components, utils;

Порядок фиксируется этим первым объявлением, дальше правила складываются в слои по имени, а место в очереди не зависит от того, где физически лежит код.
@layer reset {
* { margin: 0; padding: 0; }
}
@layer components {
.button { padding: 12px 20px; background: blue; }
}
@layer utils {
.m-0 { margin: 0; }
}

.m-0 победит любой селектор из components, включая .card .button.primary:hover. Внутри одного слоя специфичность работает как обычно, между слоями она не значит ничего.
Второй частый сценарий — сторонняя библиотека в отдельном слое. Statement @layer разрешён до @import, и ставить его первым надёжнее: порядок задан явно, а не собирается из очерёдности импортов.
@layer reset, vendor, base, components, utils;

@import url("normalize.css") layer(reset);
@import url("bootstrap.css") layer(vendor);

Bootstrap уезжает в vendor, наши компоненты лежат выше и перебивают его без !important. Всё, что написано вне слоёв, живёт в неявном верхнем слое и перебивает любой именованный, поэтому миграция идёт мягко: @layer подключается в новом коде, старый unlayered работает поверх и переезжает по частям.

С !important порядок слоёв инвертируется, important из reset перебьёт important из utils. Менее очевидная часть той же механики: unlayered important оказывается слабее любого слоя. Правка, которая годами держала переопределение поверх всего, после переезда библиотеки в слой молча перестанет работать.

Слои вкладываются друг в друга: @layer components { @layer forms, buttons, cards; }. Приоритет считается по иерархии, а весь блок components занимает одно место в глобальном порядке. Рабочая раскладка обычно укладывается в шесть слоёв: reset, tokens, base, components, utils, overrides.

Поддержка приехала в браузеры ещё в 2022, сейчас @layer в статусе Baseline widely available. Единственное — Safari 15.3 и старше выбрасывает содержимое слоя целиком, без @supports там будет пустая страница.

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

#frontendvkhub #css

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

Frontend VK Hub

CSS @scope — изоляция стилей без Shadow DOM и препроцессоров

Изоляция стилей в CSS долго решалась косвенно: BEM с длинными именами, CSS Modules с хешированием, scoped-атрибут в Vue, Shadow DOM в Web Components. У каждого варианта своя цена. @scope даёт нативный способ ограничить область действия правил. В Chrome 118 с октября 2023, Safari 17.4 с марта 2024, Firefox 143 с сентября 2025 — и в 2026 везде.

Идея простая. Внутри @scope правила применяются только к элементам в поддереве заданного корня:

@scope (.card) {
h2 { color: purple; }
p { line-height: 1.6; }
}


Все h2 и p внутри .card получат эти стили. Классов вроде .card__title не нужно: селектор внутри scope пишется как есть, границу задаёт сам scope.

Верхняя граница задаётся через to:

@scope (.article) to (.comments) {
p { font-size: 1.1rem; }
}


Правило применяется ко всем p внутри .article, но не проникнет в .comments и вложенное. Решает классическую задачу: статья и блоки комментариев стилизуются независимо, но рендерятся внутри одной иерархии.

Второй вариант — inline-scope через <style> внутри HTML. Тег <style> с @scope без селектора привязывается к родителю:

<div class="widget">
    <style>
        @scope {
            h3 { color: teal; }
            button { background: navy; }
        }
    </style>
    <h3>Заголовок</h3>
    <button>Кнопка</button>
</div>



Ближайший CSS-аналог <style scoped> из Vue: описываем стили прямо в компоненте, они применяются только к его поддереву. Без прекомпилятора и обёрток.

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

Практический паттерн — темизация секции:

@scope (.section--dark) {
:scope { background: #1a1a1a; color: #eee; }
a { color: #7cb; }
button { background: #333; color: #eee; }
}


:scope — сам элемент, к которому привязана область (аналог :host в Shadow DOM). Всё внутри .section--dark перекрашивается разом, без каскадных префиксов и без глобальных override.

@scope ограничивает только те правила, что внутри самого @scope. Не блокирует утечку правил снаружи: если во внешнем CSS .card p { color: red }, оно применится к p внутри scope.

Если в проекте BEM используется только ради изоляции, или CSS Modules подключены только для избежания конфликтов имён, @scope часто закрывает задачу без сборочного шага.

#frontendvkhub #css #scope

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

Frontend VK Hub

Temporal API

Почти в каждом проекте найдётся место, где дату надо сдвинуть на месяц вперёд или посчитать разницу между двумя днями. И почти всегда ради этого в зависимостях лежит date-fns или dayjs, потому что штатный Date для такой работы не приспособлен: он мутабельный, нумерует месяцы с нуля и знает ровно одну зону, системную.

Temporal переносит эту арифметику в сам язык, и за последний год он перестал быть предметом ожидания. В Firefox поддержка появилась ещё в 139, в январе 2026 её добрали Chrome и Edge в версии 144, а в марте предложение дошло до Stage 4 и вошло в ES2026. Поэтому разговор сместился к переводу существующего кода, и об этом расскажем в карточках: какие в Temporal типы, как он считает даты и зоны и как всё это стыкуется со старым Date.

#frontendvkhub #temporal

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

Frontend VK Hub

scheduler.yield() — нормальный способ разбивать длинные задачи

Длинные JavaScript-задачи — главная причина плохого INP. Браузер не может обработать клик или показать спиннер, пока выполняется блок дольше 50 мс. До 2024 разбивать тяжёлую работу можно было только костылями вроде setTimeout(fn, 0) или await new Promise(r => setTimeout(r, 0)). Сейчас есть scheduler.yield() — нормальный API с приоритетной очередью.

Базовая проблема:

function processItems(items) {
for (const item of items) {
process(item); // ~1 мс
}
}
// 5 000 элементов = 5 секунд блокировки main thread

Старый способ — setTimeout(fn, 0):
async function processItems(items) {
for (const item of items) {
process(item);
await new Promise(r => setTimeout(r, 0));
}
}


Работает, но с двумя минусами. Первый — минимум 4 мс на каждый yield (минимум setTimeout по спецификации). Второй, и главный — continuation попадает в самый низ очереди, после всех остальных тасков. Если параллельно дёргается чужой код или сторонний скрипт, наш цикл встанет за ним.

Если параллельно дёргается чужой код или сторонний скрипт — наш цикл встанет за ним.

Новый способ — scheduler.yield():

async function processItems(items) {
for (const item of items) {
process(item);
await scheduler.yield();
}
}


scheduler.yield() возвращает управление браузеру, чтобы тот обработал input и рендеринг, и продолжает выполнение с того же места. Continuation попадает в высокоприоритетную очередь, не в конец. То есть наш цикл возобновляется раньше других тасков и при этом не блокирует кнопки и анимации.

Для постановки тасков с приоритетом есть scheduler.postTask():

scheduler.postTask(() => doImportant(), { priority: 'user-blocking' });
scheduler.postTask(() => doBackground(), { priority: 'background' });


Три приоритета: 'user-blocking' (для реакции на клик), 'user-visible' (по умолчанию), 'background' (для аналитики и работы в idle). Нормальный планировщик с приоритетами вместо «что-то в очередь и забыли».

Где применять

Циклы обработки больше 50 мс, гидратация тяжёлых компонентов, парсинг больших JSON, инициализация трекеров и аналитики при загрузке.

Поддержка: Chrome 129 (сентябрь 2024), пока нет в Safari и Firefox. По данным веба — 71,5% пользователей. Полифилл scheduler-polyfill падает на setTimeout(0) там, где нативного нет, так что в проде уже можно.

Если до сих пор используете setTimeout(0) или await new Promise(r => setTimeout(r, 0)) для разбиения тяжёлых циклов — самое время посмотреть на scheduler.yield(). Меньше задержек, приоритет не теряется, прогресс-бары и анимации не страдают.

А какие тяжёлые задачи вы разбиваете на куски в проде?

#frontendvkhub #javascript

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

Frontend VK Hub

Продолжаем рубрику «Знакомство с командой». Сегодня свою историю расскажет Денис Гордеев, руководитель подразделения Core Frontend ВКонтакте.

➡️ От школьного фана к фронтенду

Свой первый веб-проект я сделал ещё в школе: это была система для проведения олимпиад по программированию. Поступил в МГУПИ на специальность АСОИУ («автоматизированные системы обработки информации и управления») и со второго курса начал параллельно работать фулстек-разработчиком в разных компаниях. С каждым новым опытом перекос в сторону фронтенда становился всё сильнее.

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

➡️ Над чем работаешь

Сейчас я руковожу подразделением Core Frontend ВКонтакте. Мы отвечаем за весь фронтенд vk.com, m.vk.com и за библиотеки компонентов VKUI и VKCOM kit.

Работаем по нескольким направлениям: повышаем стабильность и надёжность платформы, развиваем архитектуру и инфраструктуру, BFF, серверный рендеринг, UI-тестирование и тестовые домены.

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

➡️ Почему роль лида — это постоянный баланс

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

➡️ Что сложно

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

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

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

➡️ Что заряжает

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

➡️ Как не выгораешь

У меня есть фраза: «Гори, чтобы светить». Мне важно получать удовольствие от работы. Интерес и ощущение смысла позволяют мне не выгорать. Я вижу результат и понимаю, как он помогает пользователям.

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

➡️ Как отдыхаешь

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

➡️ Что бы ты сказал себе в начале карьеры

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

#frontendvkhub #команда

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

Frontend VK Hub

@starting-style — анимация появления и исчезновения через чистый CSS

Годами анимация появления элемента в CSS решалась через JS: то принудительный reflow, то отложенный setTimeout, то двойной requestAnimationFrame.

С исчезновением было ещё хуже — display:none убивал любую exit-анимацию мгновенно. В 2024-м это починили двумя штуками: @starting-style и transition-behavior: allow-discrete. Baseline, поддержка везде.

Разберём, почему обычный transition ломается на появлении, как это чинит @starting-style, как анимировать <popover> и <dialog>, и один неочевидный подвох со специфичностью.

#frontendvkhub #css

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

Frontend VK Hub

Синхронизация состояния между вкладками — пять браузерных API

Когда у пользователя несколько вкладок одного приложения, обычный state не работает. Логин в одной будет подхвачен в других. Открытый сокет в одной — лишний груз в остальных.

В карточках разберём, как пять браузерных API закрывают разные части этой задачи.

#frontendvkhub #api

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

Frontend VK Hub

🔵Анимации с ощущением физики:
разбор squash and stretch приёма из классической анимации, при котором объект сжимается и растягивается в процессе движения. В интерфейсах обычно ограничиваются bounce, scale или slide, а деформацию не добавляют, но именно она делает движение живым. В статье интерактивные демки на SVG, CSS и библиотеке Motion.

🔵 Chrome DevTools получили CLI с поддержкой MCP.
Гайд о том, как подключить DevTools к автоматизированному воркфлоу, чтобы быстрее получать полезные данные о странице. Примеры построены вокруг WebPerf.

🔵 Что нового в JavaScript:
что уже в ES2025, что близится к ES2026 и что можно использовать уже сейчас. Отдельная часть — про совместимость новых возможностей языка с ИИ агентами при генерации и поддержке кода.

🔵 Как Google Code Assist встраивается в работу с React в VS Code.
Агент помогает с генерацией компонентов, хуков, тестов и бойлерплейта. Результат нужно ревьюить, проверять зависимости хуков и приводить код к командным соглашениям.

🔵 TanStack Form:
headless-библиотека для форм с сильной типизацией. Внутри useForm с автокомплитом по defaultValues, несколько режимов валидации, динамические списки полей, реактивный доступ к значениям других полей и композиция field-компонентов. Headless-подход даёт контроль над UI без навязанных стилей и лишних зависимостей.

🔵 Нативный random в CSS:
разбор random() и random-item() из CSS Values and Units Level 5. Автор объясняет, почему это не просто удобная фича, а шаг к генеративному CSS: меньше костылей через Sass, :nth-child и JavaScript, больше возможностей прямо на уровне layout и стилей.

#frontendvkhub #дайджест

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

Frontend VK Hub

Новый pnpm 11 меняет несколько базовых вещей одновременно: рантайм, формат модулей, движок хранения, публикацию, глобальные установки и политику безопасности. Минимальная версия рантайма — Node.js 22+, поддержка предыдущих версий прекращена. Сам pnpm теперь распространяется исключительно в формате ESM, получает хранилище на SQLite, а pnpm init по умолчанию задаёт "type": "module".

Хранилище на SQLite

Индекс хранилища переехал из миллионов JSON-файлов в единую базу SQLite по пути $STORE/index.db. Метаданные пакетов хранятся в бинарном формате, а манифест записан прямо в индекс, поэтому новый pnpm больше не читает package.json каждого пакета при разрешении зависимостей. Это даёт сокращение числа системных вызовов и операций чтения. Для монорепозиториев с большими графами зависимостей это ощутимое снижение накладных расходов.

Записи теперь идут напрямую в content-addressed пути. SQLite работает в WAL-режиме для безопасного параллельного доступа. Также добавлены pre-allocation памяти для .tar.gz с известным размером и NDJSON-кэш метаданных.

Нативная публикация

pnpm больше не делегирует команды публикации в npm. Команды publish, login, logout, view, deprecate, unpublish, dist-tag и version реализованы нативно, что убирает зависимость от поведения npm. Новый pnpm теперь сам обрабатывает OTP-поток, интерактивные промпты и веб-авторизацию.

Политика безопасности

Несколько настроек по умолчанию стали строже. minimumReleaseAge теперь 1440 минут. Свежеопубликованные версии пакета теперь недоступны для установки в течение 24 часов. Идея в том, что вредоносный код обычно обнаруживается быстро, и суточная задержка снижает риск установки заражённого релиза.

blockExoticSubdeps стал по умолчанию true: транзитивные зависимости не могут подтягиваться из прямых ссылок на .tar.gz. Добавлен trustPolicy с политикой no-downgrade, когда доверие к пакету не может ухудшаться со временем. strictDepBuilds теперь по умолчанию тоже true, т.е. скрипты сборки выполняются только для явно разрешённых пакетов. pnpm audit перешёл на фильтрацию по GHSA-идентификаторам, поскольку npm registry отключил CVE-ориентированные эндпоинты, а настройка auditConfig.ignoreCves теперь заменена на auditConfig.ignoreGhsas. Глобальные установки стали изолированными: каждый pnpm add -g получает собственную директорию, node_modules и lockfile. Это исключает конфликты между глобальными пакетами.

Конфигурация

.npmrc сведён к настройкам npm registry и авторизации. Специфичные для pnpm параметры перенесены в pnpm-workspace.yaml или глобальный config.yaml. Переменные окружения npm_config_* больше не используются, поэтому CI-системы, которые на них полагались, требуют ручных исправлений.
Сборочные флаги из pnpm 10 объединены в allowBuilds. Параметр ignorePatchFailures удалён, ошибки патчей теперь вызывают прерывание по умолчанию. Для миграции есть скрипт pnpm-v10-to-v11, который покрывает большинство механических изменений.

Миграция

Существует заметный риск для enterprise окружений. Тулчейны, которые полагаются на require() загрузку внутренних модулей, могут сломаться. Такие ошибки часто обнаруживаются только на этапе сборки в смежной команде.

Теперь pnpm 11 безопаснее против атак на цепочку поставок, но требует явного управления политиками при быстром цикле релизов.

#frontendvkhub #pnpm11

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