frontendhubvk | Unsorted

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

-

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

Subscribe to a channel

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

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

Frontend VK Hub

Условный рендеринг в JSX — это всегда тернарники, && и вложенные map. Чем сложнее шаблон, тем больше он превращается в головоломку из выражений.

TSRX предлагает другой подход: встраивать if, for, switch прямо в шаблон, а компилятору решать, как превратить это в валидный код для конкретного фреймворка. Проект описывают как «духовного наследника JSX».

TSRX — расширение TypeScript с новым типом файлов .tsrx. В них можно описывать шаблоны, scoped-стили и управляющие конструкции как часть языка, а не через JS-выражения. Файлы .tsrx полностью совместимы с .ts и .tsx: импорты работают в обе стороны, типы сохраняются при компиляции.

Как устроен компилятор

Пайплайн состоит из трёх этапов: лексический разбор, построение AST и кодогенерация. На последнем этапе плагины для конкретных фреймворков превращают общее AST в код целевого рантайма. Сейчас поддерживаются React, Preact, Ripple, Solid и Vue.

Архитектура плагинная — новый бэкенд добавляется отдельным плагином, без изменения ядра компилятора. Компилятор генерирует идиоматичный код для каждого таргета: для Solid — fine-grained reactivity, для React — стандартная компонентная модель. Накладные расходы на рантайм минимальны, потому что основная работа происходит на этапе компиляции.

Отдельный механизм — статический анализ для корректной работы хуков. Если внутри if или for окажется вызов хука, компилятор вынесет этот блок в отдельный компонент. Без этого React нарушит правила хуков, а другие фреймворки могут потерять гарантии реактивности. Документация предупреждает, что трансформации сложных паттернов требуют тщательного тестирования.

Зачем это нужно

Основной кейс — библиотеки компонентов и дизайн-системы, которые нужно поставлять под несколько рантаймов. Один tsrx-файл компилируется в код для React, Solid или Vue через смену плагина в сборке.

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

Что с готовностью

Проект в альфе. Документация прямо говорит: не использовать в продакшене.

Поддержка в IDE на ранней стадии — упоминается расширение для VS Code, но полноценные диагностика и рефакторинг пока в процессе. Интеграция в существующие сборочные пайплайны возможна, но потребует добавления компилятора как плагина и настройки кэширования.

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

Если пишете библиотеку компонентов под несколько фреймворков — присмотритесь к TSRX как к экспериментальной основе. Для продакшен же кода использовать пока рано.

#frontendvk #tsrx

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

Frontend VK Hub

Speculation Rules API — браузер рендерит следующую страницу ещё до клика

Обычный переход между страницами работает так: пользователь кликает, браузер идёт на сервер, получает HTML, парсит его, загружает стили, скрипты, картинки, запускает JS — и только после этого пользователь видит страницу.

Даже с хорошим кешем это занимает время. Speculation Rules API меняет момент начала этой работы — всё это происходит заранее, пока пользователь ещё читает текущую страницу.

Работает просто. Добавляешь на страницу JSON-блок с правилами, и браузер начинает фоново загружать или рендерить указанные URL:


<script type="speculationrules">
{
"prefetch": [{
"where": { "href_matches": "/blog/*" },
"eagerness": "moderate"
}],
"prerender": [{
"where": { "href_matches": "/checkout" },
"eagerness": "conservative"
}]
}
</script>


Два режима — два разных уровня агрессивности.

prefetch скачивает только HTML следующей страницы и держит его в памяти. Когда пользователь кликнет — браузер уже не идёт на сервер, он берёт готовый ответ.

prerender идёт дальше: браузер полностью рендерит страницу в скрытой вкладке — загружает все ресурсы, запускает JS, выполняет запросы. Переход становится буквально мгновенным, браузер просто показывает уже готовую страницу.

Параметр eagerness контролирует, когда именно браузер начинает работу. conservative — только когда пользователь начал нажимать кнопку мыши, ещё до отпускания. moderate — при наведении на ссылку на 200мс (на десктопе) или когда ссылка появляется в видимой области при скролле (на мобильном, с января 2026). eager — как только ссылка попала в viewport.

Shopify включили API на всей платформе в июне 2025. Настроили prefetch с conservative для безопасных маршрутов — и получили до 180ms прироста по LCP на P95. При этом специально не стали использовать prerender на старте, потому что он запускает весь JS, включая аналитику, а это задваивает счётчики просмотров.

Вот в чём главная проблема prerender: браузер выполняет весь JS фоново, ещё до перехода. Запросы в аналитику, обращения к API — всё это случается дважды. Для prerender стоит явно исключать чувствительные маршруты:

<script type="speculationrules">
{
"prerender": [{
"where": {
"and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": "/logout" } },
{ "not": { "href_matches": "/cart/*" } }
]
},
"eagerness": "moderate"
}]
}
</script>


Браузер держит в памяти не больше двух prerenders одновременно — по FIFO. Новый вытесняет старый. Поэтому агрессивные правила на больших листинговых страницах могут просто не успевать: пользователь скроллит быстрее, чем браузер рендерит.

Сейчас API поддерживают Chrome 109+, Edge 109+ и все Chromium-браузеры. Firefox объявил положительную позицию по стандарту для prefetch-части, но поддержку ещё не выпустил. В Safari поинтереснее: рабочая реализация уже есть, её написал инженер Shopify специально для этого API, но по умолчанию она отключена и доступна только за флагом в Safari Technology Preview. Когда появится в стабильном Safari — неизвестно. Все остальные браузеры просто игнорируют <script type="speculationrules">, страница работает как обычно, никакого fallback писать не нужно. Посмотреть поддержку браузеров можно тут.

#frontendvk #speculationrules

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

Frontend VK Hub

History API создавался для полных перезагрузок страниц. SPA-роутеры годами строили поверх него абстракции: popstate не стреляет при pushState, клики по ссылкам нужно перехватывать вручную, для хеша нужен отдельный слушатель, а history.length даёт только число вместо доступа к стеку.

Navigation API решает это единым событием navigate на window.navigation. К нему приходят клики по ссылкам, сабмиты форм, back/forward и программные переходы — один обработчик вместо россыпи слушателей.

➡️ Роутер на History API:

window.addEventListener("click", (e) => {
const link = e.target.closest("a");
if (!link) return;
e.preventDefault();
history.pushState({}, "", link.href);
render(link.href);
});

window.addEventListener("popstate", () => {
render(location.pathname);
});


➡️ Тот же роутер на Navigation API:
navigation.addEventListener("navigate", (e) => {
if (!e.canIntercept) return;

e.intercept({
async handler() {
const data = await loadRoute(new URL(e.destination.url));
render(data);
e.scroll();
},
});
});


intercept() отключает перезагрузку страницы — DOM обновляет роутер. Условие !canIntercept отсекает переходы, которые нельзя перехватить. Браузер показывает нативный лоадер, пока промис из handler не зарезолвится. e.scroll() восстанавливает прокрутку при back/forward без ручного сохранения координат.

Стек истории

history.length — просто число. Navigation API открывает стек через navigation.entries():
const prev = navigation
.entries()
.slice(0, navigation.currentEntry.index)
.findLast((e) => new URL(e.url).pathname.startsWith("/list"));

if (prev) navigation.traverseTo(prev.key);


Код находит последний /list в стеке и переходит к нему. На History API для этого нужен параллельный стек на глобальных переменных.

У каждой записи два идентификатора:
🔵id – для привязки кэша, уникальный, не переиспользуется
🔵key – для навигации по стеку, переиспользуется при replace

Состояние записи читается через getState() — оно иммутабельно, для обновления нужен updateCurrentEntry().

Отмена переходов встроена. Если пользователь нажал stop или начался новый переход до завершения текущего, e.signal отменяет незавершённый fetch:
e.intercept({
async handler() {
const data = await fetch(url, { signal: e.signal });
if (e.signal.aborted) return;
render(data);
},
});


Новый API поддерживается в Chrome 102+, Firefox 147+, Safari 26.2+. Полифилл — @virtualstate/navigation. React Router и TanStack Router пока остаются на History API, но оба уже обсуждают переход.

#frontendvk #javascript #navigationapi

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

Frontend VK Hub

Google Search сократил HTML с 107 kB до 60 kB для вернувшихся пользователей. Etsy, Amazon, eBay экономят до 96% на передаче данных.

➡️ Compression Dictionary Transport (RFC 9842) — стандарт HTTP, который переиспользует загруженные ответы как словари сжатия.

#frontendvk #compressiondictionarytransport #http

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

Frontend VK Hub

Разбираем State of HTML 2025, в котором поучаствовали ~6200 респондентов. Главная боль — не нехватка модных API, а невозможность стилизовать <select> и <input type="date">.

#frontendvk #stateofhtml

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

Frontend VK Hub

Делимся результатами ежегодного опроса Devographics о трендах CSS — State of CSS 2025.

Более 5500 респондентов и 50 CSS-фич. :has() — самая используемая (80.4%) и самая любимая (51.5%) фича.

#frontendvk #stateofcss

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

Frontend VK Hub

Разбираем новый отчет от Devographics — ежегодный независимый опрос экосистемы State of React 2025. Данные собирали с ноября 2025 по январь 2026, участие приняли около 3760 разработчиков.

🔵Самая ожидаемая фича: React Compiler
🔵Vite впервые обошёл webpack по использованию
🔵shadcn/ui вплотную приблизился к MUI
🔵Next.js удерживает лидерство по использованию, но теряет удовлетворённость
🔵React Foundation лидирует по позитивным оценкам сообщества

#frontendvk #react #stateofreact

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

Frontend VK Hub

Popover API

Каждый попап на сайте — это исторически минимум 30 строк JS: открыть, закрыть по клику снаружи, поймать Escape, не дать фокусу уйти за пределы, поднять z-index выше всего остального. Popover API делает это нативно. С января 2025 он в Baseline — работает во всех современных браузерах без полифилов.

#frontendvk #javascript #popoverapi

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

Frontend VK Hub

State of JavaScript 2025

Недавно был опубликован State of JS 2025 — ежегодный опрос экосистемы JavaScript от Devographics. В этом году его прошли почти 13 000 разработчиков. Собрали самое важное в карточках.

🔵Самый быстрорастущий инструмент: Vitest и Playwright (+14% год к году)
🔵Самая высокая удовлетворенность: Vite (98% положительных оценок)
🔵Наивысший интерес: Vitest (83%)
🔵Next.js — самый обсуждаемый и самый поляризующий проект

#frontendvk #javascript

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

Frontend VK Hub

@layer — каскадность без !important

Специфичность в CSS всегда была проблемой. Один сторонний компонент с высокой специфичностью, и ты пишешь !important, потом !important поверх !important. @layer делает все это проще.

#frontendvk #css #layer

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

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

🔹 Между изменением DOM и пикселями на экране браузер проходит конвейер из нескольких этапов.

Понимание того, какой этап запускает каждое свойство, отделяет плавный интерфейс от дерганого — и объясняет, почему один цикл на JS может стоить кадра.

#frontendvkhub

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

Frontend VK Hub

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

Что же из старых решений всё ещё необходимо? Разберём в карточках ⬇️

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

Frontend VK Hub

В Vite 7 пайплайн был расколот надвое: esbuild оптимизировал зависимости в dev, а Rollup собирал production-бандл. У каждого движка своя семантика модулей и свои правила tree-shaking. Vite 8 убирает оба и ставит на их место один Rust-бандлер.

#frontendvk #vite8 #javascript #typescript

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

Frontend VK Hub

🔵Chrome 145: column-height и column-wrap
Новые свойства для multi-column layout, которые позволяют строить 2D-потоки с вертикальным заполнением. Пока только Chrome 145+.

🔵focusgroup — нативная клавиатурная навигация
Новый HTML-атрибут focusgroup позволяет делать arrow-key навигацию без ручного управления tabindex — браузер сам перемещает фокус внутри контейнера.

🔵Intl API — форматирование без зависимостей
Intl форматирует даты, время, числа, списки и текст с учётом локали прямо в браузере. Никаких лишних килобайт в бандле — всё из коробки.

🔵Сравнение JS-минификаторов
Бенчмарк популярных минификаторов (SWC, oxc-minify, esbuild, terser, uglify-js) по размеру выходного файла и скорости. Полезно при выборе инструмента для production-сборки.

🔵CSS-анимации как state-машина
Запоминание прошедших состояний интерфейса через CSS-анимации: например, был ли элемент в hover. Значение записывается в CSS-переменную через keyframes.

🔵 Диапазон дат на чистом CSS
Подсветка диапазона между двумя датами через :nth-child(N of selector) и :has. Вся визуализация на CSS, JS нужен только для обработки кликов.

📌 Новая статья от инженеров VK на Хабр:
Как мы пережили цветовой кризис в RuStore и нашли путь к тёмной стороне темы

#дайджест #frontendvk

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

Frontend VK Hub

CSS :has() — не parent selector, а условная логика прямо в CSS

:has() часто объясняют как «наконец-то parent selector» — можно стилизовать родителя в зависимости от дочернего элемента. Это правда, но это самый скучный способ его использовать. Интереснее то, что :has() по сути добавляет в CSS условную логику, которую раньше можно было выразить только через JavaScript.

В январе 2025 :has() получил статус Baseline Newly Available после исправления бага в iOS Safari — теперь работает во всех современных браузерах. По State of CSS 2025 — один из самых используемых и любимых CSS-селекторов года наравне с Grid и нативным нестингом.

➡️ Блокировка скролла без JS. Классическая задача при открытии модалки — запретить скролл на <body>. Обычно это две строчки JS: добавить класс при открытии, убрать при закрытии. С :has():

body:has(dialog[open]) {
overflow: hidden;
}
<dialog> открыт - скролл заблокирован. Закрыт - разблокирован. Ни строчки JS.


➡️ All-but-me hover. Эффект, когда при наведении на один элемент все остальные затемняются — раньше требовал JS-обработчика на каждый элемент. Теперь:
.gallery:has(.card:hover) .card:not(:hover) {
opacity: 0.5;
filter: grayscale(0.3);
}


Читается буквально: «если галерея содержит hovered card — все card которые не hovered получают opacity 0.5».

➡️ Quantity queries. Стилизовать контейнер в зависимости от количества дочерних элементов:
/* Grid с одной колонкой если элемент один */
.grid:has(> :nth-child(1):last-child) {
grid-template-columns: 1fr;
}

/* Две колонки если элементов два */
.grid:has(> :nth-child(2):last-child) {
grid-template-columns: repeat(2, 1fr);
}

/* Три и больше - три колонки */
.grid:has(> :nth-child(3)) {
grid-template-columns: repeat(3, 1fr);
}


Адаптивный layout в зависимости от контента — без медиазапросов и без JS.

➡️ Форм-стейты без JS. Подсветить поле ввода и его label, когда значение невалидно:
.field:has(input:user-invalid) label {
color: var(--error);
}

.field:has(input:user-invalid) input {
border-color: var(--error);
background: var(--error-bg);
}


:user-invalid срабатывает только после того, как пользователь взаимодействовал с полем, а не при загрузке. В связке с :has() — визуальная валидация формы только на CSS.

👆 Одно предостережение по производительности: не использовать :has() с широкими селекторами вроде body:has(*:hover) или *:has(.active). Браузеру нужно пересчитывать такой селектор при каждом изменении DOM. Чем конкретнее якорный элемент — тот, что стоит до :has(), тем дешевле пересчёт.

#frontendvk #css #selectors

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

Frontend VK Hub

CSS Anchor Positioning: позиционирование тултипов без JS

Каждый тултип или дропдаун на странице — это исторически JavaScript.

Popper.js, Floating UI, собственные хелперы на getBoundingClientRect. Причина одна: CSS не умел позиционировать элемент относительно другого произвольного элемента, особенно если они в разных частях DOM. С 2025 года это умеет браузер.

CSS Anchor Positioning работает в Chrome 125+, Firefox 134+ и Safari 18.2+. Для старых браузеров есть полифил от OddBird.

Идея простая: один элемент объявляется якорем через anchor-name, другой привязывается к нему через position-anchor и position-area.


.button {
anchor-name: --my-btn;
}

.tooltip {
position: absolute;
position-anchor: --my-btn;
position-area: top center;
margin-bottom: 8px;
}


position-area — сетка 3×3 вокруг якоря. top center — над якорем по центру. bottom span-right — под якорем с выравниванием вправо. Никакого calc(), никакого getBoundingClientRect.

Главная проблема старых JS-решений в том, что тултип выходит за края экрана. Anchor Positioning решает это нативно через position-try-fallbacks:

.tooltip {
position: absolute;
position-anchor: --my-btn;
position-area: top center;
position-try-fallbacks: bottom center, right span-top, left span-top;
}


Браузер последовательно пробует fallback-позиции, пока тултип не вписывается в viewport. Раньше все это требовало сотен строк JS с обработкой ресайза и скролла.

В связке с Popover API получается полностью декларативный тултип — без единой строки JavaScript:

<button popovertarget="tip" style="anchor-name: --btn">
Наведи
</button>
<div id="tip" popover style="position-anchor: --btn; position-area: top center">
Подсказка
</div>


Одно ограничение: поведение при overflow немного отличается между Chrome и Safari (открытый баг в Chromium). Для продакшена стоит тестировать оба браузера и использовать @supports (anchor-name: --test) для feature detection.

#frontendvk #css #anchorpositioning

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

Frontend VK Hub

Moment.js, Day.js и date-fns суммарно скачивают больше 100 миллионов раз в неделю. Три библиотеки, которые существуют только потому, что встроенный Date не справляется с базовыми задачами.

В марте 2026 Temporal достиг Stage 4 и вошёл в ES2026. Теперь это стандарт и вопрос только в том, когда все браузеры догонят.

В чём проблема Date

Date смешивает разные сущности в одном объекте: момент времени, локальную дату, парсинг строк, работу с часовыми поясами. Он мутабельный, а арифметика ломается на переходах DST, при сравнении дат и при добавлении дней. В результате целый класс багов живёт в JS-коде десятилетиями.

Как устроен Temporal

Temporal разделяет эти смыслы на отдельные типы, все объекты иммутабельны:
🔵 Temporal.Instant — точный момент с наносекундной точностью, без зоны и календаря;
🔵 Temporal.PlainDate — календарная дата без времени, подходит для дней рождения и дедлайнов;
🔵 Temporal.ZonedDateTime — дата-время с IANA-зоной и календарём, корректно обрабатывает переходы на летнее время.

Типичный сценарий — прибавить две недели:

// Date — мутирует объект
const d = new Date();
d.setDate(d.getDate() + 14);


Передали такой объект в функцию и исходная дата изменилась без предупреждения.
// Temporal — возвращает новый объект
const now = Temporal.Now.plainDateISO();
const inTwoWeeks = now.add({ days: 14 });


now остался нетронутым, при этом valueOf() у Instant и ZonedDateTime бросает TypeError, т.к. неявное сравнение больше не работает молча.

Арифметика и DST

Арифметика длительностей тоже стала чище. Вместо деления миллисекунд:
// Date — считать руками
const diffMs = endDate - startDate;
const days = Math.floor(diffMs / 86400000);
const hours = Math.floor((diffMs % 86400000) / 3600000);

// Temporal — готовый Duration
const duration = start.until(end, { largestUnit: "day" });
duration.days; // 1
duration.hours; // 8
duration.total("hours"); // 32


Duration не балансирует автоматически — 100 секунд остаётся PT100S, а не PT1M40S. Если нужна нормализация, то вызывайте .round({ largestUnit: 'hour' }). Это сознательное решение: разработчик видит ровно то, что задал.

DST обрабатывается явно. При переходе часов вперёд локальное время может не существовать — час просто пропускается. Temporal даёт стратегию: earlier, later, compatible или reject. Для календарей, бронирований и напоминаний это закрывает целый класс багов.

Что учесть при миграции
🔵dayOfWeek следует ISO 8601: понедельник — 1, воскресенье — 7, а не 0 и 6 как в Date.getDay()
🔵Сравнение дат — только через Temporal.PlainDate.compare(), операторы > и < молча возвращают false
🔵Chrome 144+, Firefox 139+, Edge 144+ поддерживают нативно но Safari пока отстаёт: там доступен только через Technology Preview
🔵Для продакшена с широким охватом — полифилл @js-temporal/polyfill, но он добавляет вес в бандл

Temporal заставляет выбирать правильный тип под задачу. Ментальную модель придётся перестраивать, но взамен фронтенд получает работу с датами, которая не ломается на часовых поясах и арифметике.

#frontendvk #temporal

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

Frontend VK Hub

Сегодня знакомимся с Андреем Едуновым, фронтенд-техлидом RuStore. Он пришёл в IT ещё во времена модемного интернета, успел из него уйти, пропустить несколько технологических революций и вернуться, чтобы строить крупнейший российский магазин приложений.

➡️ С чего началась твоя карьера в IT?

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

Так я узнал про HTML, купил книжку и написал свой первый сайт — максимально простой, конечно. И понял: это моё. Моя первая должность называлась «программист-курьер». Я кодил сайт, а потом на дискетке вёз его деплоить на сервер. Вот такой у меня был пайплайн. Возможно, я был первым в мире девопсом.

➡️ С каким образованием можно стать фронтендером?

У меня высшее геодезическое. Вообще мимо IT. Тогда даже слова «фронтенд» не было — была «вёрстка», а верстальщиков называли недопрограммистами. И я как раз из таких. Но это не помешало мне дорасти до руководителя отдела дизайна и вёрстки в EPAM.

Потом я решил сменить сферу и ушёл из IT на 8 лет. Пока меня не было, в индустрии произошло несколько революций: jQuery, прототипы, Backbone, React, Node.js, сборщики, современные архитектурные подходы. Всё это пришлось догонять практически с нуля.

Возвращение было жёстким: несколько месяцев я буквально жил на JavaScript курсах, чтобы просто вернуться в форму. Дальше — отечественный финтех, зарубежные стартапы, крипта и, конечно, вишенка на торте — RuStore.

➡️ Над чем ты работаешь сейчас?

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

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

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

➡️ Чем ты занимаешься вне работы?

На удалёнке начинаешь работать больше, чем в офисе, поэтому без хобби не обойтись. Катаюсь на сноуборде.

А на прошлый день рождения в мою жизнь снова вошла гитара — я играл в детстве, но петь не умел. Сейчас попробовал вновь пойти на вокал — занимаюсь почти год и даже выступил в клубе «16 тонн» на Арбате. Теперь это уже не просто хобби, а отдельная часть жизни.

#frontendvk #команда

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

Frontend VK Hub

🔵Navigation API — теперь кросс-браузерный
Navigation API становится новой основой клиентского роутинга: можно подписываться на изменения URL и перехватывать навигацию через event.intercept, делая адресную строку единым источником состояния без ручной работы с History API.

🔵Новый HTML-атрибут `focusgroup`
Microsoft Edge и Chromium уже поддерживают focusgroup, который нативно управляет клавиатурной навигацией внутри контейнеров — стрелки, пропуск disabled-элементов и восстановление фокуса теперь можно реализовывать без JS-логики.

🔵Claude нашёл 14 критических уязвимостей в Mozilla Firefox
Команда Anthropic использовала Claude для анализа исходников Firefox и обнаружила ранее неизвестные критические баги безопасности — важный сигнал о том, как LLM начинают реально применяться в аудитах сложных кодовых баз.

🔵CodePen 2.0 — переход к новой архитектуре платформы
CodePen готовит обновление с новым компилятором, расширяемой системой блоков и возможной интеграцией AI-инструментов — это может изменить привычный workflow прототипирования интерфейсов прямо в браузере. Обсуждение можно послушать в новом выпуске CodePen Radio.

🔵Opera получила 4 награды iF Design Award за интерфейс браузера
Opera стала самым награждаемым браузером в категории цифровых интерфейсов — заметный тренд на конкуренцию браузеров уже не только на уровне движков, но и UX-слоя вокруг них.

📌 Новые статьи от инженеров VK на Хабр:
🔵О специфике разработки приложений под Smart TV: личный опыт перехода от веба к ТВ
🔵От события до дашборда в облаках: практика по созданию потоковой платформы на Kubernetes

#дайджест #frontendvk

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

Frontend VK Hub

using — JS умеет закрывать ресурсы сам

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


const conn = db.connect();
try {
return conn.query('SELECT ...');
} finally {
conn.close(); // без этого будет утечка при любой ошибке выше
}


ES2026 добавляет using. Работает как const, но при выходе из блока автоматически вызывает [Symbol.dispose]() на объекте, даже если вылетело исключение.


class DbConnection {
[Symbol.dispose]() {
this.conn.close();
}
}

function processData() {
using db = new DbConnection();
return db.query('SELECT ...');
// conn.close() вызовется здесь автоматически
}


Для асинхронных ресурсов — await using с [Symbol.asyncDispose]():

async function writeLog() {
await using handle = await openFile('log.txt');
await handle.write('done');
// файл закроется после строки выше, не нужен finally
}


Это удобно в тестах. Раньше mock-сервер или тестовое соединение закрывали в afterEach, и это отдельный блок, который легко забыть или написать неправильно. С using ресурс живёт ровно столько, сколько длится тест:

test('sends request', async () => {
await using server = createMockServer();
// server.close() сам вызовется в конце теста
});


TypeScript поддерживает using с версии 5.2. Для браузеров нужен таргет ES2026 или полифил через Symbol.dispose.

#frontendvk #javascript #typescript

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

Frontend VK Hub

jQuery 4.0 — первый за 10 лет мажорный апдейт легендарной библиотеки

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

Ключевые изменения

🔵Удалена поддержка старых браузеров, остались только IE11 и 3-5 последних версий современных браузеров.
🔵Оптимизирован размер бандла. Появилась slim-сборка размером всего 19.5 КБ в gzip.
🔵Появился tree-shaking за счет добавления поддержки ES-модулей.
🔵Поддержка Trusted Types и использование <script> тега для загрузки модулей для предотвращения CSP ошибок.

Сами разработчики jQuery выделяют то, что хотели сделать уже очень давно, а именно удаление:
🔵незадокументированных функций;
🔵внутренних переменных;
🔵устаревших API.

Так были удалены поддержанные в современном JS 13 deprecated-утилит, включая:
🔵jQuery.isArrayArray.isArray();
🔵jQuery.isNumeric → нативные проверки;
🔵jQuery.trimString.prototype.trim();
🔵jQuery.parseJSONJSON.parse().

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

Актуальность

Несмотря на возраст, пакет jQuery по-прежнему получает десятки миллионов загрузок в месяц (70+ млн по npm). А по данным W3Techs он до сих используется более чем на 70% всех веб-сайтов. Особенно явно jQuery оставил свой след в enterprise-сегменте и CMS-решениях (в частности Wordpress).

Как тебе такое, Кирилл?

«Услышав об этом событии, я был искренне удивлен. В весомой части проектов использование jQuery принято избегать и упоминать о библиотеке разве что в контексте мема. Тем не менее сложно отрицать повсеместную распространенность библиотеки, а потому и новость о таком обновлении не видится исключительно смешной и не обоснованной. Более того, вместе с выпуском 4.* версии, разработчики сразу частично охарактеризовали и последующий 5.* апдейт.

Если говорить про характер изменений, то их можно описать, как глобальный рефакторинг с клинкодом, багофиксингом и адаптацией под современные стандарты (esm, csp), которые де факто являются таковыми уже не год и не два. Поэтому возникает вопрос: “Почему только сейчас?”.

Допускаю, что разработчики ждали прохождения своеобразного трешхолда по уменьшению присутствия старых браузеров в мире веба, на что намекает их аккуратный подход по внедрению изменений со словами из описания выпущенного ими релиза: “мы ожидаем, что большинство юзеров смогут обновиться с минимальными изменениями в их коде”. Но разве не разумно оставлять выбор о необходимости поддержки старых браузеров потребителям и параллельно делать то, что делают успешные проекты, а именно активно и своевременно адаптировать инструменты под потребности своего сообщества?

Оценивая потенциальный эффект от обновления, думаю, что это обновление хоть и несколько развязывает руки по использованию jQuery в современных реалиях, но оно НЕ запустит массовую работу над заблокированном техдолгом, потому что если >70% сайтов до сих пор мирится с наличием у себя jQuery, четверть из которых вообще имеет 1 или 2 версию, то вопрос - откуда должна взяться мотивация на переход к 4.* версии, когда разворачивание React/Svelte/Vue/etc в формате SPA и микро-фронтов — это шаблонно и привычно, а отличное от удаления прикосновение к jQuery в отдельных проектах не иначе как моветон​», — рассказал Кирилл Радыгин, ​руководитель Web платформы Одноклассников.


А что думаете вы — как в 2026 году видите применимость jQuery в проектах, в которых уже есть React/Svelte/Vue?

#frontendvk #jquery

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