<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Веб-разработка</title>
    <description>Статьи, инструменты, последние новости и учебные материалы для веб-разработчиков</description>
    <link>https://tproger.ru/tag/web</link>
    <atom:link href="https://tproger.ru/tag/web/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Thu, 01 Oct 2026 11:39:46 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Веб-разработка</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Оптимизация изображений для веба: где теряются мегабайты</title>
      <link>https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v</link>
      <comments>https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v</guid>
      <description><![CDATA[<p>Оптимизация изображений для веба: размер в пикселях, формат под тип картинки, AVIF против WebP и сжатие в браузере. Проверьте свои картинки по чеклисту.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v">Оптимизация изображений для веба: где теряются мегабайты</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Алгоритмы сжатия]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Sep 2026 09:00:41 GMT</pubDate>
      <content:encoded><![CDATA[<p>Картинки обычно оказываются самой тяжёлой частью страницы, и почти всегда они тяжелее, чем нужно. Скриншот интерфейса на 2,1 МБ ужимается до 102 КБ без заметной глазу разницы, а фотография на 4,7 МБ теряет три четверти веса ещё до того, как вы дотронетесь до качества сжатия.</p><p>Разница между четырёхсекундной загрузкой и загрузкой меньше секунды обычно лежит именно здесь, а не в бандле скриптов. Ниже пошаговая оптимизация изображений: что делать первым, какой формат выбирать под какой тип картинки и почему кодировать современные форматы нужно на сборке, а не на лету.</p><p>Первым делом уменьшайте размер в пикселях, а не качество: фотография 6000×4000 в карточке шириной 1200 пикселей это чистые потери. Один этот шаг убрал 77% веса тестового снимка.</p><p>Формат выбирается под тип картинки: фотографиям WebP или AVIF, скриншотам и интерфейсам сжатие без потерь, логотипам SVG, анимациям анимированный WebP вместо GIF.</p><p>AVIF при равном качестве весит вдвое меньше JPEG, но кодируется примерно в пятнадцать раз дольше, поэтому генерировать его нужно на этапе сборки.</p><p>Метаданные съёмки занимают от 10 до 30 КБ на файл и в вебе не нужны ни для чего.</p><p>Сжатие с потерями на тексте и резких границах даёт видимые артефакты: скриншоты и логотипы жмутся только без потерь, зато на 20–60%.</p><h2>Шаг, который экономит больше всех остальных</h2><p>Прежде чем подбирать кодек и качество, посмотрите на фактические размеры. Фотография 6000×4000 в карточке шириной 1200 CSS-пикселей отдаёт браузеру в двадцать пять раз больше пикселей, чем нужно обычному экрану, и вшестеро больше, чем нужно экрану с двойной плотностью.</p><p>В замерах автора чеклиста <a href="https://dev.to/_544bf5cbd223c35a49756/image-optimization-the-complete-2026-checklist-for-faster-websites-3pi5">одно только уменьшение до реально отображаемого размера ужало тестовое изображение с 4,7 МБ до 1,1 МБ</a>. Это минус 77% при нулевой потере качества: пиксели, которых не видно, просто перестали передаваться.</p><p><b>Как определить нужный размер:</b><br />Отправная точка это ширина контейнера в CSS-пикселях. На обычном экране она же и есть нужная ширина в физических пикселях, на плотных экранах нужно кратно больше: у части ноутбуков это двойка, у большинства современных смартфонов тройка. Поэтому правильный инструмент здесь не фиксированный множитель, а атрибут srcset с несколькими вариантами файла: браузер сам возьмёт тот, что соответствует плотности экрана посетителя.</p><h2>Формат под тип изображения, а не один на всё</h2><p>Самая частая ошибка — выбрать один формат и применять его ко всему подряд. Между фотографией с плавными градиентами и скриншотом с текстом и резкими границами разница принципиальная, и сжимаются они противоположными способами.</p><ul><li>Фотографии — WebP (на 30–50% меньше JPEG) или AVIF (ещё примерно на 30% меньше WebP).</li><li>Скриншоты и элементы интерфейса — PNG или WebP без потерь.</li><li>Логотипы и иконки — SVG: вектор весит копейки и масштабируется без предела.</li><li>Анимации — анимированный WebP вместо GIF, это экономит 60–80% веса.</li></ul><p>Отдельно про текст. Сжатие с потерями на буквах и резких границах создаёт заметные ореолы вокруг символов, поэтому скриншоты и логотипы обрабатываются только алгоритмами без потерь. Инструменты вроде oxipng ужимают такие файлы на 20–60%, не меняя при этом ни одного пикселя.</p><h3>Конвертация и сжатие — это два разных действия</h3><p>Перевод PNG в JPEG экономит место. Сжатие получившегося JPEG экономит ещё столько же, и про этот второй проход регулярно забывают. Для фотографий рабочий диапазон качества это 75–82%: от стопроцентного такая картинка визуально неотличима, а весит заметно меньше.</p><h3>Метаданные, которые вы отдаёте бесплатно</h3><p>В файле с камеры или из редактора лежат EXIF, координаты GPS, модель камеры и метки программы обработки. Для показа в браузере это бесполезный груз весом от 10 до 30 КБ на файл, за одним исключением: тег ориентации. Часть снимков с телефона хранит пиксели неповёрнутыми и полагается на него, поэтому поворот нужно применить к самим пикселям до того, как метаданные срежутся, иначе фотографии лягут набок. На каталоге из тысячи товарных снимков набегает до 30 МБ трафика ни за что, а координаты съёмки вдобавок могут оказаться данными, которые вы не собирались публиковать.</p><h2>AVIF: что это и почему его нельзя кодировать на лету</h2><p>AVIF (AV1 Image File Format) выпущен Alliance for Open Media в 2019 году и построен на внутрикадровом кодировании видеокодека AV1. По сути это инструменты сжатия одного кадра AV1, упакованные в самостоятельный контейнер для картинок.</p><p>Перед WebP у него два практических преимущества: выше степень сжатия при равном качестве и глубина цвета до 12 бит с поддержкой расширенного динамического диапазона, тогда как WebP ограничен восемью битами и обычным диапазоном. Достигается это за счёт заметно более богатого набора инструментов предсказания, унаследованного от видеокодека.</p><h3>Сколько это в килобайтах</h3><p>В сравнительном тесте <a href="https://dev.to/uglypeardata/avif-format-guide-the-next-generation-image-compression-std-4oa5">брали пейзажный кадр 1920×1080 с градиентами неба, текстурой листвы и границами зданий, исходник в BMP весил 5,93 МБ</a>. Целевое качество задавали по метрике структурного сходства: она сравнивает сжатую картинку с исходной, где единица означает полное совпадение, а 0,92 примерно соответствует порогу, за которым разницу перестают замечать глазом. Результаты:</p><p>На листве и градиентах неба разница видна и глазом: JPEG на низком битрейте показывает цветовые блоки, у AVIF артефактов практически нет. Отвечают за это многоуровневые фильтры внутри цикла кодирования, которые заглаживают границы блоков и восстанавливают детали текстур.</p><p>Плата за это — время. Кодирование AVIF примерно в пятнадцать раз дольше JPEG и вчетверо дольше WebP, потому что выбор разбиения и типа преобразования требует перебора с оптимизацией. Зато декодирование медленнее JPEG всего вдвое, и на просмотр это почти не влияет. Практический вывод прямой: генерируйте AVIF заранее, на этапе сборки. Сервисы доставки изображений кодируют его и по запросу, но только с кешированием результата, чтобы платить за кодирование один раз на вариант, а не на каждого посетителя. Чего делать нельзя, так это кодировать заново при каждом обращении.</p><h3>Как отдавать современный формат и не потерять старые браузеры</h3><p>Поддержка AVIF в браузерах составляет примерно 96%, но подстраховка всё равно нужна. Делается она тегом &lt;picture&gt;: браузер берёт первый формат, который понимает, и до остальных не доходит.</p><p>Атрибуты width и height здесь не декоративные: без них браузер не знает пропорций до загрузки файла и подвёрстывает страницу заново, когда картинка приходит. Это тот самый прыжок содержимого, который портит метрику визуальной стабильности. Атрибут loading=lazy убирает изображения за пределами первого экрана из очереди, конкурирующей за отрисовку главного элемента.</p><p>Именно за пределами: на картинку первого экрана его ставить нельзя. Отложенная загрузка задержит ровно тот элемент, скорость появления которого и меряет метрика отрисовки основного содержимого. Там уместен противоположный по смыслу fetchpriority=high.</p><h2>Сжатие в браузере: почему это вообще возможно</h2><p>Браузер умеет декодировать, преобразовывать и кодировать изображение прямо на устройстве, не отправляя файл никуда. Для товарных снимков, клиентских материалов и прочего чувствительного это снимает целый шаг из конвейера вместе с вопросом, где полежит копия.</p><p>Речь здесь уже не про ассеты вашего сайта, которые готовятся на сборке. Речь про картинки, которые в браузер приносит сам пользователь: форма загрузки в личном кабинете, объявление на маркетплейсе, вложение в заявку. Сжать их до отправки на сервер можно прямо во вкладке, и это снимает и трафик, и вопрос о том, где полежит оригинал.</p><p>Автор одного из таких инструментов <a href="https://dev.to/_544bf5cbd223c35a49756/how-i-built-a-browser-image-compressor-that-handles-30-images-at-once-56k4">разобрал устройство своего конвейера</a>, и его опыт пригодится всем, кто выносит тяжёлые вычисления во фронтенд.</p><h3>Вся тяжёлая работа уходит из главного потока</h3><p>Перекодирование снимка 4000×4000 нагружает процессор настолько, что в главном потоке интерфейс замирает, а браузер показывает предупреждение о зависшей странице. Поэтому весь конвейер живёт в Web Worker: главный поток отвечает за выбор файлов, превью и состояние, а рабочий поток декодирует через createImageBitmap, применяет преобразования и кодирует через OffscreenCanvas. Именно через него, а не через canvas.toBlob: последний это метод DOM-элемента, а DOM в рабочем потоке отсутствует, и нужный метод там называется convertToBlob.</p><p>Важная деталь производительности: передавать данные между потоками нужно как ArrayBuffer через механизм передачи владения, а не структурным клонированием. На пачке из тридцати изображений это разница между мгновенным откликом и лишними полусекундами нагрузки на сборщик мусора для каждого файла.</p><h3>Три ошибки, которые ищутся дольше всего</h3><p><b>Рабочий поток не имеет доступа к window.</b> Причём не только напрямую: достаточно подключить библиотеку, которая трогает window на верхнем уровне модуля. В консоли разработчика появляется ошибка обращения к неопределённому объекту, а вот в интерфейсе не появляется ничего: если сбой рабочего потока никак не показан пользователю, тот видит вечный спиннер. Лечится ревизией всех импортов рабочего потока: библиотеки, завязанные на браузерное окружение, остаются в главном потоке и передают в рабочий поток уже готовые данные.</p><p><b>Округление сломало масштабирование.</b> Быстрый путь изменения размера использовал округлённый шаг по пикселям. На больших изображениях округление уводило исходную координату за пределы строки, и картинка выходила разрезанной по горизонтали с чёрной мозаикой внизу. Помогли точные дробные коэффициенты и ограничение по границам в каждом ручном проходе по пикселям.</p><p><b>Асинхронный обработчик сообщений перепутал порядок.</b> Обработчик стал ждать преобразование уже после кодирования, а асинхронные обработчики порядок не сохраняют: состояние поворота разъехалось с готовым изображением. Полностью синхронным такой обработчик не сделать, декодирование и кодирование асинхронны по своей природе. Работает другое: обрабатывать сообщения строго по одному, не начиная следующее до завершения предыдущего, и хранить состояние вроде угла поворота рядом с данными конкретного сообщения, а не в общей переменной.</p><p><b>Заголовки безопасности ломают рабочие потоки молча:</b><br />Блокирует загрузку скрипта заголовок Cross-Origin-Embedder-Policy: он требует, чтобы каждый сторонний ресурс отдавал разрешающий заголовок, иначе браузер молча его отбрасывает. Cross-Origin-Opener-Policy на это не влияет, но включают их обычно парой, поэтому и ломается всё в одном релизе. Любое изменение заголовков безопасности проверяйте на настоящем развёрнутом стенде, а не только на машине разработчика.</p><h2>Что это даёт в цифрах</h2><p>Скриншот 1920×1080 проходит такой путь: исходный PNG весит 2,1 МБ, после уменьшения и перевода в WebP с качеством 75% — 186 КБ, то есть минус 91%. Тот же кадр в AVIF занимает 102 КБ, минус 95% от исходного.</p><p>Именно эти проценты и отделяют страницу, которая грузится четыре секунды, от страницы, которая укладывается в одну.</p><h2>Что забрать с собой</h2><p>Порядок действий важнее набора инструментов. Сначала пиксели, потом формат под тип изображения, потом второй проход сжатия, и только затем разговор про кодеки нового поколения. Обратный порядок даёт красивую строчку в отчёте и почти никакого эффекта на реальной странице.</p><p>Материалы разбора: <a href="https://dev.to/_544bf5cbd223c35a49756/image-optimization-the-complete-2026-checklist-for-faster-websites-3pi5">чеклист оптимизации с замерами</a>, <a href="https://dev.to/uglypeardata/avif-format-guide-the-next-generation-image-compression-std-4oa5">техническое устройство AVIF и сравнительный тест форматов</a> и <a href="https://dev.to/_544bf5cbd223c35a49756/how-i-built-a-browser-image-compressor-that-handles-30-images-at-once-56k4">разбор браузерного конвейера сжатия</a>.</p><p>Откройте свою главную страницу с открытой панелью сети и отсортируйте запросы по размеру. Первые три строки почти наверняка окажутся картинками, и это ваша ближайшая оптимизация изображений: уменьшить их вдвое реально за один вечер.</p>]]></content:encoded>
    </item>
    <item>
      <title>Dawarich 1.14 рисует миллион GPS-точек за секунду вместо падения браузера</title>
      <link>https://tproger.ru/news/dawarich-1-14-risuet-million-gps-tochek-za-sekundu-vmesto-padeniya</link>
      <comments>https://tproger.ru/news/dawarich-1-14-risuet-million-gps-tochek-za-sekundu-vmesto-padeniya?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/dawarich-1-14-risuet-million-gps-tochek-za-sekundu-vmesto-padeniya</guid>
      <description><![CDATA[<p>Dawarich перевёл точки и треки на карты-тайлы: 957 350 точек грузятся меньше секунды, JSON упал с 590 МБ до 150 КБ. Что ещё в 1.14.1 и сколько стоит облако.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/dawarich-1-14-risuet-million-gps-tochek-za-sekundu-vmesto-padeniya">Dawarich 1.14 рисует миллион GPS-точек за секунду вместо падения браузера</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Sep 2026 09:33:15 GMT</pubDate>
      <content:encoded><![CDATA[<p>Автор Dawarich, открытой self-hosted замены Google Timeline, под ником Freika 2 сентября <a href="https://www.reddit.com/r/selfhosted/comments/1w56g1u/dawarich_1141_now_rendering_millions_of_points_in/">показал</a>, что после перевода отрисовки на карты-тайлы тестовый набор из 957 350 геоточек загружается меньше чем за секунду. Раньше такой объём ронял браузер. Объём JSON, который уходил клиенту, уменьшился примерно с 590 МБ до 150 КБ. Сам релиз 1.14.1 <a href="https://github.com/Freika/dawarich/releases/tag/1.14.1">вышел</a> 31 августа.</p><p>Кому это важно: тем, кто много лет копил историю перемещений в Google Timeline и после переноса её на устройство ищет, где хранить данные самому. Импорт Google Takeout в Dawarich есть, а с новой отрисовкой многолетний архив перестаёт быть проблемой для интерфейса. Проект написан на Ruby on Rails с PostgreSQL и ставится через Docker; на сайте указано больше 9000 звёзд на GitHub.</p><ul><li>Точки, треки, маршруты и слои «тумана войны» теперь отдаются через map tiles; 957 350 точек за меньше чем секунду, JSON с 590 МБ до 150 КБ.</li><li>Для перетаскивания точек на карте новый режим нужно отключить.</li><li>Определение посещений (visit detection) переписано с нуля; метаданные устройств перенесены в таблицу point_sources.</li><li>OwnTracks в HTTP-режиме показывает членов семьи на карте; перелёты из AirTrail считаются отдельно от треков Dawarich.</li><li>Self-hosting бесплатен со всеми функциями; облако: Lite 59,99 евро в год (12 месяцев истории, 200 запросов API в час), Pro 149,99 евро (бессрочная история, 1000 запросов в час), Family 299,99 евро (до 5 человек).</li></ul><h2>Почему тайлы решают проблему миллиона точек</h2><p>Старая схема отдавала клиенту все точки в JSON, и браузер сам рисовал их на карте. На сотнях тысяч точек это сотни мегабайт данных и столько же объектов в памяти вкладки. Новая схема режет данные на тайлы: карта запрашивает только тайлы видимой области и масштаба, а отрисовка по-прежнему идёт в браузере, просто над несравнимо меньшим объёмом данных. Плата за это одна, и автор её называет: точки в режиме тайлов нельзя таскать мышью, для редактирования режим надо выключить.</p><p>Автор пишет, что за месяц вышло девять релизов, и называет результат «немного безумным» (перевод редакции). Для админа, который держит Dawarich на маломощном VPS или Raspberry Pi, важно другое: девять релизов за месяц означают частые миграции базы, и перед каждым обновлением нужен бэкап PostgreSQL.</p><h2>Что ещё изменилось в 1.14.1</h2><ul><li>Метаданные устройств перенесены в таблицу point_sources: миграция базы при обновлении обязательна, перед ней нужен бэкап PostgreSQL.</li><li>Импорт OwnTracks исправлен для массивов PostgreSQL; повреждённая или обрезанная загрузка теперь отклоняется без ошибки сервера.</li><li>Расстояние перелётов из AirTrail считается отдельно от расстояния, записанного трекером.</li><li>Интерфейс переведён на шесть языков: английский, немецкий, испанский, французский, польский и каталанский; следующим заявлен упрощённый китайский. Русского перевода нет.</li></ul><h2>Self-hosting или облако</h2><p>Self-hosted версия бесплатна и включает всё, что есть в платных тарифах, ограничения только у облачного варианта: Lite за 59,99 евро в год хранит 12 месяцев истории и даёт 200 запросов API в час, Pro за 149,99 евро снимает лимит истории и поднимает потолок до 1000 запросов, Family за 299,99 евро рассчитан максимум на пять участников. Условия оплаты облака по регионам проект не описывает; self-hosting от них не зависит.</p><p>Что проверить перед обновлением: сделать дамп базы, обновить образ Docker до 1.14.1, дождаться миграций и убедиться, что карта показывает точки в новом режиме. Кому релиз не нужен: тем, у кого история перемещений измеряется тысячами точек, а не сотнями тысяч; для них разница будет незаметна. О другом свежем self-hosted проекте того же класса мы писали на примере <a href="https://tproger.ru/news/home-assistant-2026-9-pokazal-kartu-matter-i-modbus-integracii-b">Home Assistant 2026.9</a>; о хранении резервных копий такого рода данных есть разбор <a href="https://tproger.ru/articles/kak-hranit-bekapy-v-s3-chtoby-ih-ne-udalil-sboj-ili-virus">про бэкапы в S3</a>.</p><p>Источники: <a href="https://www.reddit.com/r/selfhosted/comments/1w56g1u/dawarich_1141_now_rendering_millions_of_points_in/">Пост разработчика в r/selfhosted</a>, <a href="https://github.com/Freika/dawarich/releases/tag/1.14.1">Релиз 1.14.1 на GitHub</a>, <a href="https://dawarich.app/">Сайт проекта</a></p>]]></content:encoded>
    </item>
    <item>
      <title>CSS-функции sibling-index() и sibling-count() заработали во всех движках</title>
      <link>https://tproger.ru/news/css-funkcii-sibling-index-i-sibling-count-zarabotali-vo-vseh</link>
      <comments>https://tproger.ru/news/css-funkcii-sibling-index-i-sibling-count-zarabotali-vo-vseh?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/css-funkcii-sibling-index-i-sibling-count-zarabotali-vo-vseh</guid>
      <description><![CDATA[<p>С Firefox 154 функции sibling-index() и sibling-count() есть во всех трёх движках. Как задать задержку анимации по номеру элемента без JS и где они вернут 0.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/css-funkcii-sibling-index-i-sibling-count-zarabotali-vo-vseh">CSS-функции sibling-index() и sibling-count() заработали во всех движках</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Sep 2026 08:40:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>Функции sibling-index() и sibling-count() стали доступны во всех трёх основных браузерных движках: последним 18 августа их <a href="https://web-platform-dx.github.io/web-features-explorer/features/sibling-count/">поддержал</a> Firefox 154, а 2 сентября разработчики <a href="https://www.reddit.com/r/css/comments/1w52o07/siblingindex_and_siblingcount_the_css_functions/">разобрали</a> в r/css, что это меняет. Функции возвращают номер элемента среди соседей и общее число детей у родителя, и оба значения можно использовать в calc().</p><p>Практический смысл простой: то, что раньше делали через --i в инлайн-стиле каждого элемента или через JavaScript, теперь считает сам браузер. Ступенчатые задержки анимации в списке, ширина колонок по числу карточек, позиционирование по индексу без нумерации в разметке. По данным Web Platform DX, функции получили статус «newly available» с 18 августа 2026 года; статус «widely available» по правилам Baseline ожидается 18 февраля 2029 года, то есть старые браузеры ещё долго будут требовать запасного варианта.</p><ul><li>sibling-index() возвращает позицию элемента среди соседей, начиная с 1; sibling-count() возвращает число прямых детей родителя, включая текущий.</li><li>Поддержка: Chrome и Edge 138 (июнь 2025), Safari 26.2 (декабрь 2025), Firefox 154 (18 августа 2026).</li><li>Функции считают по дереву DOM, а не по flat tree; при попытке пересечь границу Shadow DOM результат может быть 0.</li><li>Типичные применения: transition-delay и animation-delay по номеру, размер элемента в зависимости от числа соседей, раскладка без JavaScript.</li><li>CSSWG допускает будущую форму с фильтром of, чтобы считать только соседей по селектору.</li></ul><h2>Как это выглядит в коде</h2><p>Классический пример из обсуждения: список, где каждый следующий пункт появляется чуть позже предыдущего. Раньше для этого либо писали style="--i: 3" в каждом li, либо перечисляли :nth-child() вручную. Теперь достаточно одного правила:</p><p>Обе функции возвращают целое число без единиц, поэтому умножение на 80ms или на 100px внутри calc() работает как с обычной переменной. В спецификации CSS Values and Units Level 5 их называют tree-counting functions, функциями подсчёта по дереву.</p><h2>Где функции ведут себя не так, как ожидается</h2><ul><li>Считается дерево DOM, а не flat tree: слоты и элементы внутри Shadow DOM учитываются иначе, чем при рендеринге; на границе теневого дерева функция может вернуть 0, чтобы не раскрывать его содержимое.</li><li>Учитываются все элементы-соседи, а не только подходящие под селектор. Если в списке есть скрытый li, он всё равно попадёт в счёт; форма с фильтром of пока только обсуждается в CSSWG.</li><li>Индексация начинается с 1, как у :nth-child(), а не с 0.</li></ul><h2>Можно ли использовать в проде</h2><p>Для декоративных эффектов вроде задержек анимации можно уже сейчас: в браузере без поддержки calc(sibling-index() * 80ms) будет невалидным значением, и правило просто не применится, элементы появятся одновременно. Для раскладки, от которой зависит читаемость, стоит завернуть правило в @supports:</p><p>Кому это ничего не даст: проектам, которые обязаны поддерживать браузеры старше Chrome 138 и Safari 26.2, а также тем, кто уже генерирует индексы на сервере. По данным Web Platform DX, Chrome и Chrome Android получили функции в версии 138 от 24 июня 2025 года, Edge 138 от 26 июня 2025 года, Safari и iOS Safari в 26.2 от 12 декабря 2025 года, Firefox и Firefox Android в 154 от 18 августа 2026 года.</p><p>Из соседних CSS-новостей на сайте: Firefox 155 <a href="https://tproger.ru/news/firefox-dlya-ios-poluchil-vstroennyj-blokirovshhik-reklamy-a-firefo">добавил</a> функцию progress(), а в Chrome 154 beta появились режимы links и tabs у scroll-marker-group. Черновик спецификации с формальным описанием функций лежит на <a href="https://drafts.csswg.org/css-values-5/">сайте CSSWG</a>.</p><p>Источники: <a href="https://www.reddit.com/r/css/comments/1w52o07/siblingindex_and_siblingcount_the_css_functions/">Обсуждение в r/css</a>, <a href="https://web-platform-dx.github.io/web-features-explorer/features/sibling-count/">Web Platform DX: sibling-count и sibling-index</a>, <a href="https://drafts.csswg.org/css-values-5/">CSS Values and Units Module Level 5</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Chrome 154 beta принёс постквантовое шифрование в Web Crypto</title>
      <link>https://tproger.ru/news/chrome-154-beta-prinyos-postkvantovoe-wifrovanie-v-web-crypto</link>
      <comments>https://tproger.ru/news/chrome-154-beta-prinyos-postkvantovoe-wifrovanie-v-web-crypto?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/chrome-154-beta-prinyos-postkvantovoe-wifrovanie-v-web-crypto</guid>
      <description><![CDATA[<p>Chrome 154 beta: ML-KEM и ML-DSA в Web Crypto, options bag и targetAddressSpace у WebSocket, режимы links и tabs у scroll-marker-group, CORS в Background Fetch.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/chrome-154-beta-prinyos-postkvantovoe-wifrovanie-v-web-crypto">Chrome 154 beta принёс постквантовое шифрование в Web Crypto</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Google Chrome]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Sep 2026 03:20:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Google 2 сентября <a href="https://developer.chrome.com/blog/chrome-154-beta">перевела</a> Chrome 154 в бету для Android, ChromeOS, Linux, macOS и Windows; desktop-сборка имеет номер 154.0.8037.0, для Android и ChromeOS сборки выходят отдельно. Самое заметное для веб-разработчиков: в Web Crypto API добавили постквантовые алгоритмы ML-KEM и ML-DSA, WebSocket научился принимать объект настроек и ходить в локальную сеть с явным разрешением, а у CSS-свойства scroll-marker-group появились режимы links и tabs.</p><p>Бета обычно доживает до стабильного релиза без крупных изменений, поэтому всё перечисленное стоит проверять уже сейчас: часть новинок меняет поведение существующего кода. Background Fetch начинает применять CORS, а AbortController теперь передаёт причину отмены в Response и ReadableStream. Автор поста в блоге Chrome for Developers Рэйчел Эндрю; отдельных региональных ограничений на бету в источнике нет.</p><ul><li>Web Crypto получил ML-KEM 768 и 1024, ML-DSA 44, 65 и 87, ChaCha20-Poly1305 и гибридную схему X-Wing.</li><li>WebSocket принимает options bag: new WebSocket(url, { protocols: "soap" }); новое поле targetAddressSpace позволяет подключаться к локальным адресам при secure context и разрешении Local Network Access.</li><li>scroll-marker-group получил режимы links и tabs; в режиме tabs активный маркер остаётся единственным tab-stop, а неактивный контент скрывается из дерева доступности.</li><li>CSSStyleValue и связанные конструкторы доступны в воркерах; text-decoration-inset принимает auto, длину, процент и одно-/двухзначную запись; FontFace.width стал алиасом stretch.</li><li>Background Fetch теперь соблюдает CORS; WebGPU получил модификаторы frag_depth less и greater, которые позволяют не терять ранний Z-тест.</li></ul><h2>Что даёт постквантовая криптография в браузерном API</h2><p>До сих пор постквантовые алгоритмы в Chrome работали только на уровне TLS, незаметно для страницы. В 154 они выходят в JavaScript: через crypto.subtle можно генерировать ключи и выполнять инкапсуляцию ML-KEM (стандарт NIST для обмена ключами) и подписи ML-DSA. Добавлены также ChaCha20-Poly1305 и X-Wing, гибрид классического X25519 и ML-KEM. На практике это нужно тем, кто делает сквозное шифрование в веб-приложениях: мессенджерам, хранилищам паролей, локальным подписям документов. Проверить у себя просто: вызвать crypto.subtle.generateKey с новым именем алгоритма в бете и убедиться, что он не бросает NotSupportedError.</p><h2>Зачем WebSocket объект настроек и локальная сеть</h2><p>Конструктор WebSocket много лет принимал только URL и строку или массив протоколов. Теперь второй аргумент может быть объектом: new WebSocket(url, { protocols: "soap" }). Это задел под будущие опции без ломки сигнатуры. Второе поле, targetAddressSpace, решает конкретную боль: страница с публичного HTTPS-сайта не могла открыть сокет к устройству в локальной сети. В 154 это возможно, но при трёх условиях: secure context, разрешение пользователя по механизму Local Network Access и имя хоста, которое резолвится в локальный IP. Сценарий типичный для панелей управления IoT и локальных серверов разработки.</p><h2>Что меняется в CSS</h2><p>Свойство scroll-marker-group, которое вместе с псевдоэлементами ::scroll-marker позволяет делать карусели и табы без JavaScript, получило два режима. links ведёт себя как набор ссылок, tabs как настоящий tablist: активный маркер единственный останавливается по Tab, а контент неактивных вкладок исключается из accessibility tree. Это закрывает главную претензию к CSS-каруселям: раньше скринридер видел все панели сразу.</p><p>Из остального: text-decoration-inset позволяет отступать подчёркивание от краёв текста и принимает auto, длину, процент и запись из одного или двух значений; FontFace.width и дескриптор font-width в @font-face стали алиасами stretch и font-stretch; типизированная объектная модель CSS (CSSStyleValue и конструкторы) теперь доступна в воркерах, что упрощает расчёты стилей вне главного потока.</p><h2>Что может сломаться после обновления</h2><ul><li>Background Fetch теперь применяет CORS: фоновые загрузки с чужих доменов без правильных заголовков начнут падать.</li><li>AbortController прокидывает reason в Response и ReadableStream: код, который сравнивал ошибку отмены с конкретным AbortError, может получить другой объект.</li><li>По заметкам к релизу, браузер в ряде сценариев использует события click вместо пары pointerdown/pointerup; обработчики, завязанные на порядок этих событий, стоит перепроверить.</li><li>В WebGPU появились модификаторы frag_depth less и greater: шейдеры, которые пишут глубину, могут вернуть себе ранний Z-тест, но это требует правки WGSL.</li></ul><h2>Как попробовать</h2><p>Бета ставится параллельно со стабильным Chrome со <a href="https://www.google.com/chrome/beta/">страницы загрузки Chrome Beta</a>; анонс сборки опубликован в <a href="https://chromereleases.googleblog.com/2026/09/chrome-beta-for-desktop-update.html">Chrome Releases</a>; на Android доступна через бета-программу в магазине. Стабильный релиз 154 по обычному графику Chrome выходит примерно через четыре недели после беты, точную дату Google в посте не называет. До этого времени полезно прогнать сайт с включёнными фоновыми загрузками и WebSocket-подключениями к локальным устройствам.</p><p>Что происходит в других движках, можно сравнить с недавними релизами: WebKit <a href="https://tproger.ru/news/safari-27-poluchit-perepisannyj-zagruzchik-modulej-i-rabochij-top-l">переписал загрузчик модулей</a> для Safari 27, а Firefox 155 <a href="https://tproger.ru/news/firefox-dlya-ios-poluchil-vstroennyj-blokirovshhik-reklamy-a-firefo">добавил</a> CSS-функцию progress(). Полный список изменений Chrome 154 с примерами кода лежит в <a href="https://developer.chrome.com/blog/chrome-154-beta">блоге Chrome for Developers</a>.</p><p>Источники: <a href="https://developer.chrome.com/blog/chrome-154-beta">Chrome for Developers: Chrome 154 beta</a>, <a href="https://chromereleases.googleblog.com/2026/09/chrome-beta-for-desktop-update.html">Chrome Releases: Chrome Beta for Desktop Update</a></p><p>Изображение на обложке: Google, логотип Chrome</p>]]></content:encoded>
    </item>
    <item>
      <title>Safari 27 получит переписанный загрузчик модулей и рабочий top-level await</title>
      <link>https://tproger.ru/news/safari-27-poluchit-perepisannyj-zagruzchik-modulej-i-rabochij-top-l</link>
      <comments>https://tproger.ru/news/safari-27-poluchit-perepisannyj-zagruzchik-modulej-i-rabochij-top-l?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/safari-27-poluchit-perepisannyj-zagruzchik-modulej-i-rabochij-top-l</guid>
      <description><![CDATA[<p>WebKit переписал загрузчик ES-модулей с нуля на C++ и исправил многолетние ошибки top-level await в Safari. Что ломалось и когда убирать обходные пути.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/safari-27-poluchit-perepisannyj-zagruzchik-modulej-i-rabochij-top-l">Safari 27 получит переписанный загрузчик модулей и рабочий top-level await</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Safari]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 02 Sep 2026 16:00:09 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда WebKit 2 сентября <a href="https://webkit.org/blog/18227/fixing-top-level-await-in-safari/">рассказала</a>, что переписала загрузчик JavaScript-модулей Safari с нуля и тем самым закрыла многолетние ошибки top-level await, из-за которых модули с await на верхнем уровне падали с сообщением «Cannot access ... before initialization». Исправление уже есть в Safari Technology Preview 251 и бете Safari 27; в стабильный Safari оно попадёт с выходом Safari 27.</p><p>Для фронтендера это означает, что один из последних поводов не использовать top-level await в продакшене исчезает: в Chrome и Firefox функция работает давно, а Safari оставался браузером, ради которого библиотеки и сборщики держали обходные пути. По словам автора публикации, инженера WebKit Кая Тамкуна, вместе с загрузчиком в порядок приведены ES-модули в целом, так что после релиза Safari 27 на них «можно опираться, не задумываясь».</p><ul><li>Старый загрузчик модулей Safari был написан по черновику WHATWG Loader, последний раз обновлённому в январе 2016 года, ещё до появления async/await в языке.</li><li>Top-level await, добавленный в ECMAScript 2022, реализовали поверх этой устаревшей основы, отсюда ошибки порядка выполнения и обращения к неинициализированным экспортам.</li><li>В январе 2026 года команда удалила старый загрузчик целиком и переписала его на C++ по алгоритмам спецификации ECMAScript, отказавшись от самохостируемого JavaScript.</li><li>Проверка: тест-кейсы от команды Bun, чей рантайм на JavaScriptCore унаследовал те же баги, фаззер графов модулей со сравнением вывода с другими движками, все модульные тесты test262 и исправленные тесты WPT без регрессий.</li><li>Попробовать можно сегодня в Safari Technology Preview 251 или Safari 27 beta; сроки стабильного Safari 27 в публикации не названы.</li></ul><h2>Что именно ломалось</h2><p>Top-level await позволяет писать await прямо в теле ES-модуля: модуль приостанавливается до разрешения промиса, и вместе с ним ждут все модули, которые его импортируют, а независимые ветки графа зависимостей продолжают выполняться. В Safari нарушался именно порядок: загрузчик неверно выбирал, когда считать модуль выполненным. WebKit показывает это на минимальном примере, где один и тот же модуль с задержкой на верхнем уровне динамически импортируется три раза подряд.</p><p>Ожидаемый порядок завершения импортов 1, 2, 3. Старый загрузчик выдавал 2, 3, 1, причём второй и третий импорт завершались с ошибкой Cannot access 'someArray' before initialization, и только первый печатал список экспортов. Причина одна: когда первый импорт доходил до await и уступал управление, промис второго импорта должен был ждать окончания выполнения модуля, но из-за ошибки разрешался сразу. Код получал ещё не инициализированные экспорты и падал. С новым загрузчиком вывод становится ожидаемым: 1, 2, 3, и каждый раз с корректным списком ключей.</p><h2>Почему баг не удавалось починить годами</h2><p>Спецификация ECMAScript оставляет часть механики модулей на усмотрение хоста, в первую очередь загрузку по сети в браузере или с диска в Node.js и Bun. Загрузчик Safari писали в эпоху предложения WHATWG Loader, которое описывало эту хостовую часть и последний раз обновлялось в январе 2016 года. Тогда модули выполнялись строго синхронно, и черновика хватало. Затем предложение фактически умерло, вытесненное разделом о модулях в самом стандарте ECMAScript, а в 2022 году в язык вошёл top-level await. В WebKit его реализовали поверх алгоритмов заброшенного черновика, а не по асинхронным алгоритмам стандарта. Отсюда тонкие ошибки, которые, по словам Тамкуна, команда безуспешно пыталась закрыть несколько раз, пока не решила заменить основание.</p><p>Второе решение касается языка реализации. Старый загрузчик был самохостируемым встроенным кодом на JavaScript. У такого подхода есть плюсы: его можно инлайнить в пользовательский код и не платить за переход между JavaScript и C++. Но он медленнее стартует, потому что компилируется во время выполнения, а оптимизирующие JIT-компиляторы JavaScriptCore плохо используют его широкие паттерны применения; загрузчик к тому же не горячий путь, так что выигрыша от компиляции на лету почти нет. Новый загрузчик написан целиком на C++.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-09-02/02a4b3fb-cf74-49e7-9132-dcbbed91c537.webp" alt="Схема вызовов операций загрузчика модулей WebKit: загрузка, линковка, выполнение и вспомогательные функции" /><figcaption>Граф вызовов операций загрузчика модулей, по которому команда планировала порядок реализации. Источник: WebKit</figcaption></figure><h2>Как переписывали и проверяли</h2><p>Работа началась в январе 2026 года с удаления файла со старым загрузчиком. Дальше команда переводила псевдокод операций из спецификации ECMAScript в C++ по одной, начав с листовых функций вроде ExecuteModule и ModuleRequestsEqual, у которых нет зависимостей, и двигаясь по графу вызовов. Через несколько недель черновая реализация справлялась с типичными случаями, и появился draft pull request.</p><p>Тестов было три слоя. Во-первых, инженеры Bun, чей рантайм построен на JavaScriptCore и унаследовал те же проблемы, передали собранные ими случаи неправильного поведения; их адаптировали под консольную оболочку jsc. Во-вторых, команда написала фаззер, который генерирует большие графы модулей, часть с top-level await, часть без, и сравнивает текстовый вывод JavaScriptCore с выводом других движков байт в байт; по словам WebKit, во всех проверенных примерах новый загрузчик отработал верно. В-третьих, все модульные тесты набора test262 стали проходить, а часть ранее падавших тестов WPT исправилась без регрессий. Перед слиянием разработчики несколько недель пользовались сборкой Safari с новым загрузчиком как основным браузером.</p><h2>Что делать фронтендеру</h2><ul><li>Проверить свои модули с top-level await в Safari Technology Preview 251 или Safari 27 beta; о найденных проблемах WebKit просит сообщать на bugs.webkit.org.</li><li>Обходные пути для Safari пока не убирать: стабильный Safari 27 ещё не вышел, а старые версии Safari останутся у пользователей надолго.</li><li>Если проект работает на Bun, следить за обновлениями рантайма: он использует JavaScriptCore и, по словам WebKit, унаследовал те же ошибки загрузчика; о сроках их исправления в Bun публикация не говорит.</li></ul><p>Дата выхода стабильного Safari 27 в публикации не названа. Открытым остаётся и вопрос старых версий: о переносе исправления в уже вышедшие Safari WebKit не сообщает, так что доля пользователей на Safari 26 и старше будет определять, когда обходные пути можно убрать совсем.</p><p>Источник: <a href="https://webkit.org/blog/18227/fixing-top-level-await-in-safari/">WebKit Blog: Fixing Top-Level Await in Safari</a></p><p>Изображение на обложке: Изображение: логотип WebKit, Apple</p>]]></content:encoded>
    </item>
    <item>
      <title>Cloudflare D1 на бесплатном плане отключается при превышении лимитов</title>
      <link>https://tproger.ru/news/cloudflare-nachala-otklyuchat-d1-na-besplatnom-plane-pri-prevyweni</link>
      <comments>https://tproger.ru/news/cloudflare-nachala-otklyuchat-d1-na-besplatnom-plane-pri-prevyweni?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/cloudflare-nachala-otklyuchat-d1-na-besplatnom-plane-pri-prevyweni</guid>
      <description><![CDATA[<p>С 1 сентября Cloudflare возвращает ошибки на запросы к D1 на плане Workers Free после превышения дневных лимитов: 5 млн прочитанных и 100 тысяч записанных строк. Что изменилось, как считаются строки, как понять, что вы близко к лимиту, сколько стоит платный план и что делать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/cloudflare-nachala-otklyuchat-d1-na-besplatnom-plane-pri-prevyweni">Cloudflare D1 на бесплатном плане отключается при превышении лимитов</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Облачные технологии]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 01 Sep 2026 17:27:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Cloudflare с 1 сентября начала жёстко применять дневные лимиты <b>D1</b>, встроенной SQLite-базы для Workers, на бесплатном плане Workers Free. Об этом компания сообщила в <a href="https://developers.cloudflare.com/changelog/post/2026-09-01-d1-free-tier-limit-enforcement/">записи changelog</a>. Раньше превышение суточной квоты на строки проходило почти незаметно, теперь запросы через Workers Binding API и REST API возвращают ошибки и не работают до полуночи по UTC. Данные при этом не удаляются.</p><p>Если у вас на Workers Free крутится пет-проект, бот или небольшой сервис с базой в D1, это касается напрямую: в один день трафик чуть выше обычного, и после обеда по Москве запросы к базе начинают завершаться ошибкой до трёх часов ночи, а приложение без обработки этой ошибки показывает её пользователям. Cloudflare обещает письмо при достижении лимита, но письмо не починит прод.</p><ul><li>Лимиты Workers Free для D1: 5 млн прочитанных строк и 100 тысяч записанных строк в сутки, 5 ГБ хранилища на аккаунт.</li><li>С 1 сентября при превышении запросы к D1 завершаются ошибкой до сброса счётчика в 00:00 UTC (03:00 мск); сохранённые данные не затрагиваются.</li><li>На Workers Paid за $5 в месяц включено 25 млрд чтений и 50 млн записей в месяц, дальше $0,001 за миллион прочитанных строк и $1 за миллион записанных; 5 ГБ хранилища включено, дальше $0,75 за ГБ в месяц.</li><li>Строки считаются по факту прочитанного движком, а не по числу строк в ответе: SELECT без индекса по таблице в 100 тысяч строк — это 100 тысяч чтений.</li><li>Cloudflare советует посмотреть статистику запросов за прошлые дни и добавить индексы: полное сканирование таблицы съедает лимит чтений быстрее всего.</li></ul><h2>Что изменилось на самом деле</h2><p>Сами лимиты не новые, они давно указаны на <a href="https://developers.cloudflare.com/d1/platform/pricing/">странице тарифов</a>. Изменился режим их применения: до 1 сентября Cloudflare не блокировала запросы при превышении, теперь блокирует. Ограничение действует и на вызовы из кода Worker через биндинг, и на REST API, которым пользуются внешние интеграции и админки. В тексте ошибки предлагается два выхода: перейти на платный план или подождать до завтра.</p><blockquote>Upgrade to a paid plan or wait until tomorrow.</blockquote><p>Компания подчёркивает, что хранилище остаётся нетронутым: речь только о временной недоступности запросов, а не о потере или заморозке данных. Счётчик сбрасывается в полночь по UTC, в три часа ночи по Москве. Уведомление по электронной почте приходит при достижении дневного лимита, и Cloudflare отдельно рекомендует посмотреть активность запросов за прошлые дни, чтобы понять, насколько проект близок к границе.</p><h2>Почему один запрос может стоить 100 тысяч чтений</h2><p>Главная ловушка D1 — учёт по прочитанным строкам, а не по запросам. Запрос SELECT * FROM events WHERE user_id = ? без индекса по user_id заставляет движок пройти всю таблицу, и каждая пройденная строка засчитывается в лимит, даже если в ответе одна запись. Поэтому небольшой сервис с парой тысяч посетителей в день может упереться в 5 млн чтений на одном неудачном запросе в цикле. Cloudflare в changelog прямо называет виновника: запросы с полным сканированием таблиц, и советует индексы как первое средство.</p><p>Сколько строк реально прочитал запрос, D1 возвращает в объекте meta ответа: поля rows_read и rows_written. Именно по ним, а не по числу вызовов, стоит оценивать, насколько вы близки к лимиту. Суммарную картину за день показывают GraphQL Analytics API и дашборд Cloudflare; страница тарифов перечисляет все три способа отслеживать расход.</p><p>С записями та же логика: учитываются записанные строки, а не вызовы. Объединение вставок в один батч сокращает число запросов и задержку, но не уменьшает rows_written, так что от лимита в 100 тысяч записей в сутки оно не спасает. Единственный способ уложиться — писать меньше строк: агрегировать события, не хранить в D1 логи на каждый запрос, выносить телеметрию в Analytics Engine или KV.</p><h2>Сколько стоит платный план</h2><p>Workers Paid стоит $5 в месяц и снимает дневные лимиты. По странице тарифов в него включены 25 млрд прочитанных строк и 50 млн записанных строк в месяц, сверх этого чтение стоит $0,001 за миллион строк, запись — $1 за миллион строк. Хранилище: 5 ГБ включено, дальше $0,75 за гигабайт в месяц. Бесплатный план даёт те же 5 ГБ, но при их превышении не тарифицирует, а блокирует новые записи и изменение схемы; но 5 млн чтений и 100 тысяч записей в сутки, то есть примерно 150 млн чтений и 3 млн записей в месяц.</p><h2>Что сделать до вечера</h2><ul><li>Откройте статистику D1 в дашборде за последние две недели: если пиковые дни выше 3–4 млн чтений, по нашей оценке вы в зоне риска; порог редакционный, Cloudflare его не задаёт.</li><li>Пройдитесь EXPLAIN QUERY PLAN по самым частым запросам и добавьте индексы там, где видите SCAN.</li><li>Кэшируйте горячие ответы в KV или Cache API: одно чтение из кэша вместо тысячи строк из базы.</li><li>Записи ограничены сильнее чтений: считаются записанные строки, а не вызовы, батчи не помогут; пишите меньше строк, агрегируйте события и не кладите логи в D1 на каждый запрос.</li><li>Обрабатывайте ошибку D1 в коде: показывайте пользователю понятное сообщение и отдавайте кэшированные данные, а не пятисотую страницу.</li></ul><h2>Контекст</h2><p>D1 вышла из беты в 2024 году как «SQLite на краю сети» для Workers: база живёт рядом с кодом и тарифицируется по строкам, а глобальная репликация чтения доступна как отдельная бета-функция, а не по процессорному времени. Учёт по строкам — осознанный выбор Cloudflare, и до сих пор он был безболезненным для бесплатных проектов. Для D1 «бесплатно» теперь читается буквально: в пределах квоты сервис работает, за пределами останавливается, а не копит счёт. Распространится ли такой режим на другие бесплатные лимиты Workers, changelog не говорит.</p><p>Источники: <a href="https://developers.cloudflare.com/changelog/post/2026-09-01-d1-free-tier-limit-enforcement/">D1 free tier limit enforcement (Cloudflare Changelog)</a>, <a href="https://developers.cloudflare.com/d1/platform/pricing/">D1 pricing</a></p><p>Изображение на обложке: Cloudflare</p>]]></content:encoded>
    </item>
    <item>
      <title>Сканеры атакуют открытые Langflow и Rails: у первого нет патча, у второго есть</title>
      <link>https://tproger.ru/news/dve-kriticheskie-uyazvimosti-ekspluatiruyut-pryamo-sejchas-langflow</link>
      <comments>https://tproger.ru/news/dve-kriticheskie-uyazvimosti-ekspluatiruyut-pryamo-sejchas-langflow?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/dve-kriticheskie-uyazvimosti-ekspluatiruyut-pryamo-sejchas-langflow</guid>
      <description><![CDATA[<p>VulnCheck зафиксировала сотни попыток эксплуатации CVE-2026-0768 в Langflow (CVSS 9.8, выполнение Python от root без аутентификации) и CVE-2026-66066 в Rails Active Storage (CVSS 9.5, чтение файлов и секретов). Условия, версии с исправлением, что проверить.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/dve-kriticheskie-uyazvimosti-ekspluatiruyut-pryamo-sejchas-langflow">Сканеры атакуют открытые Langflow и Rails: у первого нет патча, у второго есть</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby on Rails]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 01 Sep 2026 17:26:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>Компания VulnCheck, по <a href="https://thehackernews.com/2026/09/attackers-exploit-critical-langflow-and.html">сообщению The Hacker News</a> от 1 сентября, зафиксировала сотни попыток эксплуатации двух критических уязвимостей на своих ловушках: <b>CVE-2026-0768</b> в Langflow, визуальном конструкторе ИИ-приложений на Python, и <b>CVE-2026-66066</b> в Ruby on Rails. Первая позволяет без пароля выполнить произвольный Python-код от имени root, вторая — прочитать любые файлы сервера, включая ключи и пароли к базе, отправив специально собранную картинку.</p><p>Обе дыры не новые: <a href="https://github.com/advisories/GHSA-x5pr-rvjj-j6qm">advisory по Langflow</a> опубликован в GitHub Advisory Database ещё 23 января, но исправленная версия в нём не указана, а ZDI в бюллетене <a href="https://www.zerodayinitiative.com/advisories/ZDI-26-034/">ZDI-26-034</a> называет единственной мерой ограничение доступа к сервису. Для Rails исправления есть. Если у вас в проде или на тестовом сервере стоит Langflow либо Rails-приложение принимает файлы от пользователей, проверять нужно сегодня.</p><ul><li>CVE-2026-0768, Langflow: CVSS 9.8, CWE-94, инъекция кода через параметр code в эндпоинте /api/v1/validate/code, аутентификация не нужна, код выполняется от root; исправленная версия в advisory не указана.</li><li>CVE-2026-66066, Rails Active Storage: CVSS 9.5, чтение произвольных файлов при обработке изображений через libvips; уязвимы activestorage до 7.2.3.2, 8.0.x до 8.0.5.1 и 8.1.x до 8.1.3.1.</li><li>VulnCheck насчитала 360 срабатываний на ловушках в нескольких странах; в запросах ищут ключи OpenAI и AWS, файл secret_key Langflow, папку .ssh и историю shell.</li><li>Rails закрывается обновлением activestorage вместе с libvips не ниже 8.13; для Langflow единственная подтверждённая мера — ограничить доступ к сервису доверенными пользователями и сетями.</li><li>При признаках эксплуатации считайте доступные секреты скомпрометированными и меняйте их.</li></ul><h2>Langflow: код в параметре code и никакого патча</h2><p>Langflow — популярный инструмент, где ИИ-пайплайны собираются мышкой из блоков, а под капотом это Python-приложение. У него есть служебный эндпоинт /api/v1/validate/code, который проверяет пользовательский код компонента. Проверка входа там оказалась недостаточной: код из параметра выполняется, а эндпоинт не требует аутентификации. Langflow часто разворачивают в Docker от root, поэтому атакующий получает полный контроль над контейнером и всем, что в нём лежит: ключами моделей, токенами, доступами к базам.</p><blockquote>Authentication is not required to exploit this vulnerability.</blockquote><p>Это уже второй раз, когда тот же эндпоинт подводит: в 2025 году в нём же нашли CVE-2025-3248. По данным VulnCheck, в запросах атакующие целятся в переменные окружения LANGFLOW_SUPERUSER, OPENAI_API*, AWS_ACCESS*, AWS_SECRET*, файл /root/.cache/langflow/secret_key, каталог .ssh и .bash_history. Цель — не сам Langflow, а всё, к чему у него есть ключи. По данным VulnCheck, основной источник трафика на ловушки Langflow находился в России, а попадания фиксировались на canary-системе в Великобритании; атаки на Rails приходили на ловушки в Сингапуре, Израиле и Великобритании.</p><h2>Rails: картинка, которая читает файлы</h2><p>В Rails уязвим Active Storage, стандартный механизм загрузки файлов. Когда приложение обрабатывает изображение, оно передаёт файл в библиотеку libvips. Специально собранный файл заставляет libvips прочитать произвольный путь на сервере и вернуть содержимое в результирующем изображении. Так утекают secret_key_base, master key Rails, пароли БД и облачные учётные данные, а с ними в ряде конфигураций возможно и выполнение кода. Исследователи назвали уязвимость KindaRails2Shell.</p><p>Условия эксплуатации по <a href="https://github.com/advisories/GHSA-xr9x-r78c-5hrm">advisory</a>: libvips как бэкенд обработки и возможность для недоверенного пользователя загрузить файл. Если у вас ImageMagick или файлы грузят только администраторы, риск ниже, но обновиться всё равно стоит. Исправленные версии gem activestorage: 7.2.3.2, 8.0.5.1 и 8.1.3.1; advisory требует также libvips не ниже 8.13 и рекомендует заменить секреты.</p><h2>Что сделать сегодня</h2><ul><li>Langflow: ограничьте доступ ко всему сервису доверенными пользователями и сетями (VPN, reverse proxy с аутентификацией); это единственная мера, которую называет ZDI, потому что исправленной версии в advisory нет. Следите за релизами проекта.</li><li>Проверьте логи на запросы к /api/v1/validate/code с чужих адресов; нашли — считайте все ключи в окружении скомпрометированными и ротируйте их.</li><li>Rails: bundle update activestorage rails до 7.2.3.2, 8.0.5.1 или 8.1.3.1 и выше, обновите libvips до 8.13 или новее; проверьте Gemfile.lock.</li><li>Пока не обновились: на libvips 8.13 и новее включите блокировку недоверенных операций (переменная VIPS_BLOCK_UNTRUSTED или Vips.block_untrusted(true)), для более старых версий обхода advisory не даёт, остаётся отключить обработку файлов от пользователей.</li><li>После инцидента меняйте secret_key_base и master key: с их утечкой атакующий подделывает сессии и расшифровывает credentials.</li></ul><h2>Контекст</h2><p>Обе уязвимости известны с зимы, но волна эксплуатации началась, когда появился рабочий эксплойт и его добавили в автоматические сканеры. VulnCheck отдельно отмечает, что запросы приходили на ловушки в разных странах, то есть кампания не целевая, а ковровая: сканеры ищут любой доступный снаружи экземпляр. Langflow особенно распространён во внутренних ИИ-экспериментах, которые поднимают «на минутку» с публичным IP и забывают, и именно такие установки первыми находят сканеры.</p><p>Источники: <a href="https://thehackernews.com/2026/09/attackers-exploit-critical-langflow-and.html">Attackers exploit critical Langflow and Rails flaws (The Hacker News)</a>, <a href="https://github.com/advisories/GHSA-x5pr-rvjj-j6qm">GHSA-x5pr-rvjj-j6qm: Langflow code injection</a>, <a href="https://github.com/advisories/GHSA-xr9x-r78c-5hrm">GHSA-xr9x-r78c-5hrm: Active Storage arbitrary file read</a>, <a href="https://www.zerodayinitiative.com/advisories/ZDI-26-034/">ZDI-26-034</a></p><p>Изображение на обложке: Langflow, Ruby on Rails</p>]]></content:encoded>
    </item>
    <item>
      <title>Firefox для iOS получил блокировщик рекламы, а Firefox 155 функцию progress()</title>
      <link>https://tproger.ru/news/firefox-dlya-ios-poluchil-vstroennyj-blokirovshhik-reklamy-a-firefo</link>
      <comments>https://tproger.ru/news/firefox-dlya-ios-poluchil-vstroennyj-blokirovshhik-reklamy-a-firefo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/firefox-dlya-ios-poluchil-vstroennyj-blokirovshhik-reklamy-a-firefo</guid>
      <description><![CDATA[<p>Mozilla добавила в Firefox для iOS встроенный блокировщик рекламы на WebKit Content Blocker и EasyList. Одновременно вышел Firefox 155 с CSS-функциями progress() и alpha(), Promise.allKeyed() и исправлениями уязвимостей высокого уровня. Что включить и что проверить.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/firefox-dlya-ios-poluchil-vstroennyj-blokirovshhik-reklamy-a-firefo">Firefox для iOS получил блокировщик рекламы, а Firefox 155 функцию progress()</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 01 Sep 2026 17:25:52 GMT</pubDate>
      <content:encoded><![CDATA[<p>Mozilla 1 сентября <a href="https://blog.mozilla.org/en/firefox/ad-blocker-on-ios/">добавила</a> в <b>Firefox для iOS</b> встроенный блокировщик рекламы. На iPhone это важнее, чем звучит: расширения в iOS-версии Firefox, по формулировке Mozilla, «недоступны таким же образом», как на десктопе и Android, а браузер работает на движке WebKit от Apple, поэтому uBlock Origin туда не поставить. Теперь блокировка есть в настройках, но выключена по умолчанию.</p><p>В тот же день вышел <b>Firefox 155</b> для десктопа, и для верстальщиков в нём есть чем заняться: CSS-функции progress() и alpha(), свойство font-width, attr() в любом свойстве, а в JavaScript Promise.allKeyed(). Обновиться стоит и без новинок: бюллетень безопасности MFSA 2026-82 закрывает несколько уязвимостей высокого уровня.</p><ul><li>Блокировщик в Firefox для iOS включается в Settings, затем Browsing, затем Ad Blocker; по умолчанию выключен, расширение ставить не нужно.</li><li>Работает на технологии Apple WebKit Content Blocker и списке EasyList; рекламу в поисковой выдаче и рекламу самих сайтов может пропускать.</li><li>Firefox 155: CSS progress(), alpha(), font-width, attr() везде; Promise.allKeyed() и allSettledKeyed(); согласование QUIC v2 для HTTP/3; NDJSON в JSON Viewer.</li><li>MFSA 2026-82 закрывает уязвимости высокого уровня, среди них CVE-2026-84119, 84143 и 84144, и повышение привилегий в Firefox для Android.</li><li>Минимальную версию iOS для блокировщика Mozilla не назвала; доступность функции по регионам анонс не описывает.</li></ul><h2>Почему блокировщик пришлось встраивать</h2><p>Apple разрешает сторонним браузерам блокировать контент только через свой механизм <b>Content Blocker</b>: приложение отдаёт WebKit готовый список правил, а сам движок решает, какие запросы не выполнять. Расширение не может «посмотреть» на страницу и вмешаться в её код, как это делает uBlock Origin на десктопе. Mozilla взяла список EasyList, самый распространённый набор правил для рекламы, и упаковала его в такой блок правил внутри приложения.</p><blockquote>Ad Blocker uses Apple's WebKit Content Blocker technology and the EasyList filter list.</blockquote><p>Из этой архитектуры следуют ограничения, которые Mozilla перечисляет сама. Реклама, которую сайт отдаёт с собственного домена, может остаться, потому что её не отличить от контента по URL. Реклама в результатах поиска не блокируется. Рекламные ярлыки на стартовой странице самого Firefox к блокировщику не относятся. Включается всё в три касания: Settings, Browsing, Ad Blocker; там же выключается, если сайт перестал работать.</p><h2>Что Firefox 155 даёт верстальщику</h2><p>По <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/155">заметкам для разработчиков на MDN</a>, самое полезное в CSS — функция progress(): она возвращает долю от 0 до 1, показывающую, где значение находится между двумя границами. Раньше такой расчёт делали руками через calc(), теперь адаптивные размеры шрифта и отступов записываются короче. Функция alpha() меняет прозрачность цвета без переписывания его в rgb(), а attr() отныне работает в любом свойстве, а не только в content.</p><p>В JavaScript добавились Promise.allKeyed() и Promise.allSettledKeyed(): они принимают объект с промисами и возвращают объект с теми же ключами, так что не нужно сопоставлять результаты по индексам массива. Свойство font-width заменило font-stretch, старое имя оставлено как псевдоним. Если импорт модуля упал из-за временной ошибки сервера, повторный импорт теперь может выполниться успешно; это касается JS, JSON, CSS и текстовых модулей. В сетевом стеке появилось согласование QUIC version 2 для HTTP/3, а JSON Viewer в DevTools научился читать NDJSON построчно.</p><p>Для автотестов: в WebDriver BiDi исправлены перезагрузка фреймов, подписки и конфликт с DevTools, в WebRTC добавлена поддержка двухбайтовых RTP-заголовков с идентификаторами от 15 и новые поля статистики. Перед использованием progress() и alpha() в проде стоит сверить поддержку в Chrome и Safari на caniuse: MDN описывает только Firefox.</p><h2>Почему обновиться сегодня</h2><p><a href="https://www.mozilla.org/en-US/security/advisories/mfsa2026-82/">Бюллетень MFSA 2026-82</a> сопровождает релиз набором исправлений. CVE-2026-84119 (выход из песочницы через use-after-free в навигации DOM), CVE-2026-84143 и CVE-2026-84144 помечены как уязвимости высокого уровня, CVE-2026-84142 объединяет внутренне найденные ошибки памяти умеренного уровня. Отдельно для Firefox на Android бюллетень называет повышение привилегий (CVE-2026-84117, высокий уровень) и раскрытие информации через WebExtensions (CVE-2026-84127, умеренный уровень). Обновление на 155 закрывает всё это разом; на десктопе и Android оно важнее новых функций.</p><h2>Что дальше</h2><p>Mozilla объясняет встроенный блокировщик ограничениями расширений на iOS и формулирует их как «недоступны таким же образом», а не «невозможны навсегда»: в ЕС и Японии Apple уже допускает альтернативные движки, и если Firefox на iOS когда-нибудь перейдёт на Gecko, вопрос с расширениями встанет заново. Пока же блокировщик работает ровно в тех пределах, которые задаёт Content Blocker API.</p><p>Источники: <a href="https://blog.mozilla.org/en/firefox/ad-blocker-on-ios/">Introducing Ad Blocker for Firefox on iOS (Mozilla)</a>, <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/155">Firefox 155 for developers (MDN)</a>, <a href="https://www.mozilla.org/en-US/security/advisories/mfsa2026-82/">Mozilla Foundation Security Advisory 2026-82</a></p><p>Изображение на обложке: Mozilla</p>]]></content:encoded>
    </item>
    <item>
      <title>Google удалил uBlock Origin и другие расширения Manifest V2 из магазина Chrome</title>
      <link>https://tproger.ru/news/google-ubral-ublock-origin-i-ostalnye-raswireniya-manifest-v2-iz</link>
      <comments>https://tproger.ru/news/google-ubral-ublock-origin-i-ostalnye-raswireniya-manifest-v2-iz?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/google-ubral-ublock-origin-i-ostalnye-raswireniya-manifest-v2-iz</guid>
      <description><![CDATA[<p>31 августа Google удалил из Chrome Web Store все расширения Manifest V2, включая uBlock Origin. Что произошло с уже установленными расширениями, куда переехать пользователям и что менять разработчикам при переходе на Manifest V3.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/google-ubral-ublock-origin-i-ostalnye-raswireniya-manifest-v2-iz">Google удалил uBlock Origin и другие расширения Manifest V2 из магазина Chrome</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Google Chrome]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 01 Sep 2026 17:25:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>Google 31 августа удалил из Chrome Web Store все оставшиеся расширения на <b>Manifest V2</b>, и вместе с ними из магазина исчез полный <b>uBlock Origin</b>, самый популярный блокировщик рекламы. Дата удаления указана в <a href="https://developer.chrome.com/docs/extensions/develop/migrate/mv2-deprecation-timeline">официальном графике отказа от Manifest V2</a> и продублирована в <a href="https://github.com/gorhill/uBlock">README проекта</a>: «Chrome Web Store: удалён 31 августа 2026 года». Карточка расширения в магазине больше не открывается: магазин отвечает, что элемент недоступен.</p><p>Для пользователя Chrome это означает, что установить полный uBlock Origin из магазина больше нельзя, а там, где он ещё стоит, он уже не работает без корпоративной политики. Для разработчиков расширений закончился последний переходный режим: с этого дня у клиентов не может быть рабочей V2-сборки, которую можно было бы чинить и обновлять.</p><ul><li>31 августа 2026 года Google удалил из Chrome Web Store все расширения Manifest V2; uBlock Origin в их числе.</li><li>Chrome 138 был последней версией, где корпоративная политика ExtensionManifestV2Availability могла включить V2; в Chrome 139 политика удалена.</li><li>Установленные V2-расширения на старых версиях Chrome остаются в списке, но отключены для обычных пользователей ещё с марта 2025 года и не обновляются.</li><li>Полный uBlock Origin доступен в Firefox Add-ons и Microsoft Edge Add-ons; для Chrome автор предлагает uBlock Origin Lite на Manifest V3.</li><li>Разработчикам: путь V2 в Chrome Web Store закрыт полностью; Edge завершает переход позже по своему графику.</li></ul><h2>Чем Manifest V3 отличается от V2 и почему это важно для блокировщиков</h2><p>Manifest — это набор правил, по которым браузер разрешает расширениям вмешиваться в работу страниц. В V2 расширение могло само перехватывать каждый сетевой запрос через webRequest, анализировать его и блокировать по своей логике. В V3 этот механизм заменён на declarativeNetRequest: расширение заранее передаёт браузеру список правил фильтрации, а решения принимает сам Chrome. Google объясняет переход безопасностью и производительностью: расширение больше не видит содержимое запросов и не может выполнять удалённо загруженный код.</p><p>Для блокировщиков разница принципиальная. Число правил ограничено, динамические правила по содержимому страницы невозможны, а списки фильтров нельзя обновлять чаще, чем выходит новая версия расширения. Автор uBlock Origin Рэймонд Хилл с начала перехода писал, что полноценная версия в этой модели невозможна, и выпустил отдельное расширение uBlock Origin Lite, которое живёт в рамках V3. По его README, у Lite нет динамической фильтрации, а часть косметических правил работает только в более агрессивных режимах.</p><h2>Хронология: четыре с половиной года на переезд</h2><ul><li>Январь 2022 года: Chrome Web Store перестал принимать новые публичные и unlisted-расширения на V2.</li><li>Июнь 2022 года: магазин перестал принимать новые приватные V2-расширения.</li><li>31 марта 2025 года: V2 начали отключать по умолчанию у обычных пользователей; корпоративные клиенты могли включить его ключом политики ExtensionManifestV2Availability.</li><li>Chrome 138: последняя версия, в которой этот ключ работал; в Chrome 139 политика удалена.</li><li>31 августа 2026 года: все оставшиеся V2-расширения удалены из Chrome Web Store.</li></ul><blockquote>All remaining Manifest V2 extensions are removed from the Chrome Web Store.</blockquote><h2>Что происходит с уже установленным uBlock Origin</h2><p>Если расширение стоит на Chrome 138 и старше, оно остаётся в списке установленных, но для обычных пользователей уже отключено: с марта 2025 года включить его могла только корпоративная политика. Обновлений оно не получает, в том числе списков фильтров, которые у полной версии обновляются через код расширения. После удаления из магазина переустановить его оттуда нельзя. На Chrome 139 и новее полный uBlock Origin не запускается независимо от того, откуда он был установлен.</p><p>Практический выбор для пользователя Chrome сводится к трём вариантам. Первый: uBlock Origin Lite, который использует встроенный API фильтрации и справляется с большинством рекламы, но уступает полной версии. Второй: Firefox, где, по словам самого автора в README, uBlock Origin «работает лучше всего». Третий: Microsoft Edge, в чьём магазине расширение по-прежнему есть; Edge, по графику в README, завершает переход на V3 позже Chrome; для Opera README указывает лишь доступность uBlock Origin. Про Brave отдельной оговорки в README нет.</p><h2>Что это значит для разработчиков расширений</h2><p>Новости для тех, кто пишет под Chrome, нет уже год: в Chrome Web Store V2 нельзя было опубликовать с 2022 года. Изменилось другое: закончился режим «у клиентов ещё стоит старая версия, и её можно чинить». Если у продукта остались V2-сборки в корпоративных установках, они больше не получат ни одного обновления, и переезд на V3 из «когда-нибудь» стал срочным.</p><ul><li>Сетевую фильтрацию переносите на declarativeNetRequest: статические правила в JSON внутри пакета, динамические через API, с лимитом на число правил, который стоит проверить по документации Chrome до проектирования.</li><li>Фоновые страницы заменяйте на service worker; он засыпает, поэтому состояние держите в chrome.storage, а не в переменных.</li><li>Удалённо загружаемый код в V3 запрещён: вся логика должна быть внутри пакета расширения; списки фильтров обновляются только с новой версией.</li><li>Перед публикацией проверьте тот же пакет в Edge и Firefox: у них свои магазины и свои отличия в поддержке V3.</li></ul><h2>Что дальше</h2><p>Google завершила переход, который анонсировала ещё в 2019 году. Следующий фронт — сам API declarativeNetRequest: авторы блокировщиков будут добиваться повышения лимитов на правила и новых возможностей, а Google будет решать, насколько далеко готова пойти. Пока этого не произошло, Chrome остаётся браузером, где реклама блокируется хуже, чем в Firefox, и это уже не временная ситуация, а свойство платформы.</p><p>Источники: <a href="https://developer.chrome.com/docs/extensions/develop/migrate/mv2-deprecation-timeline">Manifest V2 support timeline (Chrome for Developers)</a>, <a href="https://github.com/gorhill/uBlock">Репозиторий uBlock Origin</a>, <a href="https://chromewebstore.google.com/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm">Карточка uBlock Origin в Chrome Web Store</a>, <a href="https://news.ycombinator.com/item?id=49514878">Обсуждение на Hacker News</a></p><p>Изображение на обложке: скриншот Chrome Web Store</p>]]></content:encoded>
    </item>
    <item>
      <title>RAG-бот для любого сайта на Python за 60 строк кода</title>
      <link>https://tproger.ru/articles/rag-bot-dlya-lyubogo-sajta-na-python-za-60-strok-koda</link>
      <comments>https://tproger.ru/articles/rag-bot-dlya-lyubogo-sajta-na-python-za-60-strok-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/rag-bot-dlya-lyubogo-sajta-na-python-za-60-strok-koda</guid>
      <description><![CDATA[<p>Соберите простого RAG-бота на Python, который читает любую веб-страницу и отвечает на вопросы только по её тексту. Гайд с кодом и объяснениями.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/rag-bot-dlya-lyubogo-sajta-na-python-za-60-strok-koda">RAG-бот для любого сайта на Python за 60 строк кода</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 26 Aug 2026 12:06:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если попросить языковую модель ответить по свежей документации или конкретному сайту, она с блеском выдумает то, чего там нет. Стандартное решение — <strong>Retrieval-Augmented Generation (RAG)</strong>: сначала достать реальный текст, найти в нём нужные куски и только потом передать их модели в качестве контекста.</p><p>В этой статье соберём работающего RAG-бота, который отвечает на вопросы о любой веб-странице, примерно на 60 строках Python. Никаких парсеров HTML, headless-браузеров и сложных фреймворков — только requests, локальная Ollama и чистый Markdown.</p><h2>Что такое RAG</h2><p>RAG (retrieval-augmented generation) — это подход, при котором языковая модель не отвечает по своей памяти, а сначала ищет релевантные фрагменты во внешнем тексте, а потом генерирует ответ на их основе. Это резко снижает галлюцинации и позволяет работать с данными, которых не было в обучающей выборке.</p><ul><li>RAG-бот на Python укладывается в ~60 строк и работает без облачных LLM.</li><li>Самое неприятное в RAG-пайплайне — очистка HTML; готовый Markdown API убирает эту работу.</li><li>Текст разбивается на чанки (~1200 символов), каждый превращается в эмбеддинг и сравнивается с эмбеддингом вопроса.</li><li>Локальные модели nomic-embed-text и llama3 через Ollama не требуют иностранных карт и VPN.</li><li>Качество ответа зависит от качества исходного текста: сырой HTML зашумляет поиск, чистый Markdown улучшает ретривл.</li></ul><h2>Что мы соберём</h2><p>Архитектура бота простая и универсальная:</p><ol><li>Отправляем URL в сервис извлечения текста и получаем чистый Markdown.</li><li>Разбиваем Markdown на фрагменты (чанки) по границам абзацев.</li><li>Превращаем каждый чанк в вектор — эмбеддинг.</li><li>То же самое делаем с вопросом пользователя.</li><li>Находим чанки, ближайшие к вопросу, по косинусной близости.</li><li>Отдаём найденные фрагменты + вопрос языковой модели с инструкцией отвечать только по контексту.</li></ol><p>Такая схема легко масштабируется: можно заменить локальную Ollama на OpenAI, Anthropic или российские модели, а векторы перенести в Qdrant или Chroma.</p><h2>Что понадобится</h2><ul><li>Python 3.9+</li><li>Библиотека requests</li><li>Локально запущенная Ollama с моделями nomic-embed-text и llama3</li><li>Доступ к API извлечения текста (в примере — <a href="https://rapidapi.com/xiaobao882026/api/web-to-markdown-json-api" rel="noopener noreferrer">Web to Markdown/JSON API</a>; бесплатный тариф даёт 50 запросов в сутки)</li></ul><h2>Код бота</h2><p>Сохраните скрипт как rag_bot.py и подставьте свой ключ, если сервис извлечения текста требует авторизации:</p><p><b>На что обратить внимание:</b><br />Если вы используете RapidAPI-версию сервиса, запрос к API_URL обычно требует заголовка X-RapidAPI-Key. Без ключа бесплатный endpoint может вернуть 401.</p><h3>Разбор по частям</h3><p>fetch_markdown — единственный внешний вызов. Сервис сам забирает страницу, убирает навигацию, баннеры и футер и возвращает Markdown: заголовки, абзацы, списки. Это освобождает от зависимостей вроде BeautifulSoup или headless Chrome.</p><p>chunk_markdown режет текст на фрагменты примерно по 1200 символов, не разрывая абзацы. Мелкие чанки дают более точный ретривл, но увеличивают число эмбеддингов; для начала 1200 символов — хороший баланс.</p><p>embed и cosine превращают текст в векторы и считают их близость. Модель nomic-embed-text из Ollama бесплатна, быстрая и неплохо понимает русский и английский.</p><p>answer эмбеддит вопрос, выбирает три самых похожих чанка и строит промпт с жёстким ограничением: отвечать только по контексту. Это главная страховка от галлюцинаций.</p><h2>Запуск</h2><p>Установите зависимости и скачайте модели в Ollama:</p><p>Если всё в порядке, в консоли появится примерно такой результат:</p><h2>Почему важен чистый Markdown</h2><p>Если скормить эмбеддинг-модели сырой HTML, в векторах окажутся теги &lt;div&gt;, меню навигации и копирайты из футера. В результате поиск похожести выдаст «Copyright © 2026» вместо полезного ответа. Чистый Markdown — заголовки, абзацы, списки — улучшает качество ретривла почти бесплатно.</p><p>Если не хочется зависеть от внешнего API, можно заменить fetch_markdown на один из альтернативных вариантов:</p><ul><li><a href="https://github.com/adbar/trafilatura" rel="noopener noreferrer">trafilatura</a> — библиотека на Python для извлечения главного текста.</li><li><a href="https://r.jina.ai/http://example.com" rel="noopener noreferrer">r.jina.ai/http://URL</a> — бесплатный сервис без ключа.</li><li><a href="https://www.firecrawl.dev/" rel="noopener noreferrer">Firecrawl</a> — API с поддержкой сканирования сайтов целиком.</li><li><a href="https://github.com/scrapingbee" rel="noopener noreferrer">ScrapingBee</a> — прокси + рендеринг для сложных страниц.</li></ul><p>Для российских разработчиков локальная Ollama особенно удобна: модели качаются бесплатно, не нужны иностранные карты, а инференс идёт на своём железе.</p><h2>Куда развивать</h2><ul><li>Направьте бота на документацию, чейнджлог или блог конкурента и задавайте вопросы по ним.</li><li>Замените Ollama на OpenAI, Anthropic, Gemini или российские модели — функция answer меняется в двух строках.</li><li>Сохраняйте эмбеддинги в векторную БД: Chroma, Qdrant или FAISS, чтобы индексировать сразу много страниц.</li><li>Используйте формат json вместо Markdown, если нужна структура: параграфы, заголовки, ссылки — отдельно.</li></ul><h2>Выводы</h2><p>RAG — не магия, а последовательность простых шагов: получить чистый текст, разрезать его на фрагменты, найти ближайшие к вопросу и отдать их модели. Весь минимальный пайплайн укладывается в короткий Python-скрипт, который можно запустить на своём ноутбуке.</p><blockquote>RAG работает ровно так хорошо, каков текст, который вы ему скармливаете. Уберите самую утомительную часть — очистку HTML, — и останется интересное: поиск и генерация.</blockquote><p>Исходник идеи — статья <a href="https://dev.to/bao001_xiao_37db0a18ce6b2/chat-with-any-website-build-a-rag-bot-in-60-lines-of-python-1m1k" rel="noopener noreferrer">«Chat With Any Website: Build a RAG Bot in ~60 Lines of Python»</a>. Попробуйте собрать бота на своей странице и посмотрите, где он справляется, а где начинает фантазировать.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как мы детектили фрод, а получили Джонни и Джулию: история одной браузерной разминки</title>
      <link>https://tproger.ru/articles/kak-my-detektili-frod-a-poluchili-dzhonni-i-dzhuliyu-istoriya-odnoj</link>
      <comments>https://tproger.ru/articles/kak-my-detektili-frod-a-poluchili-dzhonni-i-dzhuliyu-istoriya-odnoj?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Альберт]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-my-detektili-frod-a-poluchili-dzhonni-i-dzhuliyu-istoriya-odnoj</guid>
      <description><![CDATA[<p>Как мы боролись с фродом, а получили браузерную разминку для шеи. История о том, как система видеоидентификации превратилась в разминку с Джонни и Джулией, и почему побочные эффекты иногда лучше запланированных фич.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-my-detektili-frod-a-poluchili-dzhonni-i-dzhuliyu-istoriya-odnoj">Как мы детектили фрод, а получили Джонни и Джулию: история одной браузерной разминки</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Компьютерное зрение]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 17 Aug 2026 08:52:36 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет, Тпрогер. Меня зовут Степанян
Альберт (<a>albert.stepanyan@beorg.ru</a>), и я
всё ещё бегун по граблям и разработчик отдела R&amp;D в компании «Биорг».</p><p>В Древнем Риме говорили: «Mens sana in corpore sano» - в
здоровом теле здоровый дух. Два тысячелетия спустя мы, айтишники, превратили
эту мудрость в её полную противоположность: здоровый дух, сидящий в нездоровом
теле перед монитором. Наш позвоночник принимает форму вопросительного знака, а
шея начинает напоминать ржавый механизм - повернуть голову можно только всем
корпусом, издавая при этом характерный хруст.</p><p>Мы в «Биорг» знаем об этой проблеме не понаслышке. Но, в отличие
от большинства офисных работников, у нас под рукой оказалась система
видеоидентификации, способная видеть каждое микродвижение человеческого лица. И
как-то раз, тестируя систему видеоидентификации, мы поймали себя на мысли:</p><p><i>- То, что мы создавали для идентификации личности, по сути
готовый трекер движений. Дай ему только интерфейс и он превратится в игру.
Осталось только придумать, во что играть…</i></p><p><a href="https://neck-warmup.beorg.ru/">Попробовать разминку с
Джонни и Джулией</a></p><p>Бесплатно, без смс, без регистрации и без подвоха. Под музыку
или без! Нам не жалко. Мы вообще-то хотим просто шею размять, а не бизнес на
этом строить.</p><h3>Обычный антифрод и его необычная судьба</h3><p>Одна из основных наших задач в R&amp;D - борьба с фродом. Мы
разработали систему видеоидентификации, которая определяет живость человека по
движениям головы, согласно командам. Корректность их выполнения подтверждает,
что перед нами живой пользователь.</p><p>О том, как мы пришли к этому решению и почему оно эффективно,
уже рассказано в статье <a href="https://habr.com/ru/articles/1016592/">Развенчан
маскарад подделок: прорыв в проверке документов</a></p><p>В процессе работы мы научились детектировать ключевые точки лица
с высокой точностью. Алгоритм в реальном времени вычисляет углы поворота
головы, наклоны, моргания. И однажды мы заметили, что эти движения похожи на
те, которые человек выполняет во время зарядки.</p><p>Тогда и родилась идея: а что, если мы сделаем не просто
идентификацию, а полезную разминку для шеи, встроенную прямо в браузер?</p><h3>Рождение Джонни и Джулии</h3><p>Испытать искреннее удивление от собственных возможностей и
окружающего мира - это прекрасные и глубокие ощущения. Получить их может
человек, который вырвался из привычной рутины и столкнулся с тем, что выходит
за рамки его повседневного опыта. Так на свет появились два персонажа: Джонни и
Джулия.</p><p>Их история похожа на красивый роман. За плечами дипломы одного
из лучших университетов мира и блестящие перспективы за рубежом. Они приехали в
Россию как гости, желая увидеть страну. Россия встретила их искренним
гостеприимством, новой культурой, непередаваемой атмосферой. Наша страна
покорила их сердца навсегда. Очарованные увиденным, они приняли главное решение
в своей жизни - остаться здесь, с нами.</p><figure><img src="https://media.tproger.ru/user-uploads/139720/2026-08-07/6037b387-c648-433f-aa2b-9b7cc95882e8.webp" alt="" /></figure><p>Почему двое? Мы добавили в виджет определение пола пользователя
на старте - система определяет, кто перед камерой, и предлагает тренера того же
пола. Это мелочь, но она делает взаимодействие чуть более персонализированным.
Для определения пола используется открытая библиотека face-api.js с лицензией
MIT. По желанию, пол инструктора можно сменить. Для этого есть специальная
кнопка на экране - справа вверху.</p><p>Персонажей мы нарисовали в мультяшном стиле - яркие, добрые, с
улыбкой. Потому что разминка должна вызывать радость, а не напряжение. К тому
же, мы подумали: если пользователь сейчас будет делать серьёзное лицо, разминая
шею, это выглядит глупо. А если рядом весёлый инструктор - процесс идёт легче.</p><p>Есть один нехитрый приём, который делает картинку цельной. Мы
убираем фон у окна с пользователем и заменяем его на белый. То же самое делаем
с фоном инструктора. В результате их фоны сливаются с общим белым фоном
страницы, и визуально окна перестают быть «окнами» - они превращаются в единую
композицию. Пользователь видит себя и тренера в одном пространстве, а не в двух
отдельных квадратах.</p><figure><img src="https://media.tproger.ru/user-uploads/139720/2026-08-07/05d1c05f-df3f-4c64-bf50-a882519e624b.webp" alt="" /></figure><h3>Как мы считаем синхронизацию</h3><p>Разминка состоит из 30 движений, и они каждый раз генерируются
случайным образом. Никаких заучиваний - каждый новый подход будет отличаться от
предыдущего. Это не даёт скучать и не позволяет мозгу «засыпать» на
автоматических движениях.</p><p>Разминка состоит из нескольких упражнений. У каждого есть
ожидаемая длительность - t.time. Пока пользователь выполняет движение, мы
замеряем его фактическую скорость и фиксируем задержку (тот самый delay) - насколько пользователь отстаёт от тренера.</p><p>Когда все упражнения завершены, мы суммируем две величины:</p><p>totalExp - общее ожидаемое время всех движений;</p><p>totalDelay  - суммарное отставание пользователя.</p><p>Дальше простая формула:</p><p>То есть, если вы выполнили разминку идеально синхронно - твой
скор стремится к 100. Но мы оставили люфт, потому что в реальном мире есть
погрешности: камера может чуть дрожать, браузер - подвисать, а твоя шея - иметь
свою точку зрения на то, как быстро надо поворачиваться.</p><p>И ещё один важный нюанс по геймплею. Мы заметили в тестах, что
некоторые пользователи не могли с первого раза повторить то или иное движение.
Может шея затекла, может не поняли траекторию. Зависать на одном движении
бесконечно - плохая идея. Это раздражает и убивает смысл разминки.</p><p>Поэтому мы сделали так: после двух неудачных повторов инструктор
переходит к следующему движению. Пользователь не чувствует себя неудачником, а
просто продолжает разминку. А если он вообще не понял, что делать, - система не
наказывает, а мягко ведёт дальше. В конце его ждёт честный результат, а не
строгий экзамен.</p><p>Итоговый результат мы очеловечиваем:</p><p>98%, а не 100% специально обозначено как идеал. Потому что
перфекционизм это хорошо в коде, но вредно для здоровья. Если ты получил 98%, то считай, что ты чемпион. А вот 30% это повод не расстраиваться, а
попробовать ещё раз, просто поймав ритм.</p><h3>Как мы подружили разминку с телефонами</h3><p>Мы изначально проектировали разминку для больших мониторов
лэптов и рабочих станций - удобно: сидишь перед камерой ноутбука, поворачиваешь
голову, и Джонни с Джулией тебя понимают. Но когда мы решили затестить у
коллег, то первым их вопросом было:</p><p><i>- А на телефоне это работать будет?</i></p><p>Первая мысль была определять устройство по размеру экрана. Но
это оказалось ловушкой. Современные телефоны имеют диагональ почти как у
небольших ноутбуков, а планшеты и вовсе размывают границы.</p><p>Я лично столкнулся с этой проблемой на своём Redmi Note 9. Экран
у него, конечно, не как у ноутбука, но по ширине в пикселях он вполне
сопоставим с некоторыми дешёвыми ноутбуками. Система считала, что раз экран
достаточно широкий значит, это компьютер, и отказывалась переключаться в
мобильный режим. Кнопки оставались мелкими, интерфейс не адаптировался, а
инструктор с пользователем пытались уместиться в той же раскладке, что и на
большом экране. Работать было невозможно.</p><p>Стало понятно, размер экрана  это ненадёжный признак, и
нужно искать что-то другое.</p><p>Тогда я пошёл другим путём: проверять наличие датчика
ориентации, но не одним, а двумя признаками:</p><p>Первое условие - поддержка события ориентации (есть у телефонов
и планшетов). Второе - поддержка касаний (отсекает компьютеры, даже если у них
случайно затесался акселерометр). Вместе 2 условия дают почти 100% точность.</p><p>Если проверка проходит, то добавляем на страницу класс <i>mobile</i>:</p><p>И дальше уже через CSS управляем всем, что должно отличаться. Но
самое главное это размер и положение окна с пользователем и инструктором.</p><p>На компьютере, как и на телефоне, в горизонтальном режиме, мы
используем классическую раскладку: пользователь слева, инструктор справа. Это
естественно для широкого экрана - взгляд скользит слева направо, и ты видишь
одновременно и себя, и тренера.</p><p>На телефоне в вертикальном режиме всё иначе. Экран узкий, и
раскладка «слева-направо» не работает. Поэтому пользователь занимает верхнюю
половину экрана, а окно с инструктором нижнюю. Так пользователь видит и
тренера, и себя одновременно.</p><p>И это не просто визуальная прихоть. Если окно с пользователем
слишком маленькое - он не видит, правильно ли выполняет движения. Если слишком
большое - перекрывает инструктора: теряется смысл «повторяй за мной». Поэтому
мы потратили несколько итераций, чтобы найти идеальные пропорции для каждого
типа устройства и каждой ориентации.</p><p>Сам полноэкранный режим мы, кстати, реализовали и для компа, и
для телефона:</p><p>Справедливости ради: подсказка про выход из полноэкранного
режима появляется и на компьютере, и на телефоне. Просто она разная. На
компьютере - «Нажмите Esc для выхода из полноэкранного режима». На телефоне - «Проведите снизу вверх для выхода из полноэкранного режима». В обоих случаях
она исчезает через 3 секунды, чтобы не мешать пользователю разминаться.</p><h3>Трекинг лица: локальная сборка без сюрпризов</h3><p>Для трекинга лица в разминке мы используем MediaPipe Face Mesh.
Это открытая библиотека от Google, распространяемая под лицензией Apache 2.0.
Мы взяли её в локальную сборку, поэтому всё работает стабильно и без внешних
запросов к CDN. Никаких сюрпризов с недоступными серверами или обновлёнными
API. Только предсказуемая логика в твоём браузере.</p><p>Инициализируем трекер так:</p><p>Обратите внимание на refineLandmarks: false - мы выключили его
специально. Нам не нужна микро-детализация губ и глаз, только общий контур
головы. Экономия ресурсов браузера это наше всё. И, кстати, именно благодаря
локальной сборке мы можем настраивать параметры под свои задачи, не оглядываясь
на внешние зависимости.</p><p>И ещё один бонус локального подхода: библиотека лежит в нашем
проекте, а браузер кеширует её при первом запросе, так что при повторных
запусках она не скачивается заново.</p><p>И главное, что MediaPipe работает независимо от того, как ты
держишь телефон: вертикально или горизонтально. Главное, чтобы лицо было в
кадре!</p><h3>Какой режим выбрать?</h3><p>В итоге оказалось, что в вертикальном режиме пользователь
интуитивно держит телефон на уровне лица и это идеально для детекции. Плюс,
интерфейс с Джонни и Джулией выглядит как видеозвонок с личным тренером.</p><p>А в горизонтальном режиме телефон можно поставить на подставку
или положить на стол и выполнять упражнения, глядя на экран как на маленькое
зеркало. Такой формат больше похож на классический фитнес-гаджет.</p><p>Так что теперь мы рекомендуем вертикальный режим для атмосферы,
а горизонтальный для техничного прохождения с максимальным комфортом.</p><h3>Музыка - двигатель прогресса (и шеи)</h3><p>Когда прототип с Джонни и Джулией заработал, мы дали его
потестить коллегам. Офис разделился на два лагеря.</p><p>Первые, хмуро глядя в монитор, синхронно поворачивали головы и
напоминали роботов на конвейере. Вторые незаметно покачивались в такт и слегка
пританцовывали, даже когда никто не смотрел. Разница была в одном: у вторых на
фоне тихо играла музыка.</p><p>Мы решили, что пусть пользователь сам решает, хочет ли он
разминаться в тишине или под ритмичный трек. Так появились две кнопки: «Под
музыку» и «Без музыки».</p><p>И если с «тихим» режимом всё просто, то с музыкой пришлось
повозиться. Мы перебрали десяток треков разного темпа, пока не нашли тот самый,
который совпадает с комфортной скоростью поворота головы при разминке. Слишком
быстро - пользователь не успевает, слишком медленно - скучно. Идеальный темп
нашёлся где-то около 140 BPM, как у хорошего транс-хауса.</p><p>И вот теперь представь: ты сидишь после пяти часов дебаггинга,
запускаешь разминку, выбираешь «Под музыку», и на экране появляется симпатичная
Джулия, которая под ритмичный бит начинает поворачивать голову. Ты повторяешь и
незаметно для себя перестаёшь думать о багах и просто двигаешься. Это работает
как медитация.</p><h3>Тайна, которую мы не раскроем (но вы всё равно узнаете)</h3><p>Когда разминка заканчивается и на экране появляется твой
результат что-то происходит.</p><p>Не будем раскрывать, что именно. Пусть это останется сюрпризом
для тех, кто дойдёт до финала. Скажем одно: мы вложили туда частичку нашей
души, и, судя по первым тестам, это вызывает чистую, детскую радость даже у
самых суровых бэкенд-разработчиков.</p><p>Так что когда дойдёте до конца, поделитесь в комментариях, какой
бонус увидели и понравилось ли вам.</p><h3>Заключение</h3><p>История этой разминки это отличное напоминание о том, что лучшие
идеи рождаются не из строгих ТЗ. Мы не планировали делать разминку. Мы
планировали делать антифрод. А заодно получили продукт, который одинаково
полезен и для безопасности системы, и для шеи разработчика.</p><p>А вообще, Джонни и Джулии у нас нравится. Они уже члены нашей команды - с удовольствием ходят на парады и даже поздравляют нас с праздниками.</p><figure><img src="https://media.tproger.ru/user-uploads/139720/2026-08-07/e69a36d3-32d0-4e00-9f25-6e0d81b59476.webp" alt="" /></figure>]]></content:encoded>
    </item>
    <item>
      <title>Zero на Three.js: инженерный разбор интерактивного сайта</title>
      <link>https://tproger.ru/articles/zero-na-three-js-inzhenernyj-razbor-interaktivnogo-sajta</link>
      <comments>https://tproger.ru/articles/zero-na-three-js-inzhenernyj-razbor-interaktivnogo-sajta?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/zero-na-three-js-inzhenernyj-razbor-interaktivnogo-sajta</guid>
      <description><![CDATA[<p>Разбираем, как BUNQ LABS сделала zero.university: виртуальный скролл, шейдеры, KTX2/DRACO, адаптивное качество и загрузка текстур без фризов. Проверьте техники.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/zero-na-three-js-inzhenernyj-razbor-interaktivnogo-sajta">Zero на Three.js: инженерный разбор интерактивного сайта</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 28 Jul 2026 04:19:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Представьте, что вы заходите на сайт, а он не пускает. Нет кнопки «войти» — только поле, где нужно нарисовать ноль. Как только круг замыкается, из линии расходится инеевый узор, и сайт начинает рассказывать историю. Это не декоративная заглушка: так работает <a href="https://zero.university/">zero.university</a> — кейс, где первый жест пользователя сразу задаёт тон всему повествованию.</p><p><b>Zero</b> — иммерсивный лендинг индийского стартапа Zero University, который предлагает альтернативу классическому университетскому пути. Сайт превращает скролл в шестиактную историю: традиционное образование, разбитое стекло, горящие деньги, уничтоженные сертификаты, тоннель из логотипа ZERO и, наконец, интерактивная карта города с офисами реальных компаний. Цель — не просто показать красивую картинку, а провести пользователя через аргумент: диплом перестаёт быть гарантией, а навыки открывают дорогу в индустрию.</p><p>Проект разрабатывала студия <b>BUNQ LABS</b> четыре месяца. Исходные ассеты занимали больше гигабайта: несжатые Blender-сцены, 8K-текстуры и запечённые анимации. Финальная сборка уместилась в 10 МБ и держит 60 FPS даже на бюджетном Android. Команда опубликовала технический разбор на Codrops, а мы выделили решения, которые можно перенести в свои WebGL-проекты.</p><ul><li>Первый жест как ворота: распознавание нуля — это простая проверка угла, округлости и замкнутости, а не нейросеть.</li><li>Виртуальный скролл заменяет нативный: одно число управляет загрузкой, анимацией, шейдерами и текстом.</li><li>Ассеты важнее рендера: DRACO, KTX2/ETC1S, атласы и собственный превьювер сжали гигабайты до мегабайтов.</li><li>Текстурные загрузки — главный источник фризов; декодинг в воркере и очередь по requestIdleCallback решают проблему.</li><li>Адаптивное качество по frame time позволяет не гадать о мощности устройства.</li><li>Мобильная точность шейдеров: mediump на Adreno и Mali — это реальный 16-битный float, и его недостаточно для сложных эффектов.</li></ul><p>Разбираем, как это устроено изнутри, и что из этого можно взять в свою работу.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-07-28/00e5f2ad-8fc7-49b9-88da-322a34a6bef1.webp" alt="Шесть этапов интерактивного повествования zero.university: от традиционного образования до интерактивной карты города." /><figcaption>Схема повествования: шесть этапов и пять «ворот», через которые проходит пользователь. Источник: Codrops / BUNQ LABS</figcaption></figure><h2>Сюжет из шести этапов и пяти ворот</h2><p>Интерактивный нарратив строится вокруг пяти «ворот» — точек, где скролл останавливается и ждёт действия пользователя. Сначала нужно нарисовать ноль, затем удерживать касание, чтобы разбить стекло, потом — чтобы запуститься сквозь тоннель. Каждый жест связан с сюжетным поворотом: обещание университетского пути буквально трескается, за ним появляется статистика безработицы, диплом превращается в горящую бумагу, сертификаты рвутся на полосы.</p><h3>От обещания к свободе</h3><p>Шесть этапов идут от иллюзии контролируемого пути к интерактивной карте, где пользователь сам выбирает, куда смотреть. Финальный экран — город с башней Zero University в центре. Можно приближать, панорамировать и открывать карточки ролей, сценариев и инструментов. Это не просто финал: после того как сайт вёл пользователя за руку, он отдаёт управление обратно.</p><h2>Архитектура: один скролл управляет всем</h2><p>Одно из главных архитектурных решений — отказ от нативного скролла браузера. Нет ScrollTrigger, нет огромного прокручиваемого DOM. Вместо этого события колёсика и тача обновляют виртуальное значение скролла, которое плавно догоняет цель. Всё остальное — загрузка ассетов, анимации, тайминги шейдеров, текст и оверлеи — читают это единственное число.</p><p>Проект разбит на девять таких сегментов; загрузчик одновременно выполняет роль первых ворот. Каждый сегмент самодостаточен: у него свой жизненный цикл, свои объекты и своя утилизация. Это упростило поддержку и отладку. Переход к любому этапу воспроизводит жизненные циклы всех предыдущих сегментов, поэтому состояние всегда консистентно — как будто пользователь дошёл до этого места естественным скроллом.</p><h2>Конвейер 3D-ассетов: как уместить 1 ГБ в 10 МБ</h2><p>Большую часть четырёх месяцев ушла не на код, а на подготовку ассетов. Исходники пришли из Blender: несжатая геометрия, 8K-текстуры, запечённые анимации — всё вместе больше гигабайта. Первый месяц команда тратила на то, чтобы выбрать формат для каждого типа ресурсов.</p><h3>DRACO и KTX2</h3><p>Вся геометрия отправляется со сжатием DRACO, декодеры для которого хостятся локально в public/vendor/. Урок команда усвоила на собственном опыте: замедление на gstatic и unpkg привело к тому, что все сжатые ассеты перестали декодироваться, хотя сами файлы лежали на ихних серверах. Если декодер зависит от чужого CDN, весь пайплайн зависит от него.</p><p>Самый большой выигрыш дали текстуры. PNG может быть маленьким на диске, но в видеопамять он загружается распакованным. Текстура 2048² занимает около 16 МБ VRAM независимо от размера файла. Формат KTX2 со сжатием ETC1S остаётся сжатым на GPU, занимает меньше памяти и загружается быстрее.</p><h3>Собственный превьювер компрессии</h3><p>С KTX2 есть проблема: ETC1S — lossy, и локально его не посмотреть обычным просмотрщиком. Чтобы не гадать с настройками, команда сделала внутренний дашборд: сжатая и несжатая версия каждой картинки и видео рядом. Так можно было подобрать степень сжатия индивидуально — усилить там, где артефакты не заметны, сохранить качество для ключевых объектов и отключить мипмапы, где они не нужны. Инструмент простой, но редко встречается в WebGL-пайплайнах, хотя экономит огромное количество времени и памяти.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-07-28/3a57d9e3-14e7-4f55-8aad-78cee34f1da3.webp" alt="Внутренний дашборд команды для сравнения сжатой и несжатой версии каждого ассета." /><figcaption>Превьювер компрессии: сжатая и несжатая версии текстур и видео рядом. Источник: Codrops / BUNQ LABS</figcaption></figure><h3>Атласы вместо дюжин картинок</h3><p>Похожие текстуры собрали в общие атласы. Например, все текстуры рук уместили в один атлас 4×4, а каждая mesh сдвигала UV-координаты, чтобы взять свой кусок. Спрайты текста, сертификаты, бумажные обрывки, облака, монеты и осколки стекла тоже ушли в атласы. Больше 50 отдельных изображений превратились примерно в дюжину атласов, а большинство градиентных фонов заменили несколькими строками GLSL. Ранние сборки весили 35–40 МБ, финальная — меньше 10 МБ. При этом интерактивная карта мира вынесена в отдельную группу загрузки, чтобы не блокировать открытие сайта.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-07-28/e1686dcf-b13a-494e-94b3-0e32f0eb880a.webp" alt="Атлас текстур рук 4×4: каждая mesh сдвигает UV-координаты, чтобы взять свой кусок." /><figcaption>Атлас рук: все текстуры рук упакованы в одну текстуру 4×4. Источник: Codrops / BUNQ LABS</figcaption></figure><h2>Текстурные загрузки: главный источник фризов</h2><p>Уменьшить скачивание — только половина дела. Сжатые текстуры всё равно нужно загрузить в GPU на главном потоке, и крупная текстура легко блокирует рендер на 50 мс — достаточно, чтобы потерять несколько кадров. Если эта загрузка случается впервые во время скролла, подёргивание заметно сразу. Сайт может хорошо показывать себя в бенчмарках и при этом чувствоваться вязким.</p><ul><li>Декодировать вне главного потока — через createImageBitmap(). Тогда во время рендера остаётся только загрузка в GPU.</li><li>Загружать в GPU в простое — декодированные текстуры ставят в очередь и выгружаются по requestIdleCallback, пока есть запас времени.</li><li>Разбивать большие атласы на плитки 256² и загружать по одной на кадр, чтобы не выбиваться из бюджета кадра.</li></ul><p>Когда известно, что следующий этап вот-вот появится — после загрузчика или во время перехода между воротами — очередь сбрасывается синхронно. Все нужные текстуры уже в видеопамяти, прежде чем они появятся на экране.</p><h2>Адаптивное качество по реальному frame time</h2><p>Невозможно заранее знать, на каком устройстве откроется сайт. Рендерер поэтому постоянно измеряет время кадра по скользящему окну и динамически меняет уровень качества. Если рендеринг замедляется — понижается tier. Если производительность стабильно высокая — tier снова растёт. Задержка между переключениями не даёт постоянно метаться у границы.</p><p>Уровни качества влияют только на визуальную полировку: devicePixelRatio, количество сэмплов размытия, геометрию монет, разрешение текста. Сама история остаётся неизменной и на флагмане, и на бюджетном телефоне. Для особо тяжёлых моментов — например, разбитие стекла — рендерер временно понижает пиксельное соотношение и отключает размытие и иней, прячет затраты внутри самого жеста.</p><h2>Шейдеры под каждый эффект</h2><p>Каждый ключевой момент использует собственный шейдер. ИИ помогал сгенерировать первые версии, но все финальные шейдеры переписывались и дорабатывались вручную. Вот несколько приёмов, которые стоит запомнить.</p><h3>Постпроцессинг из нескольких проходов</h3><p>Кадр собирается из цепочки проходов: основная 3D-сцена, процедурный фон, преломление стекла, иней и след от жеста, глубина резкости, foreground с зернистостью и тональной картой, отложенный текст, и в конце — разбитое стекло. Стеклянный, текстовый и шейдер разбития инициализируются лениво и прогреваются в простое, чтобы не попадать на критический путь загрузчика.</p><h3>Иней из нарисованного нуля</h3><p>Эффект инея строится на ping-pong-буфере из четырёх проходов: горизонталь, вертикаль и две диагонали. Каждый проход распространяет нарисованный штрих, захватывая самые яркие соседние пиксели и создавая восьмиугольный паттерн роста. Яркость текстуры льда модулирует шаг распространения, край получается кристаллическим. После замыкания контура центр масс штриха становится точкой отсчёта для радиального таяния.</p><h3>Освещение без источников света</h3><p>Реалтаймовое освещение скинненной меши рук было бы слишком дорогим, а свет должен был точно совпадать с оригинальным артом. Поэтому освещение запекли в текстуры и смешивают между ними. Используются два слота: один содержит текущий ключевой кадр, другой — следующий. По мере проигрывания анимации новый слот плавно вытесняет старый.</p><p>Перед смешиванием альфа предумножается, чтобы вокруг прозрачных краёв рук не появлялись тёмные ореолы. Обе текстуры освещения лежат в одном атласе, поэтому переключение между ключами требует только обновления двух UV-смещений и коэффициента смешивания.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-07-28/cb760b51-b0f4-4804-aff6-58ce015d2fda.webp" alt="Две запечённые текстуры освещения рук внутри одного атласа для плавного переключения." /><figcaption>Запечённое освещение рук: два ключевых кадра в одном атласе смешиваются по прогрессу анимации. Источник: Codrops / BUNQ LABS</figcaption></figure><h3>Горящие деньги</h3><p>Эффект сгорания использует noise-driven distance field. Фронт горения проходит по купюре, слегка опережая точку дискарда. Перед ним появляется тонкий HDR-ободок углей, затем обугленная поверхность. FBM — самая дорогая часть шейдера, поэтому фрагменты отсекаются как можно раньше, если они ещё не достигли порога горения.</p><h3>Рвущиеся сертификаты</h3><p>Каждая вершина хранит индекс полосы, к которой принадлежит фрагмент диплома. Фронт разрыва движется слева направо, и каждая полоса отделяется и падает независимо со своим вращением. Нормали для освещения строятся аналитически из той же волновой функции, которая анимирует меш, поэтому normal map не нужен.</p><h3>Тоннель ZERO</h3><p>Тоннель получается выдавливанием поперечного сечения из логотипа ZERO. Импульс яркости распространяется по мировой координате Z, поэтому эффект остаётся бесшовным, даже когда секции тоннеля повторяются.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-07-28/bfbebb17-dc15-4bbb-b00c-a1fb7f98c13f.webp" alt="Тоннель ZERO, полученный выдавливанием сечения логотипа." /><figcaption>Тоннель ZERO: импульс яркости распространяется по мировой координате Z, сохраняя бесшовность. Источник: Codrops / BUNQ LABS</figcaption></figure><h3>Текст, который приходит в фокус</h3><p>Нарративный текст появляется не мгновенно, а проявляется через семиотводное гексагональное размытие. Радиус размытия зависит от прогресса появления, поэтому буквы будто фокусируются. Проход выполняется в отложенном текстовом проходе и полностью пропускается, когда текст не виден.</p><h3>Точность на мобильных</h3><p>Одна из самых неприятных находок возникла на реальных мобильных GPU. Несколько шейдеров пришлось явно перевести на highp float, потому что на Adreno и Mali mediump — это настоящий 16-битный float. На десктопе ошибок не было, а на телефоне полосы диплома двигались одинаково, а эффект горения покрывался бэндами. Вывод: тестировать на реальных мобильных устройствах нужно с первых дней, а не перед релизом.</p><h2>Дизайн взаимодействий</h2><p>Исходный материал от заказчика состоял из картинок и видео, поэтому поведение каждых ворот проектировали с нуля. Большинство используют общую систему «нажми и удерживай». Общий конфиг задаёт момент появления подсказки и длительность удержания, а каждые ворота реализуют визуал через собственные хуки.</p><p>Пока пользователь удерживает касание, кадр постепенно смещается в тёмно-красный. Когда стекло разбивается, цвет возвращается примерно за 200 мс — это создаёт ощущение, что осколки выбивают темноту. Проверили вариант в 400 мс: он ощущался заметно слабее. Звук разбития привязан к первому отрисованному кадру, а не к таймеру: на медленных устройствах таймер может сыграть раньше анимации, и эффект рассинхронится.</p><h2>Финальная награда — интерактивный мир</h2><p>Последняя последовательность запуска выносит пользователя в открытое небо. Облака расступаются, открывая город с башней Zero University в центре, над которой появляется ореол — финальные ворота. Камера приземляется в интерактивную карту, где можно панорамировать, зумить и открывать карточки с ролями, сценариями и инструментами. Плашка Join Beta превращается в форму waitlist. После того как сайт вёл пользователя через историю, он отдаёт ему контроль — и просит остаться.</p><h2>FAQ</h2><h2>Выводы</h2><p>Самый важный урок проекта — подготовка ассетов и загрузка в GPU заслуживают не меньше внимания, чем сам рендеринг. Инструменты вроде превьювера компрессии, локальных декодеров, очереди загрузки и адаптивного менеджера качества редко выглядят героически, но именно они превратили гигабайт исходников в 10-мегабайтный сайт, который не тормозит на дешёвом телефоне.</p><blockquote>ИИ генерировала первые версии кода и прототип, который выиграл нам проект, за 48 часов. Но полировка — сотни мелких решений, тестирование на реальных устройствах и инженерная интуиция — осталась за людьми.</blockquote><p><b>Источник:</b> технический разбор команды BUNQ LABS на <a href="https://tympanus.net/codrops/2026/07/17/zero-the-engineering-behind-a-defiant-interactive-narrative/">Codrops</a>.<br />Попробуйте открыть <a href="https://zero.university/">zero.university</a> на десктопе и на бюджетном смартфоне — и сравните, где заметнее компромиссы качества.</p>]]></content:encoded>
    </item>
    <item>
      <title>React-паттерн, который все используют, но он убивает производительность</title>
      <link>https://tproger.ru/articles/react-pattern-kotoryj-vse-ispolzuyut-no-on-ubivaet-proizvodite</link>
      <comments>https://tproger.ru/articles/react-pattern-kotoryj-vse-ispolzuyut-no-on-ubivaet-proizvodite?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/react-pattern-kotoryj-vse-ispolzuyut-no-on-ubivaet-proizvodite</guid>
      <description><![CDATA[<p>Почему React.memo перестаёт работать из-за inline-пропсов и как это исправить. Разбираем на примере со 200 строками и замерами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/react-pattern-kotoryj-vse-ispolzuyut-no-on-ubivaet-proizvodite">React-паттерн, который все используют, но он убивает производительность</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 24 Jul 2026 04:56:37 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вы обернули список в React.memo, добавили useCallback на обработчики и ждёте, что интерфейс полетит. Но при каждом вводе в поисковую строку список всё равно тормозит, а Profiler показывает 200 лишних рендеров. Чаще всего виноват не React, а один крошечный JSX-паттерн, который встречается в каждом втором компоненте.</p><p>В статье разбираем, почему React.memo сравнивает пропсы по ссылке, как inline-объекты и inline-функции обнуляют эту оптимизацию, и какие два простых приёма действительно возвращают производительность.</p><p>React.memo пропускает рендер только тогда, когда все пропсы равны по Object.is. Для объектов и функций это проверка по ссылке.</p><p>Inline-объекты и inline-колбэки в JSX создают новую ссылку на каждый рендер родителя, поэтому memo видит «новые» пропсы и снова рисует дочерний компонент.</p><p>В эксперименте со 200 memoизированными строками это дало 243,9 мс на один keystroke; после стабилизации ссылок — 6 мс.</p><p>Сначала выносите статические объекты за пределы компонента, а useCallback применяйте только там, где колбэк действительно пересекается с memoизированным потомком.</p><p>Оптимизировать всё подряд не нужно: измеряйте в Profiler, а не добавляйте хуки «на всякий случай».</p><h2>Как React решает, рендерить компонент заново или нет</h2><p>Когда родитель перерисовывается, React не делает послаблений дочерним элементам только потому, что они обёрнуты в React.memo. Он сравнивает новые пропсы со старыми. Если каждый проп проходит проверку Object.is, React может «отказаться» от рендера — bailout. Если хотя бы один проп не равен, компонент рисуется заново.</p><p>Для примитивов Object.is работает очевидно: 1 === 1 и 'hello' === 'hello'. А вот для объектов и функций сравнение идёт по ссылке.</p><p>Два объекта с одинаковым содержимым — это разные объекты в памяти. То же самое с функциями. Поэтому, когда вы пишете style=\{\{ padding: 16 \}\}, React получает новую ссылку на каждом рендере и считает проп изменившимся.</p><h2>Почему inline-пропсы — это не микрооптимизация, а поломка контракта</h2><p>Сам по себе объект в JSX не вреден. Если компонент дешёвый, редко перерисовывается и не обёрнут в memo, inline-пропсы почти не влияют на скорость. Проблема появляется, когда три условия накладываются друг на друга:</p><ul><li>родитель перерисовывается часто — поиск, скролл, фильтры, live-данные;</li><li>дочерний компонент или поддерево достаточно тяжёлые, чтобы лишний рендер был заметен;</li><li>вы уже добавили React.memo и ожидаете, что React будет пропускать работу.</li></ul><p>В такой ситуации нестабильные ссылки не просто добавляют накладных расходов — они полностью отменяют ту оптимизацию, ради которой вы взяли React.memo. UI продолжает работать, но лагает ввод, тормозят списки, а в Profiler видно, что дерево горит жёлтым при каждом чихе.</p><h3>Классический опасный пример</h3><p>Представьте список товаров из 200 строк. Каждая строка обёрнута в memo, но в месте вызова передаются inline-пропсы:</p><p>Здесь style и onAddToCart создаются заново при каждом рендере ProductList. Для memo это сигнал, что у каждой строки изменились пропсы, и все 200 компонентов рисуются снова.</p><h2>Эксперимент: от 243,9 мс до 6 мс на один keystroke</h2><p>Автор оригинальной статьи собрал контрольный пример: поисковый интерфейс со 200 memoизированными строками. Все строки получают одинаковые логические значения, но новые ссылки на объекты и функции. Результат после шести введённых символов: каждая видимая строка отрендерилась 14 раз.</p><p>В React DevTools Profiler один keystroke дал коммит длительностью 243,9 мс, в котором подсветились все 200 волокон строк. Инструмент @welldone-software/why-did-you-render прямо указал причину: props.style — «different objects that are equal by value», props.onAddToCart — «different functions with the same name».</p><p><b>Почему 14 рендеров?</b><br />
Каждый ввод в поиск меняет searchTerm, родитель перерисовывается, и inline-пропсы дают строкам новые ссылки. Счётчик рендеров растёт на каждый keystroke, даже если отфильтрованные товары не изменились.</p><h2>Как починить: два приёма вместо дюжины хуков</h2><p>Чтобы восстановить bailout, нужно сделать так, чтобы неизменяющиеся значения не получали новую ссылку на каждом рендере. Правило простое: сначала вынести, потом закешировать.</p><h3>1. Статические объекты — за пределы компонента</h3><p>Если объект не зависит от пропсов и состояния, создайте его один раз на уровне модуля. Это дешевле любого хука и не требует dependency-массива.</p><h3>2. Динамические колбэки — useCallback</h3><p>Если функция передаётся в memoизированный компонент и не должна меняться без причины, оберните её в useCallback со стабильным массивом зависимостей.</p><p>После этих двух изменений в эксперименте время рендера упало с 243,9 мс до 6 мс, счётчики строк застыли на 2, а Why Did You Render замолчал — avoidable re-renders исчезли.</p><h2>Когда не нужно ничего стабилизировать</h2><p>Главная ошибка — оборачивать в useCallback каждую функцию и выносить каждый объект за компонент. React сам по себе быстрый, а мемоизация — это контракт, а не стиль кодирования.</p><ul><li>Компонент дёшев и редко перерисовывается — не тратьте когнитивный бюджет команды.</li><li>Дочерний элемент не обёрнут в React.memo — тогда стабильные ссылки ничего не экономят.</li><li>Значение зависит от часто меняющегося состояния — useCallback с нестабильным массивом зависимостей всё равно будет пересоздаваться.</li><li>Вы ещё не замерили в Profiler — оптимизация без измерений почти всегда лишняя работа.</li></ul><p>React Compiler, который сейчас выходит в стабильное состояние, автоматически мемоизирует многое из того, что раньше делали вручную. Но и он не отменяет понимания ссылочной стабильности: useMemo и useCallback остаются полезными, когда нужен точный контроль, например для зависимостей эффектов.</p><h2>Часто задаваемые вопросы</h2><h2>Выводы</h2><p>Inline-объекты и inline-колбэки в JSX — не антипаттерн сами по себе. Они становятся проблемой только на границе memoизации, где React ожидает стабильные ссылки. Как только вы понимаете это правило, многие «таинственные» лишние рендеры перестают быть таинственными.</p><ol><li>Профилируйте до оптимизации, а не после.</li><li>Вынесите статические объекты за компонент — это самый дешёвый способ стабилизации.</li><li>Применяйте useCallback только для колбэков, которые уходят в memoизированные потомки.</li><li>Проверяйте себя через React DevTools Profiler и Why Did You Render.</li><li>Не забывайте про React Compiler, но не полагайтесь на него как на волшебную палочку.</li></ol><blockquote>Мемоизация — это контракт. Если потомок рассчитывает на стабильные ссылки, родитель должен их обеспечить. Нарушение этого контракта стоит намного дороже, чем отсутствие мемоизации вовсе.</blockquote><p><b>Источник:</b> <a href="https://blog.logrocket.com/react-pattern-everyone-uses-kills-performance/" rel="noopener noreferrer">LogRocket — The React pattern everyone uses that kills performance</a>.</p><p>Проверьте свой текущий проект: откройте React DevTools Profiler, введите что-нибудь в поиск и посмотрите, сколько компонентов подсветится жёлтым только из-за новой ссылки в пропсах.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как исправить hydration-ошибки RSC в Next.js: практический гид</title>
      <link>https://tproger.ru/articles/kak-ispravit-hydration-owibki-rsc-v-next-js-prakticheskij-gid</link>
      <comments>https://tproger.ru/articles/kak-ispravit-hydration-owibki-rsc-v-next-js-prakticheskij-gid?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-ispravit-hydration-owibki-rsc-v-next-js-prakticheskij-gid</guid>
      <description><![CDATA[<p>Разбираем, почему возникают hydration mismatches в React Server Components и Next.js App Router, и как находить, исправлять и предотвращать их в production.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-ispravit-hydration-owibki-rsc-v-next-js-prakticheskij-gid">Как исправить hydration-ошибки RSC в Next.js: практический гид</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Отладка]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 21 Jul 2026 11:37:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Hydration mismatch в Next.js легко поймать в next dev, но в production он превращается в минимизированный код ошибки React и ссылку на декодер. В статье разбираем, почему ошибки гидратации особенно болезненны в приложениях с React Server Components, какие причины встречаются чаще всего и какой рабочий процесс помогает находить и предотвращать такие баги.</p><p>Речь пойдёт не о теории reconcile-алгоритма, а о практике: что проверять первым делом, как изолировать проблему через Suspense, куда смотреть в production-логах и как писать тесты, которые ловят регрессии до попадания к пользователям.</p><h2>Что такое hydration mismatch</h2><p>Гидратация — это процесс, при котором React берёт серверный HTML и навешивает на него обработчики событий, после чего страница становится интерактивной. React ожидает, что дерево, которое он отрендерил на клиенте, точно совпадёт с тем, что пришло с сервера. Если строки, атрибуты или структура различаются, возникает hydration mismatch.</p><p>В development-режиме React покажет предупреждение, текст расхождения и стек компонента. В production всё сводится к коротким кодам вроде #418 или #425. Без телеметрии вы не узнаете, на каком маршруте, в каком компоненте и из-за каких данных произошёл сбой.</p><h2>Почему это больно именно в RSC</h2><p>В классическом SSR обычно один серверный рендер и один клиентский проход гидратации. App Router добавляет Server Components, Client Components, потоковую передачу, Suspense-границы, динамические данные маршрута и RSC payload, который едет рядом с HTML.</p><p>Когда несовпадение происходит вне Suspense-границы, React может отбросить весь серверный HTML и перерендерить дерево на клиенте. Приложение заплатило цену серверного рендера, а пользователь не получил ни производительности, ни преимуществ стриминга. Это не просто предупреждение в консоли, а реальная потеря производительности.</p><h2>Ключевые выводы</h2><ul><li>Hydration mismatch в production без телеметрии почти невозможно локализовать: нужна инструментация на клиенте.</li><li>Основные причины: browser-only API, дата/время/локаль, состояние авторизации, невалидный HTML, расширения браузера, CSS-in-JS.</li><li>Граница 'use client' — это не только маркер сборки, но и граница гидратации: серверный рендер должен быть детерминирован.</li><li>Suspense-границы помогают изолировать сбой и не давать ему сломать всё дерево.</li><li>Проверяйте hydration только на production-сборке: next dev ведёт себя иначе.</li><li>Добавьте Playwright-smoke-тесты на критичные маршруты, чтобы ловить регрессии в CI.</li></ul><h2>Самые частые причины</h2><p>Перед тем как копать RSC payload или сравнивать HTML, стоит проверить шесть типовых сценариев. Они покрывают подавляющее большинство production-инцидентов.</p><ul><li><b>Browser-only API во время рендера:</b> window, document, localStorage, navigator — сервер не знает об этих значениях.</li><li><b>Дата, время и локаль:</b> Date, Intl.DateTimeFormat, относительное время — сервер обычно в UTC, пользователь в своей зоне.</li><li><b>Состояние авторизации:</b> сервер рендерит выклогнутый UI, клиент сразу видит авторизованного пользователя.</li><li><b>Невалидный HTML:</b> браузер чинит DOM до гидратации, а React сравнивает с исходным деревом.</li><li><b>Расширения и middleware:</b> браузерные плагины и edge-переписывания меняют HTML.</li><li><b>CSS-in-JS и порядок классов:</b> styled-components и Emotion могут генерировать разные имена классов при стриминге.</li></ul><h3>Browser-only API и сторонние провайдеры</h3><p>Самая частая причина — не ваш собственный код, а сторонний провайдер, который читает localStorage, window или navigator при инициализации. Под это попадают аналитика, фичер-флаги, A/B-тесты, session replay и персонализация.</p><p>Проблемный вариант: провайдер читает localStorage прямо при рендере.</p><p>Исправление: серверные флаги передаются в Client Component, а локальные оверрайды применяются после гидратации.</p><p><b>Принцип:</b> серверный и первый клиентский рендер должны получить одинаковый результат. Браузерные оверрайды включаются в useEffect после монтирования.</p><h3>Дата, время и локаль</h3><p>Сервер часто работает в UTC, а пользователь — в своей зоне. Date.toLocaleString(), Intl.DateTimeFormat и функции вроде formatDistanceToNow() дают разные строки в зависимости от часового пояса и времени между рендером и гидратацией.</p><p>Проблемный вариант: относительное время считается на сервере.</p><p>Исправление: сервер отдаёт стабильную абсолютную дату, клиент заменяет её на относительную после монтирования.</p><p>suppressHydrationWarning здесь уместен, потому что расхождение ожидаемо, ограничено листовым элементом  и управляется явно. Но оборачивать им большой контейнер, чтобы скрыть неизвестную ошибку, — значит замазать баг, а не починить его.</p><h3>Состояние авторизации</h3><p>Типичный сценарий: сервер рендерит UI для неавторизованного пользователя, потому что маршрут статический или не читает куки, а клиент сразу видит залогиненного пользователя. При каждой загрузке страница перерендеривается.</p><p>Решение — читать куки на сервере через cookies() из next/headers.</p><p>С cookies() маршрут становится динамическим — это обычно правильный компромисс для UI, зависящего от авторизации. Начиная с Next.js 15, cookies() асинхронный и требует await. В Next.js 16 синхронный доступ к request-time API полностью уходит.</p><h3>Невалидный HTML</h3><p>Браузер молча чинит невалидную вёрстку. React же гидратирует не исходную строку, а DOM, который построил браузер. Классический пример —  внутри <p></p>: браузер закроет параграф до div, и React увидит другое дерево.</p><p>Браузер превратит это в примерно такую структуру:</p><p>Если HTML приходит из CMS или редактора, валидируйте и нормализуйте его на сервере. Для собственных компонентов следите за предупреждениями validateDOMNesting в DevTools.</p><h3>Расширения браузера и middleware</h3><p>Менеджеры паролей, переводчики, грамматические плагины и другие расширения могут вставлять или переупорядочивать узлы до гидратации. Edge middleware и CDN-трансформации тоже могут переписывать HTML в пути.</p><p>Если несовпадение затрагивает только &lt;html&gt; или &lt;body&gt;, сначала подозревайте расширения. React 19 стал терпимее к инъекциям в head/body, но на старых версиях такие ошибки особенно шумные.</p><p>suppressHydrationWarning на корневых элементах — документированный escape hatch, но он работает только на один уровень вглубь и не должен использоваться для сокрытия неизвестных расхождений в продуктовом UI.</p><h3>CSS-in-JS и порядок классов</h3><p>В проектах со styled-components или Emotion имена классов могут зависеть от порядка рендера. Стриминг и Suspense меняют этот порядок, поэтому нужен registry с useServerInsertedHTML.</p><h2>Production workflow для отладки</h2><p>Не начинайте с diff-а огромных HTML-документов. Работайте по порядку, сужая область поиска.</p><ol><li>Настройте клиентскую телеметрию: перехватывайте console.error и отправляйте hydration-ошибки на свой endpoint.</li><li>Воспроизводите баг на production-сборке: next build &amp;&amp; next start, а не next dev.</li><li>Используйте Suspense-границы, чтобы изолировать проблемный участок и понять, в каком поддереве ошибка.</li><li>Сравнивайте серверный HTML (curl) и клиентский DOM после гидратации.</li><li>Когда найдёте расходящийся элемент, проверьте: browser-only API, дата/время, авторизацию, HTML-вложенность, расширения, стили.</li></ol><h3>Инструментация: instrumentation-client.ts</h3><p>Файл instrumentation-client.ts в Next.js запускается после загрузки документа, но до гидратации React. Это удобная точка для лёгкой клиентской телеметрии.</p><p>Если используете LogRocket, Sentry или другой инструмент, прикрепите тот же payload к текущей сессии — тогда можно будет увидеть, как выглядела страница в момент сбоя.</p><h3>Изоляция через Suspense</h3><p>Suspense-границы не только показывают fallback при загрузке. Если hydration mismatch случается внутри границы, React может ограничить восстановление этим поддеревом, а не переключать весь root на клиентский рендер.</p><p>Оберните поочерёдно основные секции. Если страничная ошибка исчезает после оборачивания конкретной секции, баг почти наверняка внутри неё.</p><h3>Сравнение HTML и DOM</h3><p>Получите серверный HTML через curl с нужными куками:</p><p>В Chrome DevTools после загрузки страницы скопируйте живой DOM:</p><p>Сохраните результат в /tmp/client-render.html и сравните:</p><p>Этот метод хорошо ловит HTML-слой, но может пропустить расхождения на уровне reconciler-а и RSC payload. Если raw HTML совпадает, проверяйте Client Components и браузерное состояние.</p><h2>Профилактика</h2><p>Лучше не допускать ошибки, чем потом их чинить. Несколько практик, которые помогают держать серверный и клиентский рендер синхронизированными.</p><ol><li>Server Component должен быть детерминированным: одни и те же входные данные дают одни и те же выходные HTML и RSC payload.</li><li>Все browser-only API, куки, заголовки, локаль и время должны оставаться за границей 'use client' или читаться через request-time API на сервере.</li><li>Для клиентского UI сначала рендерите стабильный baseline, а улучшения добавляйте в useEffect после гидратации.</li><li>Валидируйте HTML из внешних источников до того, как React его увидит.</li><li>Тестируйте hydration на production-сборке в CI.</li></ol><h3>Пример: стабильный baseline + клиентское улучшение</h3><p>Скелетон — это стабильная базовая разметка. Карточки товаров появляются после монтирования. Сервер и первый клиентский рендер совпадают, а пользователь получает нужный контент чуть позже.</p><h3>Smoke-тесты в CI</h3><p>Ручное тестирование пропустит регрессии. Добавьте Playwright-тест на критичные маршруты.</p><p>Запускайте такой тест только против production-сборки, никогда против next dev. Сделайте его обязательной проверкой для маршрутов, где hydration failure критичен: продуктовые страницы, дашборды, чекаут, личный кабинет.</p><h2>FAQ</h2><h2>Выводы</h2><p>Hydration mismatch — не придирка React, а реальный баг производительности и корректности. Каждое несовпадение означает, что приложение могло отбросить серверный HTML, за который уже заплатило ресурсами.</p><p>В приложениях с React Server Components, где цель — меньше клиентского JavaScript и более ранний стриминг полезного UI, hydration failures тихо отменяют эти преимущества. Поэтому важно держать браузерную логику за границей 'use client', рендерить стабильные серверные baseline и проверять гидратацию в production-условиях до того, как ошибку найдут пользователи.</p><blockquote>Hydration errors should be fixed, not ignored — официальная позиция React.</blockquote><p><b>Источник:</b> <a href="https://blog.logrocket.com/how-fix-rsc-hydration-mismatches-next-js/" rel="noopener noreferrer">LogRocket Blog — How to fix RSC hydration mismatches in Next.js</a>.</p><p>Проверьте свои критичные маршруты на production-сборке, настройте телеметрию и не давайте hydration-ошибкам копиться в консоли.</p>]]></content:encoded>
    </item>
    <item>
      <title>WP2Shell: хакеры атакуют критические уязвимости WordPress</title>
      <link>https://tproger.ru/news/wp2shell-hakery-atakuyut-kriticheskie-uyazvimosti-wordpress</link>
      <comments>https://tproger.ru/news/wp2shell-hakery-atakuyut-kriticheskie-uyazvimosti-wordpress?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/wp2shell-hakery-atakuyut-kriticheskie-uyazvimosti-wordpress</guid>
      <description><![CDATA[<p>WordPress выпустил экстренные патчи 6.9.5 и 7.0.2 для цепочки WP2Shell. Уязвимости позволяют получить контроль над сайтом без авторизации. Проверьте версию CMS.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/wp2shell-hakery-atakuyut-kriticheskie-uyazvimosti-wordpress">WP2Shell: хакеры атакуют критические уязвимости WordPress</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[WordPress]]></category>
      <category><![CDATA[Хакеры]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[CMS]]></category>
      <category><![CDATA[Кибербезопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 21 Jul 2026 08:38:27 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если ваш сайт работает на WordPress 6.9.x или 7.0.x — проверьте версию прямо сейчас. 17 июля 2026 года WordPress выпустил экстренные обновления 6.9.5, 7.0.2 и 6.8.6, закрывающие критическую цепочку уязвимостей WP2Shell. Уже через несколько дней после релиза патчей компании Patchstack, Hexastrike и WatchTowr зафиксировали реальные атаки: злоумышленники получают полный контроль над сайтами без учётной записи и без установленных плагинов.</p><p>WP2Shell — цепочка CVE-2026-63030 и CVE-2026-60137 в ядре WordPress.</p><p>Под угрозой полного удалённого выполнения кода: WordPress 6.9.0–6.9.4 и 7.0.0–7.0.1.</p><p>Атака работает без авторизации на стоковой установке без плагинов и тем.</p><p>WordPress.org применил редкую меру — принудительные автообновления для уязвимых версий.</p><p>Решение: обновиться до 6.9.5, 7.0.2 или 6.8.6 и проверить журналы доступа.</p><h2>Что такое WP2Shell</h2><p>WP2Shell — это комбинация двух багов в ядре WordPress, а не в стороннем плагине или теме. CVE-2026-63030 связана с путаницей маршрутов в пакетном endpoint REST API /wp-json/batch/v1. CVE-2026-60137 — SQL-инъекция в параметре author__not_in компонента WP_Query. По отдельности они серьёзны, вместе дают удалённое выполнение кода от анонимного пользователя.</p><h2>Какие версии под угрозой</h2><p>Полная цепочка RCE работает на WordPress 6.9.0–6.9.4 и 7.0.0–7.0.1. SQL-инъекция CVE-2026-60137 также присутствует в ветке 6.8.0–6.8.5, но там она не превращается в удалённый шелл, поскольку REST API batch endpoint появился только в 6.9. Исправления — версии 6.9.5, 7.0.2 и 6.8.6.</p><h2>Масштаб угрозы</h2><p>По официальной статистике WordPress, уязвимые версии установлены на более чем 400 миллионах сайтов. Исследователь Дэниэл Кард проанализировал выборку около 3500 площадок и оценил долю уязвимых экземпляров менее чем в 15%. Даже при такой оценке речь идёт о десятках миллионах потенциальных жертв.</p><h2>Что делать</h2><ol><li>Проверить версию WordPress в админ-панели или через WP-CLI.</li><li>Обновиться до 6.9.5, 7.0.2 или 6.8.6 в зависимости от текущей ветки.</li><li>Убедиться, что принудительное автообновление действительно применилось.</li><li>Проверить журналы доступа на обращения к /wp-json/batch/v1.</li><li>Если обновление невозможно срочно — временно заблокировать endpoint /wp-json/batch/v1 на WAF.</li></ol><h2>Выводы</h2><blockquote>Атака не требует предварительных условий и может быть использована анонимным пользователем на стоковой установке WordPress без плагинов.</blockquote><p>WP2Shell — редкий случай, когда уязвимость затрагивает ядро CMS, а не стороннее расширение. WordPress.org пошёл на нехарактерный шаг — принудительную доставку патчей, — что говорит о серьёзности угрозы. Если вы администратор сайта на WordPress, обновление до актуальных версий — приоритетная задача.</p><p>Источник: <a href="https://tech.slashdot.org/story/26/07/20/234246/hackers-are-exploiting-recently-patched-wordpress-bugs-putting-millions-of-websites-at-risk">Slashdot</a> (цитирует TechCrunch).</p>]]></content:encoded>
    </item>
    <item>
      <title>«Почему стоит перестать деструктурировать всё в JavaScript»</title>
      <link>https://tproger.ru/articles/pochemu-ya-perestal-destrukturirovat-vsyo-v-javascript</link>
      <comments>https://tproger.ru/articles/pochemu-ya-perestal-destrukturirovat-vsyo-v-javascript?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pochemu-ya-perestal-destrukturirovat-vsyo-v-javascript</guid>
      <description><![CDATA[<p>Разбираем, когда деструктуризация объектов в JS и React упрощает код, а когда делает его труднее для чтения. Практические правила от Мэтта Смита.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pochemu-ya-perestal-destrukturirovat-vsyo-v-javascript">«Почему стоит перестать деструктурировать всё в JavaScript»</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 20 Jul 2026 05:40:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы пишете на JavaScript, скорее всего, деструктуризация — один из первых паттернов, который вы используете каждый день. Но что, если автоматическая деструктуризация делает код не короче, а труднее для чтения?</p><p>В своей статье разработчик Мэтт Смит объясняет, почему перестал раскладывать объекты на переменные по умолчанию и как это изменило его подход к читаемости кода.</p><p><b>Деструктуризация — инструмент, а не норма.</b> Её стоит применять там, где она правда упрощает код, а не просто экономит символы.</p><p><b>Объект хранит контекст.</b> project.status понятнее, чем голая переменная status, особенно в больших функциях.</p><p><b>Вложенные объекты раскрывайте поэтапно.</b> Сначала доберитесь до нужного уровня, а потом уже извлекайте поля.</p><p><b>Деструктурируйте позже, а не раньше.</b> Сохраняйте исходный объект до тех пор, пока он действительно не понадобится в разобранном виде.</p><p><b>Каждая новая переменная — когнитивная цена.</b> Если имя не добавляет смысла, лучше обратиться к свойству объекта напрямую.</p><h2>Деструктуризация — не религия</h2><p>Несколько лет назад Мэтт Смит деструктурировал почти всё: объекты, пропсы, параметры, возвращаемые значения. Если встречался объект — он его раскладывал. Это перестало быть осознанным решением и превратилось в привычку: так пишет «современный JavaScript».</p><p>Сейчас он всё ещё использует деструктуризацию, но уже не автоматически. Причина простая: возвращаясь к старому коду, Смит тратит больше времени, чем ожидает, чтобы понять, откуда взялась та или иная переменная. Ему приходится мысленно собирать исходный объект обратно, прежде чем разобраться, что происходит.</p><p>В какой-то момент до него дошло: он оптимизировал процесс написания, а не чтения. Экономия нескольких нажатий клавиш сегодня оборачивалась дополнительными минутами разбора завтра.</p><h2>Не бойтесь повторов</h2><p>Один из самых распространённых паттернов — вынесть поля из объекта, а потом передать их как пропсы в компонент:</p><p>С этим ничего не случилось. Но сегодня автор с большей вероятностью напишет так:</p><p>Да, здесь повторяется post. Но когда он вернётся к этому коду через месяц, ему не придётся вспоминать, откуда взялись title или author. Контекст остаётся на виду.</p><h2>Объект несёт контекст</h2><p>Это особенно заметно в длинных функциях. Представьте, что в начале файла вы написали:</p><p>А сто строк ниже встретили такой код:</p><p>Моментальная пауза: «archived»… что именно? Сравните с вариантом, где объект сохраняет свою форму:</p><p>Объект по-прежнему несёт полезный контекст. Лишние символы редко замедляют чтение. А вот необходимость помнить, к какой сущности относится переменная, замедляет гораздо сильнее.</p><h2>Вложенность лучше раскрывать поэтапно</h2><p>Раньше автор считал вложенную деструктуризацию элегантной. Сейчас она часто кажется попыткой понять всю структуру объекта ещё до того, как начал решать задачу.</p><p>Автор предпочитает писать иначе:</p><p>Так лучше отражается мышление о данных: сначала интересует профиль, а уже потом, если нужно, из него извлекают конкретные поля.</p><h2>Деструктурируйте позже, а не раньше</h2><p>С параметрами компонентов ситуация похожа. Для маленьких компонентов деструктуризация пропсов отлично работает:</p><p>Но по мере роста компонента автор чаще пишет так:</p><p>Ему нравится держать исходный объект под рукой до тех пор, пока он действительно не понадобится в разобранном виде. Это также упрощает понимание того, что получил компонент.</p><h2>Каждая переменная — цена для читателя</h2><p><b>Каждая локальная переменная просит читателя запомнить ещё одно имя.</b> Иногда это стоит того, иногда — нет.</p><p>Если новая переменная обозначает осмысленную концепцию, автор с удовольствием её вводит. Имя вроде billingAddress становится частью словаря функции.</p><p>Но если автор просто превращает project.status в status, уверенности, что код стал читабельнее, нет. Полезное правило большого пальца: если деструктуризация даёт коду лучший словарь — использует её. Если она только экономит несколько символов — обычно нет.</p><h2>Когда деструктуризация всё ещё уместна</h2><p>Всё вышесказанное — не аргумент против деструктуризации. Автор по-прежнему применяет её постоянно.</p><p>Эти случаи локальны, сфокусированы и убирают шум. Есть и другие исключения. При маппинге массива я спокойно пишу:</p><p>Объект существует всего несколько строк, поэтому автор не чувствует, что теряет контекст. Иногда имеет смысл даже переименовать извлечённое свойство: const { status: projectStatus } = project;.</p><p>Такое имя сохраняет больше контекста, чем просто status. Но если автор всё равно несёт имя объекта в переменную, часто оказывается, что project.status читается естественнее. Не нужно придумывать новое имя, а связь с объектом остаётся очевидной.</p><p>Разница в том, что автор больше не деструктурирует просто потому, что объект существует.</p><h2>Главный вопрос</h2><p>Автор всё ещё любит деструктуризацию. Есть множество мест, где она заметно очищает код. Просто он больше не хватается за неё автоматически.</p><p>Перед тем как убрать объект, он спрашивает себя: удаление объекта действительно облегчает понимание или просто делает код короче?</p><blockquote>Если деструктуризация даёт коду лучший словарь — автор её использует. Если она только экономит несколько символов — обычно нет.</blockquote><h2>Выводы</h2><p>Деструктуризация остаётся одним из самых полезных синтаксических улучшений JavaScript. Но удобство записи не должно превращаться в удобство только для автора. Читаемость кода измеряется не количеством символов, а скоростью, с которой человек понимает, что происходит.</p><p>Сохраняйте объекты там, где они несут контекст. Раскрывайте вложенность поэтапно. Вводите переменные, только если они добавляют смысла. И не забывайте главный вопрос: вы делаете код понятнее или просто короче?</p><p><b>Источник:</b> <a href="https://allthingssmitty.com/2026/07/13/i-stopped-destructuring-everything/">Matt Smith — I stopped destructuring everything</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Как выбрать VPS/VDS под свой проект: гайд по параметрам и 6 провайдеров</title>
      <link>https://tproger.ru/digest/kak-vybrat-vps-vds-pod-svoj-proekt-gajd-po-parametram</link>
      <comments>https://tproger.ru/digest/kak-vybrat-vps-vds-pod-svoj-proekt-gajd-po-parametram?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/digest/kak-vybrat-vps-vds-pod-svoj-proekt-gajd-po-parametram</guid>
      <description><![CDATA[<p>Разбираем, как подобрать VPS/VDS под проект по CPU, RAM, дискам и трафику. Сравнили Макхост, UFO.Hosting, SmartApe, PSB Hosting, FirstVDS и Hetzner Cloud.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/digest/kak-vybrat-vps-vds-pod-svoj-proekt-gajd-po-parametram">Как выбрать VPS/VDS под свой проект: гайд по параметрам и 6 провайдеров</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Облачные технологии]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[VPS]]></category>
      <category><![CDATA[Подборки]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 30 Jun 2026 09:26:50 GMT</pubDate>
      <content:encoded><![CDATA[<p>Выбирать VPS или VDS стоит не по цене за гигабайт диска, а по сочетанию CPU, RAM, типа накопителя и трафика под конкретный проект. В подборке — шесть провайдеров с разными акцентами: бюджетный старт, российские документы, зарубежные локации, гибкие ресурсы и облачная инфраструктура.</p><p><b>Макхост</b> — низкий порог входа и российские документы.</p><p><b>UFO.Hosting</b> — широкая линейка VPS и выделенных серверов.</p><p><b>SmartApe</b> — гибкие конфигурации и быстрый старт.</p><p><b>PSB Hosting</b> — зарубежные локации и безлимитный трафик.</p><p><b>FirstVDS</b> — бюджетный массовый вариант для простых проектов.</p><p><b>Hetzner Cloud</b> — иностранная облачная альтернатива с ограничениями для РФ.</p><h2>Как мы выбирали</h2><p>В подборку вошли провайдеры, которые подтвердили ключевые параметры в брифах и предоставили актуальную информацию о тарифах, инфраструктуре и поддержке. Мы ориентировались на прозрачность конфигураций, наличие российских локаций или документов для юрлиц, а также на реальные сценарии использования — от лендинга и телеграм-бота до 1С и высоконагруженных баз данных.</p><h2>1. Макхост — низкий порог входа</h2><p>Макхост — российский хостинг-провайдер с собственными панелями управления и низким стартовым тарифом. Входит в реестр хостинг-провайдеров, работает с юрлицами и предлагает VPS в России и Европе.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Сайты-визитки и лендинги на минимальной конфигурации с 1 CPU и 1 GB RAM.</li><li>Интернет-магазины на популярных CMS и телеграм-боты: по данным провайдера, часто выбирают KVM-2 с 2 GB RAM.</li><li>1С:Предприятие и корпоративные сайты с модулем синхронизации: рекомендуют конфигурации от 4 GB RAM.</li><li>VPN-серверы личного использования и небольшие тестовые окружения.</li></ul><h3>Что можно развернуть</h3><ul><li>Операционные системы: Ubuntu, Debian, AlmaLinux, CentOS Stream.</li><li>Панели управления: ISPmanager, FastPanel; на тарифах VPS первый месяц ISPmanager 6 в подарок.</li><li>Готовые образы и стеки: WordPress, 1С, Docker, LAMP, почта, DNS, SSL.</li><li>SSH и root-доступ для произвольной настройки окружения.</li></ul><h3>Инфраструктура и экосистема</h3><ul><li>Виртуализация KVM с гарантированными ресурсами.</li><li>Дата-центры: DataPro в Москве и площадка в Амстердаме.</li><li>Диски: NVMe и DDR4 на всех VPS-тарифах, кроме самого дешёвого KVM-NEW с SSD.</li><li>Сеть: порт до 1 Гбит/с, безлимитный трафик на всех тарифах, кроме KVM-NEW (2 ТБ).</li><li>Соответствие 152-ФЗ, реестр хостинг-провайдеров; закрывающие документы для юрлиц.</li></ul><h3>Отзывы и репутация</h3><p>На странице VPS у Макхоста указана средняя оценка 5 на основе 13 оценок. Пользователи отмечают круглосуточную поддержку и быструю помощь в сложных ситуациях; провайдер позиционирует себя как лидер авторитетных рейтингов.</p><h3>Поддержка и каналы связи</h3><ul><li>Каналы: тикет-система и онлайн-чат на сайте.</li><li>Среднее время первого ответа: 10–20 минут.</li><li>Для корпоративных клиентов и крупных проектов возможен персональный менеджер.</li><li>База знаний, блог со статьями и платное администрирование VPS при необходимости.</li></ul><h3>Тарифы, ограничения и условия</h3><ul><li>Стартовый KVM-NEW: 1 CPU, 0.6 GB RAM, 5 GB SSD, 2 ТБ трафика — 143 ₽/мес.</li><li>Популярный KVM-2: 1 CPU, 2 GB RAM, 30–60 GB NVMe — от 693 ₽/мес при оплате за год.</li><li>Топовый VPS KVM-12: 6 CPU, 12 GB RAM, 180–360 GB NVMe — от 3465 ₽/мес при оплате за год.</li><li>Скидки за предоплату: 3%, 6%, 12%, 24% за 3, 6, 12, 24 месяца соответственно.</li><li>Тестовый период: 3 дня с активационным платежом 290 ₽, который остаётся на балансе.</li><li>Апгрейд без пересоздания сервера, обычно с кратковременной перезагрузкой.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/3db7d571-bf7d-42d2-b2fb-bd0cd9e35169.webp" alt="Тарифная сетка VPS Макхост" /><figcaption>Тарифная сетка VPS Макхост</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/21161d7e-7ce2-4ea0-91c6-c0a9f9f9a919.webp" alt="Панель управления Макхост" /><figcaption>Панель управления Макхост</figcaption></figure><p>Официальный сайт: <a href="https://mchost.ru/services/linux-vps/?utm_source=tproger&amp;utm_medium=article&amp;utm_campaign=kak_vybrat_vps_vds">Макхост</a></p><h2>2. UFO.Hosting — широкая линейка</h2><p>UFO.Hosting предлагает виртуальные и выделенные серверы в России с акцентом на широкую линейку конфигураций и NVMe-диски. Подходит тем, кто рассматривает и VPS, и bare-metal в одном кабинете.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Небольшие проекты и сайты-визитки на тарифе Naos с 1 CPU и 1 GB RAM.</li><li>Интернет-магазины, корпоративные сайты и телеграм-боты с вебхуками на Brachium с 2 CPU и 4 GB RAM.</li><li>1С:Предприятие и нагруженные CMS: рекомендуют от 4 CPU и 8 GB RAM.</li><li>Проекты, которым нужны выделенные серверы без соседей.</li></ul><h3>Что можно развернуть</h3><ul><li>Операционные системы: различные дистрибутивы Linux и Windows (ISO-образы доступны на старших тарифах).</li><li>Панели управления: ISPmanager, Vesta, Hestia, Cyberpanel, Virtualmin.</li><li>Готовые шаблоны ПО в зависимости от выбранной ОС.</li><li>Дополнительные IP-адреса, аренда подсетей, настройка BGP.</li></ul><h3>Инфраструктура и экосистема</h3><ul><li>Виртуализация KVM; процессоры Intel Xeon E5-2697A v4.</li><li>Дата-центр IXcellerate в Москве, сертифицированный Tier III+.</li><li>NVMe-диски в RAID10 на VPS/VDS; Enterprise SSD на выделенных серверах.</li><li>Сеть: порт до 10 Гбит/с на ноде, 32 ТБ трафика в месяц на VPS (далее ограничение 100 Мбит/с); на выделенных серверах — без ограничений.</li><li>Работа по 152-ФЗ, реестр хостинг-провайдеров; документы для юрлиц через ЭДО.</li></ul><h3>Отзывы и репутация</h3><p>Публичные отзывы и агрегированные рейтинги в предоставленных материалах не указаны. Провайдер акцентирует внимание на Tier III+ инфраструктуре и запуске серверов до 15 минут.</p><h3>Поддержка и каналы связи</h3><ul><li>Каналы: онлайн-чат на сайте и тикет-система в биллинге 24/7; телефон в будни с 9:00 до 18:00.</li><li>Среднее время первого ответа: не более 30 минут в любое время суток.</li><li>База знаний в блоге ufo.hosting/blog.</li><li>Продажи и поддержка готовы консультировать B2B-клиентов.</li></ul><h3>Тарифы, ограничения и условия</h3><ul><li>Минимальный VPS Naos: 1 vCPU, 1 GB RAM, 25 GB NVMe — 605.85 ₽/мес.</li><li>Популярный Brachium: 2 vCPU, 4 GB RAM, 60 GB NVMe — 1025.85 ₽/мес.</li><li>Топовый VPS Intercrus: 32 vCPU, 64 GB RAM, 510 GB NVMe — 16 800 ₽/мес.</li><li>Выделенный сервер Восток-1: 2x E5-2697v4, 384 GB RAM ECC, 4x960 GB Enterprise SSD — 43 050 ₽/мес.</li><li>Скидки за предоплату: 5%, 10%, 15% за 3, 6, 12 месяцев.</li><li>Тестовый период: 3 дня на VPS после полной верификации аккаунта; на выделенных серверах — обсуждается персонально.</li><li>Апгрейд тарифа из личного кабинета без пересоздания сервера, вступает в силу после перезагрузки.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/cca3508e-09e1-432d-89e7-57efb6843a61.webp" alt="Тарифы виртуальных серверов UFO.Hosting" /><figcaption>Тарифы виртуальных серверов UFO.Hosting</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/29c559f2-0a56-4b7c-a5b1-79cd16c7347f.webp" alt="Тарифы VPS/VDS Hi-CPU UFO.Hosting" /><figcaption>Тарифы VPS/VDS Hi-CPU UFO.Hosting</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/851bd0b3-9ee8-43b5-91ff-9341f54ccf29.webp" alt="Выделенные серверы UFO.Hosting" /><figcaption>Выделенные серверы UFO.Hosting</figcaption></figure><p>Официальный сайт: <a href="https://ufo.hosting/?from=1982260">UFO.Hosting</a></p><h2>3. SmartApe — гибкие конфигурации</h2><p>SmartApe делает ставку на гибкость: кроме фиксированных линеек есть полностью конфигурируемые тарифы, где можно менять ресурсы под задачу. Провайдер использует процессоры Intel Xeon Platinum, AMD EPYC и AMD Ryzen.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Лендинги и сайты-визитки на минимальных конфигурациях с 2 CPU и 1 GB RAM.</li><li>WordPress, корпоративные сайты и интернет-магазины до 10 тыс. посетителей в сутки.</li><li>Bitrix, CRM, ERP и 1С: рекомендуют от 4 CPU и 8 GB RAM.</li><li>Нагруженные API, базы данных и высоконагруженные проекты на конфигурируемых тарифах.</li></ul><h3>Что можно развернуть</h3><ul><li>Linux- и Windows-серверы, панели управления ISPmanager, Hestia и другие.</li><li>Готовые стеки под Docker, базы данных, веб-приложения.</li><li>Автоматическое развёртывание сервера за 1–2 минуты; бесплатная помощь с переносом сайтов при использовании ISPmanager или Hestia.</li></ul><h3>Инфраструктура и экосистема</h3><ul><li>Виртуализация KVM с изоляцией и гарантированными ресурсами.</li><li>Процессоры: Intel Xeon E5-2696 v4, Intel Xeon Platinum, AMD EPYC, AMD Ryzen 9.</li><li>Диски: серверные NVMe SSD или HDD + SSD-кэш, RAID-10.</li><li>Дата-центры: DataPro Moscow I, II, III в России; Host-Telecom в Чехии; Partner Group в Израиле; уровни Tier III и Tier IV.</li><li>Сеть: безлимитный трафик на всех VPS, канал до 200 Мбит/с.</li><li>SLA 99.9%, заявленный фактический uptime 99.982%.</li><li>Соблюдение 152-ФЗ, договор на обработку персональных данных.</li></ul><h3>Отзывы и репутация</h3><p>Публичные отзывы и рейтинги в предоставленных материалах не указаны. Провайдер акцентирует внимание на показателях NVMe-хранилища: до 680 тыс. IOPS на чтение и до 185 тыс. IOPS на запись.</p><h3>Поддержка и каналы связи</h3><ul><li>Каналы: тикеты в личном кабинете, онлайн-чат, телефон.</li><li>Среднее время первого ответа: 10–15 минут.</li><li>Раздел помощи на smartape.ru/help.</li><li>Персональный менеджер обсуждается индивидуально для B2B.</li></ul><h3>Тарифы, ограничения и условия</h3><ul><li>Минимальные тарифы: HDD S1 (2 CPU, 1 GB RAM, 50 GB HDD+SSD) — 345 ₽/мес; NVMe X1 (2 CPU, 1 GB RAM, 10 GB NVMe) — 495 ₽/мес; Turbo R1 AMD Ryzen (2 CPU, 1 GB RAM, 20 GB NVMe) — 645 ₽/мес.</li><li>Топовый VPS NVMe X64: 24 CPU, 64 GB RAM, 640 GB NVMe — 11 870 ₽/мес.</li><li>Скидки за предоплату: 5%, 15%, 30%, 50% за 3, 6, 12, 24 месяца.</li><li>Тестовый период: 10 дней без привязки банковской карты, нужно подтверждение номера телефона.</li><li>Резервное копирование со стороны провайдера не предусмотрено; можно настроить самостоятельно или заказать FTP-хранилище.</li><li>Апгрейд фиксированных тарифов — по запросу в поддержку с перезагрузкой; конфигурируемые тарифы меняются в личном кабинете.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/cb58575b-0b21-4f8e-9192-2467ea34b98c.webp" alt="Список операционных систем и шаблонов SmartApe" /><figcaption>Список операционных систем и шаблонов SmartApe</figcaption></figure><p>Официальный сайт: <a href="https://smartape.ru/">SmartApe</a></p><h2>4. PSB Hosting — зарубежные локации</h2><p>PSB Hosting ориентирован на международные дата-центры и широкий выбор операционных систем. Подходит проектам, которым важны европейские и американские площадки, безлимитный трафик и подсеть IPv6 /64 на всех тарифах.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Сайты и веб-приложения, ориентированные на аудиторию в Европе и США.</li><li>VPN-серверы, прокси и сетевые сервисы благодаря безлимитному трафику и IPv6 /64.</li><li>Проекты на Node.js, Django, Docker, WordPress и других стеках.</li><li>Разработчики, которым нужна нестандартная ОС или загрузка собственного ISO.</li></ul><h3>Что можно развернуть</h3><ul><li>Операционные системы: Ubuntu, Debian, CentOS, Windows, Astra Linux, AlmaLinux, Rocky Linux, FreeBSD, Oracle Linux; можно загрузить свою ОС через ISO.</li><li>Предустановленное ПО: Docker, LAMP, Keitaro, FastPanel, Node.js, Portainer, WordPress, Django, Outline, OpenVPN, Wireguard, HestiaCP, VestaCP, Bitrix.</li><li>Полноценная панель управления DNS-записями доменов.</li></ul><h3>Инфраструктура и экосистема</h3><ul><li>Виртуализация KVM, NVMe-диски.</li><li>Дата-центры: euNetworks в Амстердаме, Frankfurt 1 Data Center в Германии, Digita в Хельсинки, Long Island Interconnect в Нью-Йорке.</li><li>Сеть: порт до 10 Гбит/с, безлимитный трафик, подсеть /64 IPv6 на всех тарифах.</li><li>SLA 99.7%; мониторинг состояния сервера встроен в панель.</li><li>Договор на обработку персональных данных; оплата картами РФ, СНГ, ЕС и криптовалютой.</li></ul><h3>Отзывы и репутация</h3><p>Публичные отзывы и агрегированные рейтинги в предоставленных материалах не указаны. Провайдер позиционирует себя через широкий выбор ОС, безлимитный трафик и неограниченное количество резервных копий.</p><h3>Поддержка и каналы связи</h3><ul><li>Каналы: тикеты и Telegram 24/7.</li><li>Время ответа зависит от загрузки; поддержка работает круглосуточно.</li><li>Документация и API на сайте.</li><li>Персональный менеджер доступен для B2B-клиентов.</li></ul><h3>Тарифы, ограничения и условия</h3><ul><li>Популярная конфигурация: 4 vCPU, 8 GB RAM, 100 GB SSD — $25/мес.</li><li>Скидки за предоплату: 5%, 10%, 15% за 3, 6, 12 месяцев.</li><li>Бесплатного тестового периода нет.</li><li>Резервные копии платные, создаются ежедневно; количество не ограничено.</li><li>Апгрейд без потери данных с перезагрузкой сервера.</li><li>Сервер выделяется за 5–10 минут после установки ОС.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/ecf706ec-fc5e-4552-a4fd-2d7ed2552a56.webp" alt="Список виртуальных машин в панели PSB Hosting" /><figcaption>Список виртуальных машин в панели PSB Hosting</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/42924f0e-4efe-4074-a52f-137c4907797a.webp" alt="Детали виртуальной машины в панели PSB Hosting" /><figcaption>Детали виртуальной машины в панели PSB Hosting</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/44f4ffda-188d-4a54-b51f-ac9fabb45ee7.webp" alt="Выбор операционной системы PSB Hosting" /><figcaption>Выбор операционной системы PSB Hosting</figcaption></figure><p>Официальный сайт: <a href="https://psb.hosting/">PSB Hosting</a></p><h2>5. FirstVDS — бюджетный VPS/VDS для простого старта</h2><p>FirstVDS — российский VPS/VDS-провайдер с готовыми тарифами и быстрым запуском сервера. Он подходит для простых веб-проектов, тестовых окружений и задач, где важны понятная стартовая цена, российские площадки и базовые дополнительные услуги.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Небольшие сайты, pet-проекты, тестовые стенды и простые backend-сервисы.</li><li>Проекты, где важнее низкая цена входа и быстрый запуск, чем детальный подбор ресурсов под нагрузку.</li><li>Сценарии, где можно начать с готового тарифа и позже мигрировать на более производительную линейку.</li></ul><h3>Что можно развернуть</h3><ul><li>Linux/VDS для сайтов, блогов, небольших баз данных и веб-приложений.</li><li>Windows-серверы: на сайте есть отдельная линейка VDS для Windows Server 2019 и 2022.</li><li>Дополнительные услуги: S3, автоматическое резервное копирование, администрирование, DDoS-защита, мониторинг сайтов.</li></ul><h3>Инфраструктура и экосистема</h3><p>На официальной странице FirstVDS указаны серверы в России, Нидерландах и Казахстане, запуск готового сервера за 2 минуты, отдельные линейки VDS Форсаж, CPU.Турбо, VDS Atlant, Storage и GPU. Это вариант для тех, кто хочет выбрать готовую линейку, а не собирать конфигурацию вручную.</p><figure><img src="https://media.tproger.ru/user-uploads/115582/2026-06-30/b5ae6b6a-ee36-4bcf-adfe-f652b858ef34.webp" alt="Тарифы на готовые серверы FirstVDS" /><figcaption>Тарифы на готовые серверы FirstVDS</figcaption></figure><h3>Тарифы и ограничения</h3><ul><li>Стартовая цена на сайте: VPS/VDS от 249 ₽/мес.</li><li>Плюс: круглосуточный бесплатный телефон 8 800 775-38-37 и большое количество отзывов на сайте.</li><li>Особенность: параметры под конкретный сценарий лучше дополнительно проверять в конфигураторе и на тестовой конфигурации.</li></ul><p>Официальный сайт: <a href="https://firstvds.ru/">FirstVDS</a></p><h2>6. Hetzner Cloud — зарубежное облако для международных проектов</h2><p>Hetzner Cloud — европейский облачный провайдер с API и дата-центрами в Германии, Финляндии, США и Сингапуре. Он подходит для международных проектов, тестовых окружений и команд, которым важны автоматизация, сети, firewalls и понятная облачная модель. Для российских юридических и регуляторных требований условия нужно проверять отдельно.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Тестовые окружения, личные проекты, международные веб-сервисы и инфраструктура для разработчиков.</li><li>Команды, которым нужны API, CLI, Terraform/Ansible-интеграции, private networks и firewalls.</li><li>Проекты с аудиторией в Европе, США или Азии, где российская юрисдикция и документы не критичны.</li></ul><h3>Что можно развернуть</h3><ul><li>Linux-дистрибутивы: Ubuntu, Debian, Fedora и другие образы.</li><li>One-click apps: Docker, WordPress, Nextcloud, GitLab, Grafana, Jitsi Meet, WireGuard и другие.</li><li>Облачная инфраструктура с networks, firewalls, load balancers, API, CLI и интеграциями для CI/CD.</li></ul><h3>Инфраструктура и экосистема</h3><p>Hetzner описывает shared cloud как вариант для разработки, тестов, личных сайтов, небольших баз данных и веб-серверов со средней нагрузкой. Dedicated cloud рассчитан на бизнес-приложения и устойчивую высокую нагрузку. На сайте также указаны GDPR, ISO/IEC 27001 для дата-центров в Германии и Финляндии, 99,9% uptime и поддержка 24/7 по email.</p><figure><img src="https://media.tproger.ru/user-uploads/115582/2026-06-30/00f6e9b6-01aa-4620-acfd-883382765ea4.webp" alt="Тарифы на серверы Hetzner Cloud" /><figcaption>Тарифы на серверы Hetzner Cloud</figcaption></figure><h3>Тарифы и ограничения</h3><ul><li>Цены и конфигурации зависят от выбранной страны, валюты и типа cloud-сервера; в статье лучше считать их отдельно в калькуляторе Hetzner.</li><li>Плюс: зрелая европейская облачная экосистема и сильная автоматизация.</li><li>Особенность: иностранная юрисдикция и документы отличаются от российских провайдеров, поэтому для проектов с персональными данными и 152-ФЗ условия нужно проверять отдельно.</li></ul><p>Официальный сайт: <a href="https://www.hetzner.com/cloud/">Hetzner Cloud</a></p><h2>Сравнение по ключевым критериям</h2><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-30/8c6a63a1-9829-440f-bdd3-d97af4ab404a.webp" alt="Сравнительная таблица шести VPS и VDS провайдеров по цене, конфигурациям, дискам, трафику, тестовому периоду и географии" /><figcaption>Сравнительная таблица шести VPS/VDS-провайдеров из подборки.</figcaption></figure><p>Минимальный вход: у Макхоста самый дешёвый стартовый тариф — 143 ₽/мес, но с ограниченным трафиком и SSD. SmartApe предлагает старт от 345 ₽/мес с двумя ядрами и HDD+SSD-кэшем; FirstVDS начинается от 249 ₽/мес и подходит как бюджетная точка входа. UFO.Hosting, PSB Hosting и Hetzner Cloud стоит считать по конфигурации и требованиям к географии.</p><p>Популярные конфигурации: Макхост и UFO.Hosting выделяют тарифы с 2 GB RAM для магазинов и CMS; у SmartApe стартовый NVMe-тариф даёт 2 CPU и 1 GB RAM; у PSB Hosting популярный тариф — 4 CPU и 8 GB RAM за $25/мес. FirstVDS удобен для простых стартовых задач, а Hetzner Cloud — для международных проектов и команд, которым нужны API, сети и автоматизация.</p><p>Диски и трафик: у каждого провайдера разные акценты по дискам, портам, бэкапам и ограничениям. FirstVDS даёт массовую VPS/VDS-линейку и дополнительные сервисы вроде S3, бэкапов и мониторинга. Hetzner Cloud силён по API, сетям, firewalls и included traffic; его условия нужно пересчитывать отдельно под регион и валюту.</p><p>Тестовый период: SmartApe даёт 10 дней без карты, Макхост и UFO.Hosting — 3 дня с условиями, PSB Hosting — не предусмотрен. Для FirstVDS и Hetzner Cloud тестовый период и условия пробного запуска лучше проверять на момент заказа.</p><p>География и документы: Макхост, UFO.Hosting и SmartApe подтверждают работу по 152-ФЗ и наличие российских площадок; PSB Hosting работает только из зарубежных дата-центров и предлагает оплату криптовалютой. FirstVDS имеет российские и зарубежные площадки. Hetzner Cloud работает в иностранной юрисдикции, поэтому для проектов с персональными данными россиян нужно заранее проверить документы, обработку данных и требования 152-ФЗ.</p><h2>Выводы</h2><p>Выбор VPS начинается с честной оценки нагрузки: 1 CPU и 1 GB RAM хватит для статического лендинга или простого бота, но для CMS с плагинами, интернет-магазина или 1С стоит закладывать минимум 2 CPU и 4 GB RAM, а лучше — тестировать реальную нагрузку на выбранной панели.</p><p>Если важен минимальный бюджет и российские документы — смотрите на Макхост. Если нужна широкая линейка от VPS до выделенных серверов в одном кабинете — на UFO.Hosting. Для гибкого подбора ресурсов под растущую нагрузку подойдёт SmartApe. Если проект ориентирован на зарубежную аудиторию и нужен безлимитный трафик — PSB Hosting.</p><p>FirstVDS подойдёт для недорогих и простых запусков с российскими и зарубежными площадками. Hetzner Cloud — для международной инфраструктуры, где важны API, сети и дата-центры за пределами России; юридические и регуляторные требования нужно проверять отдельно.</p><p>Перед покупкой всегда используйте тестовый период или минимальную конфигурацию: реальная скорость диска, отклик панели и качество поддержки часто важнее цифр в прайсе.</p>]]></content:encoded>
    </item>
    <item>
      <title>VPS vs VDS vs виртуальный хостинг: что выбрать в 2026 году</title>
      <link>https://tproger.ru/digest/vps-vs-vds-vs-virtualnyj-hosting-chto-vybrat-v-2026-godu</link>
      <comments>https://tproger.ru/digest/vps-vs-vds-vs-virtualnyj-hosting-chto-vybrat-v-2026-godu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/digest/vps-vs-vds-vs-virtualnyj-hosting-chto-vybrat-v-2026-godu</guid>
      <description><![CDATA[<p>Сравнили VPS, VDS и виртуальный хостинг: чем отличаются, кому что подходит и сколько стоит. Подборка провайдеров с ценами и условиями.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/digest/vps-vs-vds-vs-virtualnyj-hosting-chto-vybrat-v-2026-godu">VPS vs VDS vs виртуальный хостинг: что выбрать в 2026 году</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[VPS]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Подборки]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 30 Jun 2026 04:40:29 GMT</pubDate>
      <content:encoded><![CDATA[<p>Виртуальный хостинг, VPS и VDS часто выбирают по цене, но потом выясняется, что проекту не хватает ресурсов, гибкости или поддержки. Разобрались, чем эти три формата отличаются на практике, и собрали шесть провайдеров с разным подходом: от бюджетного старта до зарубежных локаций.</p><ul><li>Виртуальный хостинг — сайты соседствуют на одном сервере, управляет провайдер. Дешёвый старт, но ограниченная конфигурация.</li><li>VPS и VDS — почти всегда синонимы: изолированные виртуальные серверы с root-доступом и гарантированными ресурсами.</li><li>Выделенный сервер — отдельное железо, максимум контроля и цены, требует администрирования.</li><li>В подборке: Интернет Хостинг Центр, UFO.Hosting, SpaceWeb, PSB Hosting, AdminVPS и FirstVDS.</li></ul><h2>Как мы выбирали участников</h2><p>Отбирали провайдеров, которые явно работают с тремя категориями или хотя бы с двумя и могут показать читателю реальную разницу. Важны были прозрачные цены и лимиты, география дата-центров, скорость и каналы поддержки, тестовые периоды и документы для юрлиц. Факты сверяли по официальным страницам, документации, тарифам и публичным данным провайдеров.</p><h2>1. Интернет Хостинг Центр — гибкие конфигурации</h2><p>Российский провайдер, у которого VPS и VDS — это одна услуга. Можно выбрать виртуализацию под задачу (KVM или Virtuozzo), собрать конфигурацию от минимальной до высоконагруженной и расти внутри одной платформы до выделенного сервера.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Небольшой сайт компании на WordPress с 300–500 посетителей в сутки спокойно живёт на виртуальном хостинге; при росте трафика переходят на VPS.</li><li>Интернет-магазин на 1С-Битрикс с 500–1000 пользователями в день переносят на VPS/VDS, когда подключают CRM и платёжные системы.</li><li>Разработчик с несколькими проектами берёт VPS/VDS под API, базу данных и тестовые окружения — виртуальный хостинг здесь слишком ограничен.</li></ul><h3>Что можно развернуть</h3><p>На виртуальном хостинге — сайты на PHP 5.2–8.2 с MySQL, панели IHC, cPanel или ISPmanager. На VPS/VDS — любые Linux-дистрибутивы, Windows, WireGuard, MikroTik Router, панели ispmanager/FastPanel, VPN-шаблоны, CMS вроде 1С-Битрикс.</p><h3>Инфраструктура и экосистема</h3><p>Дата-центры Tier III в Москве (DataPRO и IXcellerate Moscow One) и в Амстердаме. Виртуализация — KVM или Virtuozzo. Защита от DDoS входит во все тарифы, IPv6-сети /64 доступны за доплату. Есть партнёрская программа с выплатами до 50% от привлечённых оплат.</p><h3>Отзывы и репутация</h3><p>На сайте публикуются отзывы с внешних площадок: средняя оценка 4,8 по 20 оценкам. Клиенты отмечают стабильную работу и скорость техподдержки.</p><h3>Поддержка и каналы связи</h3><p>Тикеты через личный кабинет, онлайн-чат на сайте, Telegram @IHC_Support_Bot, телефоны в Москве, Санкт-Петербурге и бесплатный номер для регионов. Первый ответ обычно приходит за 10–30 минут в рабочее время. Для корпоративных клиентов доступно сопровождение через отдел продаж и аккаунт-менеджеров.</p><h3>Тарифы, ограничения и условия</h3><ul><li>Виртуальный хостинг: тариф IHC-2 — от 123 ₽/мес при оплате за год или 147 ₽/мес помесячно; 2 сайта, 2 ГБ SSD, 150 МБ под БД, домен .RU в подарок при оплате за 2 года.</li><li>VPS/VDS: минимальная конфигурация ssdVPS:1 — 1 ГБ RAM, 20 ГБ SSD, 1 CPU, безлимитный трафик со снижением скорости после 20 ТБ — от 317 ₽/мес за год или 380 ₽/мес помесячно.</li><li>Типовая конфигурация для небольшого проекта — 2 ГБ RAM, 1–2 CPU, 30–45 ГБ NVMe — от 609 ₽/мес за год или 700 ₽/мес помесячно.</li><li>Тестовый период: 7 дней на виртуальном хостинге, 3 дня на VPS/VDS; для активации нужно пополнить баланс на 100 ₽, которые можно вернуть или потратить.</li><li>Бэкапы: место под резервные копии — от 52,5 ₽/мес за 5 ГБ; снапшоты зависят от платформы.</li><li>Работа по 152-ФЗ, есть реестр хостинг-провайдеров; закрывающие документы для юрлиц доступны.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/0af1599e-dc11-44e3-8794-9213246cf720.webp" alt="Тарифы виртуального хостинга ИХЦ" /><figcaption>Тарифы виртуального хостинга Интернет Хостинг Центр.</figcaption></figure><p>Официальный сайт: <a href="https://www.ihc.ru/vps.html?utm_source=tproger&amp;utm_medium=article&amp;utm_campaign=vps_vs_vds_vs_virt_hosting">ihc.ru</a></p><h2>2. UFO.Hosting — космическая экосистема</h2><p>Провайдер, который объединяет VPS/VDS, выделенные серверы, защиту сайтов, DNS-хостинг, аренду IP, лицензии ISPmanager и домены в одном личном кабинете. Для UFO.Hosting VPS и VDS — два названия одной услуги; разница только в терминологии.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Интернет-магазин с трафиком 10–50 тыс. посетителей в день — VPS даёт стабильность при пиковых нагрузках и возможность настроить SSL, СУБД и кэширование.</li><li>Веб-студии и агентства выбирают VPS/VDS ради изоляции ресурсов: проблемы одного клиента не влияют на соседние проекты.</li><li>CRM-системы, лендинги с формами заявок и приложения с умеренной нагрузкой — удобно масштабировать RAM и CPU без переплаты за железо.</li><li>Выделенные серверы берут под крупный e-commerce с интенсивным чтением/записью, проекты с жёсткими требованиями к безопасности и задачи с огромными объёмами дисков.</li></ul><h3>Что можно развернуть</h3><p>VPS/VDS на Linux и Windows, панели Vesta, Hestia, CyberPanel, Virtualmin, ISPmanager. Можно поднять веб-серверы, базы данных, VPN, контейнеры, игровые серверы, DNS-зоны, а рядом заказать защиту сайта от DDoS L7 и внешнее FTP-хранилище.</p><h3>Инфраструктура и экосистема</h3><p>Серверы стоят в дата-центре IXcellerate в Москве, соответствующем Tier III. Сеть ноды VPS/VDS — 10 Гбит/с, распределяется между серверами по тарифу. Доступны обычные конфигурации на Intel Xeon, Hi-CPU на Ryzen и Storage-линейка с расширенным хранилищем.</p><h3>Отзывы и репутация</h3><p>Публичных агрегированных рейтингов в предоставленных источниках не указано. Провайдер позиционируется как экосистемный игрок с акцентом на удобное управление всеми услугами из одного кабинета.</p><h3>Поддержка и каналы связи</h3><p>Техподдержка 24/7 через онлайн-чат на сайте и тикет-систему в биллинге. Телефонная поддержка работает в будни с 9:00 до 18:00; Telegram не используется. Фактическое время ответа — не более 30 минут в любое время суток. Есть база знаний и блог.</p><h3>Тарифы, ограничения и условия</h3><ul><li>Минимальная конфигурация VPS/VDS Naos (Intel Xeon E5-2697A v4) — 1 vCore, 1 ГБ RAM, 25 ГБ NVMe — 605,85 ₽/мес.</li><li>Типовая конфигурация Brachium (Intel Xeon E5-2697A v4) — 2 vCore, 4 ГБ RAM, 60 ГБ NVMe — 1025,85 ₽/мес.</li><li>Скидки за предоплату: 3 месяца — 5%, 6 месяцев — 10%, 12 месяцев — 15%.</li><li>Тестовый период — до 3 дней на любой тариф VPS; требуется верификация аккаунта (email, телефон, KYC). На выделенные серверы — до 3 дней по договорённости.</li><li>Трафик безлимитный с порогом 32 ТБ/мес; после превышения скорость ограничивается 100 Мбит/с.</li><li>Root-доступ полный. На тарифах Naos и Haedus выбор ОС ограничен списком провайдера; на остальных можно ставить любую ОС.</li><li>Бэкапы платные: ежедневные — 525 ₽/мес, еженедельные — 262,5 ₽/мес; снапшотов нет, есть услуга бэкапов.</li><li>Работа по 152-ФЗ, сертификатов ФСТЭК нет; есть реестр хостинг-провайдеров. Для юрлиц — договор и ЭДО, постоплата недоступна.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/294b50fd-7642-4b85-a416-e7a021dee5ba.webp" alt="Тарифы VPS/VDS UFO.Hosting" /><figcaption>Тарифы VPS/VDS UFO.Hosting в российском дата-центре.</figcaption></figure><p>Официальный сайт: <a href="https://ufo.hosting/?from=1982260">ufo.hosting</a></p><h2>3. SpaceWeb — посуточная тарификация</h2><p>Один из старейших российских хостеров, у которого можно начать с виртуального хостинга, перейти на VPS/VDS с посуточной оплатой и докупать IP, SSL и защиту от DDoS. Удобен тем, кто хочет платить только за фактическое потребление ресурсов VPS.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Лендинг, блог или сайт-визитка с небольшой посещаемостью — хватит виртуального хостинга с автоустановкой CMS.</li><li>Интернет-магазин и корпоративный сайт на 1С-Битрикс — тарифы повышенной мощности с выделенными CPU и приоритетной поддержкой.</li><li>Проект с непредсказуемой нагрузкой — VPS/VDS с посуточной тарификацией и изменением ресурсов «на лету».</li></ul><h3>Что можно развернуть</h3><p>На хостинге — WordPress, Joomla, Drupal, 1С-Битрикс, OpenCart, MODx, Laravel, Django и другие CMS и фреймворки. Поддерживаются PHP 5.x–8.4, MySQL 8/5.7, PostgreSQL 14.4, Perl, Python, Ruby. На VPS/VDS — Ubuntu, Debian, CentOS, AlmaLinux, Rocky Linux, панели Hestia, FASTPANEL, ISPmanager, Docker.</p><h3>Инфраструктура и экосистема</h3><p>Дата-центры Tier III в Санкт-Петербурге, Москве и Амстердаме. Собственная SPA-панель управления, VNC-консоль, DNS-редактор, статистика, логи, бэкапы и снапшоты. На всех сайтах включена изоляция для защиты от вредоносного ПО и защита от DDoS L3-4; защиту L7 можно докупить от 290 ₽/мес.</p><h3>Отзывы и репутация</h3><p>На сайте публикуются отзывы клиентов: отмечают стабильную работу, быструю техподдержку и удобную панель. Некоторые пользователи работают с провайдером с 2016 года.</p><h3>Поддержка и каналы связи</h3><p>Email, телефон, онлайн-чат и ВКонтакте. Среднее время ответа: 1–2 минуты по телефону, в чате и ВКонтакте; до 60 минут по почте. Поддержка помогает с переносом проектов, диагностикой и администрированием серверов с ISPmanager.</p><h3>Тарифы, ограничения и условия</h3><ul><li>Виртуальный хостинг: тариф «Старт» — 1 ГБ NVMe SSD, 1 база данных, ∞ FTP и почтовых ящиков, 120 CP — 149 ₽/мес; «Взлёт» — 311 ₽/мес, «Ракета» — 530 ₽/мес, «Космос» — 755 ₽/мес.</li><li>VPS/VDS: посуточная тарификация, параметры CPU/RAM/диска меняются «на лету»; конкретную стоимость конфигурации проверяйте в калькуляторе на сайте.</li><li>Тестовый период: 14 дней на виртуальном хостинге и на VPS/VDS.</li><li>Ежедневное резервное копирование включено на хостинге; резервные копии VPS — от 45 ₽/мес за 3 копии.</li><li>Дополнительный IP — 130 ₽/мес, SSL GlobalSign — от 1 900 ₽/год, домен .RU — 179 ₽/год.</li><li>Работа с юрлицами через договор оферты, безналичные платежи и ЭДО.</li></ul><p>Официальный сайт: <a href="https://spaceweb.ru/vds/">spaceweb.ru</a></p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/09d49f48-c058-403a-87e9-3e828ef338e2.webp" alt="Тарифы SpaceWeb для хостинга и VPS" /><figcaption>Сводка тарифов и условий SpaceWeb по данным карточки провайдера.</figcaption></figure><h2>4. PSB Hosting — зарубежные локации</h2><p>Провайдер с фокусом на VPS в Европе и США: Amsterdam, Frankfurt, Helsinki, New York. Не предлагает виртуальный хостинг в привычном понимании, зато даёт полный root, /64 IPv6 на всех тарифах, неограниченные резервные копии и оплату криптовалютой.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Небольшие интернет-магазины на WordPress или 1С-Битрикс, лендинги, корпоративные сайты и блоги.</li><li>Проекты с Telegram-ботами, API-сервисами и другой автоматизацией.</li><li>Команды, которым важны зарубежные локации и гибкие способы оплаты, включая криптовалюту.</li></ul><h3>Что можно развернуть</h3><p>VPS под Linux, Windows или FreeBSD с предустановленным ПО: Bitrix, Django, Docker, FastPanel, HestiaCP, Keitaro, LAMP, Node, OpenVPN, Outline, Portainer, VestaCP, WireGuard, WordPress. Подходит под сайты, backend-приложения, VPN, корпоративные системы, базы данных и тестовые среды.</p><h3>Инфраструктура и экосистема</h3><p>Серверы размещены в дата-центрах euNetworks (Amsterdam), Frankfurt 1 Data Center, Digita (Helsinki) и Long Island Interconnect (New York). Оборудование — AMD и Intel с DDR5 и NVMe, RAID 10. Безлимитный трафик, порт ноды 10 Гбит/с, на VPS выделяется 300 Мбит/с. Полноценная панель управления DNS-записями доменов.</p><h3>Отзывы и репутация</h3><p>На сайте указаны рейтинги на независимых площадках: OtzovikMarketing.ru — 4,8, In-Scale.ru — 5,0, Aff1.ru — 5,0, 101Poisk.ru — 4,89. Провайдер позиционируется как решение для бизнеса, разработки и высоконагруженных проектов.</p><h3>Поддержка и каналы связи</h3><p>Поддержка работает круглосуточно через тикеты и Telegram; время ответа зависит от загрузки. Есть документация и API. Для B2B-клиентов предусмотрен менеджер.</p><h3>Тарифы, ограничения и условия</h3><ul><li>VPS: минимальный тариф на странице VPS — от 8 USD; есть High-CPU VPS на AMD Ryzen 7950X.</li><li>Почасовая оплата доступна; скидки за предоплату: 3 месяца — 5%, 6 месяцев — 10%, 12 месяцев — 15%.</li><li>Бесплатного тестового периода нет.</li><li>Безлимитный трафик, порт VPS — 300 Мбит/с; можно установить любую ОС; полный root-доступ.</li><li>Бэкапы платные, снапшоты есть.</li><li>IPv6-подсеть /64 на всех тарифах, неограниченное количество резервных копий.</li><li>Не работает по 152-ФЗ, сертификатов ФСТЭК нет, в реестре отечественного ПО нет. Оплата картами РФ/СНГ/ЕС и криптовалютой.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-22/df620a3c-35c1-452b-a81f-f7ffc156cfbc.webp" alt="Тарифы PSB Hosting для VPS" /><figcaption>Сводка тарифов и условий PSB Hosting по данным карточки провайдера.</figcaption></figure><p>Официальный сайт: <a href="https://psb.hosting/">psb.hosting</a></p><h2>5. AdminVPS — VPS и хостинг в одном кабинете</h2><p>Провайдер с виртуальным хостингом, VPS/VDS, выделенными серверами, доменами, SSL и дополнительными сервисами в одном аккаунте. В подборке он закрывает сценарий, когда проекту нужен обычный хостинг для сайта и отдельный VPS под приложение, базу данных или тестовую среду.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Сайты на CMS и небольшие магазины, которые начинают с виртуального хостинга и постепенно переходят на VPS.</li><li>Команды, которым нужны домены, SSL, хостинг и серверы в одном личном кабинете.</li><li>Проекты, где важна российская площадка и возможность подобрать конфигурацию VPS под нагрузку.</li></ul><h3>Что можно развернуть</h3><p>На виртуальном хостинге — сайты на популярных CMS и почту на домене. На VPS/VDS — Linux-серверы под сайты, backend, базы данных, тестовые окружения и сервисы с root-доступом. В экосистеме также есть домены, SSL-сертификаты, резервное хранилище, объектное хранилище и защита от DDoS.</p><h3>Инфраструктура и экосистема</h3><p>На странице VPS в России указано размещение в Москве, процессоры Intel Xeon Gold и AMD EPYC, NVMe-диски, тарифы с портом от 100 Мбит/с до 1 Гбит/с и включённым месячным трафиком. В меню также есть VPS в Германии, Нидерландах, Польше, Испании, Беларуси, Казахстане, Финляндии, Великобритании и Франции.</p><h3>Отзывы и репутация</h3><p>На странице VPS указана агрегированная оценка 4,9 и несколько сотен отзывов. Провайдер позиционируется как универсальная площадка для сайтов, серверов и сопутствующих услуг.</p><h3>Поддержка и каналы связи</h3><p>Поддержка работает круглосуточно через тикет-систему в личном кабинете. Отдел продаж доступен по телефону и через запрос на сайте.</p><h3>Тарифы, ограничения и условия</h3><ul><li>VPS/VDS в России: конфигуратор стартует от 500 ₽/мес; в готовых тарифах есть Lite с 1 CPU, 1 ГБ RAM и 15 ГБ NVMe.</li><li>Виртуальный хостинг и CMS-хостинг доступны отдельными услугами.</li><li>В тарифах VPS указаны месячные пакеты трафика; на младшем Lite — 1 ТБ и порт 100 Мбит/с.</li><li>Бэкапы зависят от тарифа: для части тарифов платно, для части включены.</li><li>Есть скидки за предоплату на 6, 12 и 24 месяца.</li><li>На странице указано соответствие требованиям РФ по 152-ФЗ.</li></ul><p>Официальный сайт: <a href="https://adminvps.ru/vps/vps_russia.php">adminvps.ru</a></p><h2>6. FirstVDS — готовые VDS/VPS-конфигурации</h2><p>Провайдер с фокусом на виртуальные серверы: готовые VDS/VPS, отдельные линейки для высоких CPU-частот, storage-сценариев, GPU и Windows. В подборке это вариант для тех, кто выбирает именно VPS/VDS и сопутствующие услуги, а не классический shared-хостинг.</p><h3>Кейсы клиентов и кому подойдёт</h3><ul><li>Небольшие сайты и сервисы, которым нужен отдельный сервер вместо виртуального хостинга.</li><li>Разработчики, которым важны готовые Linux-образы, SSH-доступ и быстрый запуск сервера.</li><li>Проекты, где позже могут понадобиться Windows-серверы, storage-линейка или зарубежная локация.</li></ul><h3>Что можно развернуть</h3><p>На VPS/VDS доступны Linux-дистрибутивы Debian, Ubuntu, FreeBSD, CentOS и Alma, платная Windows, панели ispmanager и дополнительные IP. В линейке есть VDS для Windows, VDS в Нидерландах и Алматы, storage-серверы, GPU-серверы и объектное хранилище S3.</p><h3>Инфраструктура и экосистема</h3><p>На сайте указаны дата-центры в России, Нидерландах и Казахстане. Для VDS в Москве доступны каналы до 100 Мбит/с с безлимитным трафиком или до 1 Гбит/с с пакетом 32 ТБ в месяц; для Амстердама и Казахстана условия отличаются.</p><h3>Отзывы и репутация</h3><p>FirstVDS работает как отдельный бренд виртуальных серверов и указывает награды отраслевой премии ЦОДы.рф. На сайте также опубликованы пользовательские отзывы и раздел базы знаний.</p><h3>Поддержка и каналы связи</h3><p>На сайте указан бесплатный круглосуточный телефон 8 800 775-38-37, база знаний и служба поддержки. Для серверов доступны дополнительные услуги администрирования и технического сопровождения.</p><h3>Тарифы, ограничения и условия</h3><ul><li>Готовые VDS/VPS — от 249 ₽/мес; запуск сервера заявлен за несколько минут.</li><li>Бесплатно с сервером: 1 выделенный IP-адрес, ispmanager 6 lite на 1 месяц, установка ОС на выбор и полный SSH-доступ.</li><li>Тестовый период предоставляется по согласованию.</li><li>Windows тарифицируется отдельно: на странице указано 680 ₽/мес за 1 ядро, недоступно для VDS в Амстердаме и Алматы.</li><li>Для VDS в Москве возможен канал до 100 Мбит/с с безлимитным трафиком или до 1 Гбит/с с лимитом 32 ТБ/мес.</li><li>Дополнительные услуги: бэкап, мониторинг, BitNinja, DDoS-защита, домены, SSL и DNS-хостинг.</li></ul><p>Официальный сайт: <a href="https://firstvds.ru/products/vds_vps_hosting">firstvds.ru</a></p><h2>Сравнение по ключевым критериям</h2><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-06-30/6b343a98-7cea-4190-9154-005b10c5cab8.webp" alt="Сравнительная таблица шести провайдеров VPS, VDS и виртуального хостинга" /><figcaption>Сравнительная таблица сервисов из подборки.</figcaption></figure><p>Ниже — сводка по ценам, лимитам и условиям, которые чаще всего влияют на выбор.</p><ul><li>Минимальный виртуальный хостинг: ИХЦ — от 123 ₽/мес (при оплате за год), SpaceWeb — от 149 ₽/мес; AdminVPS предлагает виртуальный/CMS-хостинг отдельной линейкой; UFO.Hosting, PSB Hosting и FirstVDS в подборке рассматриваются прежде всего как VPS/VDS-провайдеры.</li><li>Минимальный VPS/VDS: ИХЦ — от 317 ₽/мес (за год), UFO.Hosting — 605,85 ₽/мес, SpaceWeb — цена в калькуляторе с посуточной тарификацией, PSB Hosting — от 8 USD, AdminVPS — от 500 ₽/мес в конфигураторе, FirstVDS — от 249 ₽/мес.</li><li>Виртуализация: ИХЦ — KVM/Virtuozzo на выбор; UFO.Hosting — Intel Xeon и Ryzen линейки; SpaceWeb — собственная облачная платформа; PSB Hosting — KVM; AdminVPS и FirstVDS предлагают готовые VPS/VDS-линейки с Linux-образами.</li><li>Трафик: ИХЦ и PSB Hosting — безлимитный (у ИХЦ снижение скорости после 20 ТБ); UFO.Hosting — безлимитный с порогом 32 ТБ; SpaceWeb — параметры уточняйте в конфигураторе; AdminVPS указывает месячные пакеты трафика; FirstVDS разделяет безлимитный канал 100 Мбит/с и пакеты трафика на более быстрых каналах.</li><li>Root и ОС: полный root у всех шести; ИХЦ и PSB Hosting позволяют загружать собственные ISO; UFO.Hosting ограничивает список ОС на младших тарифах; у FirstVDS Windows и панели управления идут как платные дополнения.</li><li>Бэкапы: SpaceWeb включает ежедневные бэкапы на хостинге; ИХЦ и PSB Hosting — платно; UFO.Hosting — платная услуга резервного копирования; AdminVPS и FirstVDS предлагают бэкапы как тарифную или дополнительную опцию.</li><li>Тестовый период: SpaceWeb — 14 дней на хостинге и VPS; ИХЦ — 7 дней хостинг / 3 дня VPS; UFO.Hosting — до 3 дней VPS; FirstVDS — по согласованию; PSB Hosting — нет; условия AdminVPS зависят от акции и выбранной услуги.</li><li>Дата-центры: ИХЦ — Москва + Амстердам; UFO.Hosting — Москва; SpaceWeb — Москва, Санкт-Петербург, Амстердам; PSB Hosting — Amsterdam, Frankfurt, Helsinki, New York; AdminVPS предлагает VPS в разных странах; FirstVDS указывает Россию, Нидерланды и Казахстан.</li><li>Юридика: ИХЦ, UFO.Hosting, SpaceWeb и AdminVPS работают с российской юридической рамкой; PSB Hosting ориентирован на зарубежные локации; для FirstVDS условия документов и лицензий зависят от выбранных услуг.</li></ul><h2>Вывод</h2><p>Виртуальный хостинг остаётся самым простым стартом для сайта-визитки, блога или небольшого магазина: не нужно администрировать сервер, всё настроено провайдером. VPS/VDS стоит брать, когда проекту нужна изоляция, root-доступ, нестандартное ПО или рост нагрузки. Выделенный сервер — следующий шаг, когда виртуализация уже не тянет задачу.</p><p>Если приоритет — российская юридика и плавный рост от хостинга до железа, смотрите на <b>Интернет Хостинг Центр</b> или <b>SpaceWeb</b>. Если важна экосистема из доменов, защиты и серверов в одном кабинете — <b>UFO.Hosting</b> или <b>AdminVPS</b>. Если нужен недорогой вход именно в VPS/VDS — можно сравнить <b>FirstVDS</b> с базовыми тарифами других участников. Если нужны зарубежные локации и гибкая оплата — <b>PSB Hosting</b>. Перед покупкой всегда берите тестовый период и проверяйте реальную производительность под вашей нагрузкой.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как сделать 3D-вращение изображений при скролле: разбираем эффект от Codrops</title>
      <link>https://tproger.ru/articles/kak-sdelat-3d-vrashhenie-izobrazhenij-pri-skrolle-razbiraem-effek</link>
      <comments>https://tproger.ru/articles/kak-sdelat-3d-vrashhenie-izobrazhenij-pri-skrolle-razbiraem-effek?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-sdelat-3d-vrashhenie-izobrazhenij-pri-skrolle-razbiraem-effek</guid>
      <description><![CDATA[<p>Разбираем, как устроен эффект 3D-вращения картинок из свежей статьи Codrops. Примеры кода на GSAP, Lenis и CSS-трансформации.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-sdelat-3d-vrashhenie-izobrazhenij-pri-skrolle-razbiraem-effek">Как сделать 3D-вращение изображений при скролле: разбираем эффект от Codrops</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 19 Jun 2026 08:09:13 GMT</pubDate>
      <content:encoded><![CDATA[<p>Хотите, чтобы лендинг или портфолио запомнили с первого взгляда? Попробуйте добавить изображениям объёмное вращение при скролле. Эффект выглядит дорого и кинематографично, но под капотом — обычные CSS 3D-трансформации и немного JavaScript.</p><p>В начале июня команда Codrops опубликовала небольшую, но наглядную демонстрацию: галерея фотографий проезжает через вьюпорт, пока каждая картинка медленно кувыркается в трёхмерном пространстве. Идея позаимствована у аниматора Jason Booth, а код выложен на GitHub вместе с пятью готовыми вариациями.</p><p>В этой статье разберёмся, как устроен эффект, из чего состоит математика и как быстро повторить его у себя — без WebGL, Canvas и тяжёлых библиотек.</p><p>Эффект строится на CSS-свойствах perspective и transform-style: preserve-3d, а анимация крутит rotationX/Y/Z и translateZ по прогрессу скролла.</p><p>Для синхронизации с прокруткой используется GSAP ScrollTrigger с параметром scrub: true; плавность даёт библиотека Lenis.</p><p>Codrops предлагает пять вариаций: от мягкого волнообразного движения до агрессивного разворота с blur и изменением яркости.</p><p>Всего нужно три ингредиента: разметка с фоновыми изображениями, CSS для 3D-контекста и 30—40 строк JS, которые связывают скролл с трансформациями.</p><h2>Как устроен базовый эффект</h2><p>В основе лежит простая мысль: каждая картинка — это не плоский прямоугольник, а объект в 3D-пространстве. Пока пользователь скроллит страницу, объект проходит перед «камерой» и меняет ориентацию. Входная точка анимации начинается, когда элемент появляется снизу экрана, а заканчивается, когда уходит вверх.</p><p>Для реализации используется связка GSAP + ScrollTrigger. Параметр scrub: true привязывает анимацию напрямую к позиции скролла: чем дальше прокручено, тем сильнее трансформация. Библиотека Lenis отвечает за плавность: без неё колёсико мыши на Windows или трекпад на macOS могут давать рваное движение, и вся магия растворится.</p><h3>Разметка и CSS</h3><p>HTML минимален: контейнер .gallery и набор .gallery__item с фоновыми картинками. Главное — обернуть каждый item дополнительным .gallery__item-wrap и задать ему perspective. Именно обёртка создаёт 3D-контекст, внутри которого вращается сама картинка.</p><h3>Плавный скролл и триггеры</h3><p>Перед запуском анимации инициализируем Lenis и связываем её с GSAP. Это стандартный «боеприпас» для большинства современных сайтов с анимацией по скроллу.</p><h3>Математика вращения</h3><p>Каждой картинке случайно задаётся начальная ориентация по трём осям. Затем GSAP анимирует от этих значений до противоположных, создавая эффект «переворота» на 180°. В обработчике onUpdate вычисляется смещение по оси Z: чем ближе элемент к центру экрана, тем глубже он «погружается» в пространство.</p><p><b>Совет:</b> если вы убираете плавный скролл, протестируйте эффект на мобильном устройстве. Нативный скролл на iOS и Android может дать менее плавную картинку, и тогда имеет смысл оставить Lenis или добавить @media (prefers-reduced-motion) для доступности.</p><h2>Пять вариаций одной идеи</h2><p>Codrops не ограничивается одной анимацией: в репозитории пять HTML-файлов, каждый из которых демонстрирует, как одно и то же ядро превращается в разное настроение. Вот краткая карта отличий.</p><ul><li><b>Вариант 1.</b> Мягкое волнообразное расположение картинок по горизонтали, случайные углы rotationX 70—120° и небольшой зазор по Z (−50 px). Универсальная, спокойная подача.</li><li><b>Вариант 2.</b> Больший размах по rotationX (240—290°) и усиленная глубина до −300 px. Картинки буквально переворачиваются перед глазами.</li><li><b>Вариант 3.</b> Триггер вычисляет поворот через cos(progress * π), добавляет сдвиг по Y (yPercent) и фильтры saturate/brightness. Получается «подводное» движение.</li><li><b>Вариант 4.</b> Акцент на скорости: в обработчике Lenis отслеживается velocity, и чем быстрее скролл, тем сильнее blur и ниже насыщенность. Динамично и спортивно.</li><li><b>Вариант 5.</b> Агрессивное искажение масштаба: scaleX и scaleY меняются в противофазе, картинки растягиваются и сжимаются, проходя через центр экрана.</li></ul><h2>Мини-руководство: повторяем у себя</h2><p>Чтобы не копировать всю демку целиком, можно взять только схему и адаптировать под свой проект. Ниже — самый короткий путь от макета до рабочей анимации.</p><h2>FAQ</h2><h2>Выводы</h2><p>3D-анимации по скроллу — это способ сделать обычную галерею запоминающейся без тяжёлых WebGL-сцен. Хватает CSS-свойств perspective и transform-style, пары строк GSAP и библиотеки Lenis для плавности.</p><p>Главное, что предлагает Codrops, — не готовый плагин, а отправная точка. Пять вариаций показывают, как одну и ту же идею можно растянуть от спокойного волнообразного движения до агрессивного искажения с blur. Возьмите базовую схему, подберите углы и фильтры под свои картинки — и получите эффект, который будет выглядеть так, будто над ним работала целая команда аниматоров.</p><blockquote>Пользователь не запоминает интерфейс, который просто красив. Он запоминает тот, который отзывается на его действия.</blockquote><p>Источники: оригинальная статья <a href="https://tympanus.net/codrops/2026/06/18/exploring-3d-image-rotations-on-scroll/">Codrops</a>, демо <a href="https://tympanus.net/Development/RotatingOnScrollAnimations/">Rotating On-Scroll Animations</a> и исходный код на <a href="https://github.com/codrops/RotatingOnScrollAnimations">GitHub</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Чистое API на Node.js: практическое руководство</title>
      <link>https://tproger.ru/articles/chistoe-api-na-node-js-prakticheskij-gajd</link>
      <comments>https://tproger.ru/articles/chistoe-api-na-node-js-prakticheskij-gajd?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chistoe-api-na-node-js-prakticheskij-gajd</guid>
      <description><![CDATA[<p>Как построить поддерживаемое REST API на Node.js: слои, Zod, единые ошибки, версионирование и Swagger. Проверьте свою архитектуру.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chistoe-api-na-node-js-prakticheskij-gajd">Чистое API на Node.js: практическое руководство</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 16 Jun 2026 11:00:21 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если ваше Node.js-приложение начиналось с одного server.js, а через полгода превратилось в лабиринт маршрутов, где бизнес-логика растворилась в обработчиках Express — эта статья для вас. Чистое API проектируется не ради красоты, а чтобы команда могла добавлять конечные точки, не боясь сломать соседние.</p><p>Разберём минимальный, но готовый к продакшену скелет: разделение слоёв, валидацию входных данных, централизованную обработку ошибок, версионирование, ограничение частоты запросов и автоматическую документацию. Все принципы применимы и к Express, и к Fastify, и к NestJS.</p><p>Чистое API — это прежде всего разделение ответственности: роутер знает маршруты, контроллер переводит HTTP в вызовы сервиса, сервис отвечает за бизнес-логику, а схема проверяет входные данные. Такой подход делает код предсказуемым при любом масштабе.</p><p>Чистое API — это, прежде всего, разделение ответственности: роутеры, контроллеры, сервисы и валидация живут в разных слоях.</p><p>Валидация с помощью Zod выполняется на границе — до того, как запрос попадёт в бизнес-логику.</p><p>Централизованный обработчик ошибок — единственное место, где исключения превращаются в HTTP-ответы.</p><p>Стоит закладывать версионирование и документацию OpenAPI с первого дня: позже это обойдётся дороже.</p><p>Fastify и NestJS дают те же архитектурные идеи из коробки, но логика слоёв от этого не меняется.</p><h2>Что мы будем строить</h2><p>Возьмём намеренно простой домен — каталог товаров. Нам важна не бизнес-логика, а структура. К концу у нас будет REST API с единым форматом ответов, валидацией, версионированием по пути /api/v1, ограничением частоты запросов и интерактивной документацией Swagger.</p><h2>Структура проекта</h2><p>Прежде чем писать код, договоримся, где что лежит. Каждая фича — отдельная папка, а не рассыпанный по проекту набор файлов.</p><ul><li>api/v1/ — все маршруты версионированы с первого дня. Добавить v2 позже можно новой папкой, а не рефакторингом.</li><li>products/ — фичевая папка владеет роутером, контроллером, сервисом и схемой.</li><li>middleware/ — сквозная функциональность: защита, логирование, лимиты.</li><li>lib/ — утилиты без привязки к фреймворку.</li></ul><h2>Разделяем ответственность</h2><p>Самая частая ошибка в Express-приложениях — бизнес-логика внутри обработчика маршрута. Там же появляется валидация, работа с базой данных и формирование ответа. При росте проекта такой файл становится опасным для изменений.</p><h3>Роутер знает только «куда идти»</h3><h3>Промежуточный обработчик валидации</h3><p>Промежуточный обработчик validateRequest проверяет body, params и query до попадания в контроллер. Если данные не проходят проверку, ошибка передаётся в централизованный обработчик.</p><h3>Контроллер переводит HTTP в вызовы сервиса</h3><p>Контроллер не знает, где хранятся товары. Его задача — извлечь параметры из запроса, вызвать сервис и вернуть ответ. Всё остальное передаётся в централизованный обработчик ошибок через next(error).</p><h3>Сервис содержит бизнес-логику</h3><p>Сервис не зависит от HTTP. Когда придёт время заменить хранилище в памяти на настоящую базу данных, потребуется поправить только этот файл.</p><h2>Валидация на границе с Zod</h2><p>Любое API, принимающее внешние данные, должно их проверять. Без валидации один некорректный запрос способен превратиться в ошибку времени выполнения, некорректную запись в базе или уязвимость.</p><p>Zod даёт две вещи сразу: проверку во время выполнения и типы TypeScript, выведенные из одной схемы. Промежуточный обработчик validateRequest проверяет body, params и query до того, как запрос попадёт в контроллер. Если данные невалидны, дальше они не идут.</p><h2>Единый обработчик ошибок</h2><p>Разбросанная обработка ошибок — один из главных источников хаоса: где-то возвращается { error: '...' }, где-то { message: '...' }, а где-то случайно отдаётся HTML-страница. Решение — один обработчик, через который проходят все исключения.</p><p>Теперь клиент всегда получает предсказуемую форму ответа, а добавление логирования или отправки ошибок в мониторинг — однострочное изменение в одном месте.</p><h2>Единый формат ответов</h2><p>Успешный ответ всегда выглядит как { success: true, data: ... }, а ошибка — как { success: false, error: { code, message, details } }. Фронтенд или сторонний интегратор знает, чего ожидать от любого эндпоинта.</p><h2>Версионирование API</h2><p>Версионировать API с первого дня стоит недорого. Добавить версию позже — значит ломать существующих клиентов или городить сложную миграцию.</p><p>Новая версия — новая папка src/api/v2/ и новый префикс. Старые клиенты продолжают работать на /api/v1.</p><h2>Ограничение частоты запросов</h2><p>Rate limiting защищает API от случайных и намеренных перегрузок. Настроить его в Express помогает пакет express-rate-limit.</p><p>Глобальный лимит распространяется на все запросы; операции, которые изменяют данные, ограничены жёстче. Ответ тоже соответствует единому формату ошибки.</p><h2>Документация OpenAPI и Swagger</h2><p>API без документации годится только для автора. С помощью swagger-jsdoc и swagger-ui-express можно получить интерактивную документацию прямо из JSDoc-комментариев в роутерах.</p><p><b>Совет:</b><br />Держите описания эндпоинтов в одном файле с маршрутами, а glob в swagger.ts настройте на файлы, доступные во время работы приложения. Лучше генерировать спецификацию на этапе сборки, чем полагаться на исходники TypeScript.</p><h2>Fastify и NestJS: альтернативы Express</h2><p>Всё, что мы разобрали, работает и в Express. Но если вы начинаете проект с нуля, стоит взглянуть на альтернативы.</p><ul><li>Fastify — быстрее Express в бенчмарках (порой в два раза), имеет встроенный логгер Pino и валидацию по схеме. Разделение слоёв остаётся на совести разработчика.</li><li>NestJS — популярен в крупных компаниях: слои модулей, контроллеров и сервисов навязаны архитектурой, что упрощает введение новых разработчиков в проект.</li><li>Express — остаётся лучшим выбором, если вы присоединяетесь к существующему проекту или команда уже знает экосистему.</li></ul><p>Архитектурные принципы — разделение слоёв, единый формат ошибок, валидация на границе — не зависят от фреймворка. Меняется только синтаксис.</p><h2>FAQ</h2><h3>Минимальный набор для старта</h3><p>Для самостоятельного запуска понадобятся базовые зависимости и алиасы путей в tsconfig.json. Объявите @/* на папку src, и примеры заработают без ручных правок импортов.</p><h2>Выводы</h2><blockquote>Чистая структура API — это не переусложнение. Это минимум, при котором бэкенд можно поддерживать нескольким людям.</blockquote><p>Мы собрали минимальный, но масштабируемый каркас: папки по фичам, разделённые слои, валидацию на границе, централизованную обработку ошибок, единый формат ответов, версионирование, лимиты и автоматическую документацию. Ни один из этих шагов сложный сам по себе. Их ценность — в сочетании и в том, чтобы сделать всё это до того, как код разрастётся.</p><p>Если начинаете новый Node.js-проект, не откладывайте структуру «на потом». А в существующем — попробуйте вынести валидацию в схему и собрать ошибки в одном обработчике. Потом всегда дороже.</p><h2>Источники</h2><p>Идеи и примеры в статье основаны на материале Gavin Cettolo «<a href="https://dev.to/gavincettolo/clean-api-design-in-nodejs-a-practical-guide-3a32">Clean API Design in Node.js: A Practical Guide</a>» (dev.to).</p>]]></content:encoded>
    </item>
    <item>
      <title>Представляем MDN MCP server</title>
      <link>https://tproger.ru/translations/predstavlyaem-mdn-mcp-server</link>
      <comments>https://tproger.ru/translations/predstavlyaem-mdn-mcp-server?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/predstavlyaem-mdn-mcp-server</guid>
      <description><![CDATA[<p>MDN MCP server переносит актуальную документацию и данные о совместимости браузеров прямо в редактор или AI-агента. Разбираем, как подключить и почему точнее.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/predstavlyaem-mdn-mcp-server">Представляем MDN MCP server</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Mozilla]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 15 Jun 2026 11:30:35 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перевод статьи The MDN Team из MDN Blog, оригинал: <a href="https://developer.mozilla.org/en-US/blog/introducing-mdn-mcp-server/">Introducing the MDN MCP server</a>.</p><p>Мы рады анонсировать выпуск MDN MCP server. MCP (Model Context Protocol) — открытый стандарт, который позволяет ИИ-инструментам подключаться к внешним источникам данных. MDN MCP server использует этот протокол, чтобы перенести документацию MDN и данные о совместимости браузеров прямо в вашего ИИ-агента или IDE.</p><ul><li>MDN MCP server — экспериментальный сервер по протоколу MCP.</li><li>Даёт ИИ-агентам и IDE доступ к актуальной документации MDN и данным о совместимости браузеров.</li><li>Работает с VS Code, Zed, Cursor, Claude Code, Codex CLI, Antigravity CLI и Claude Desktop.</li><li>В тестах с Claude Code Opus 4.7 MDN MCP дал гораздо точнее и надёжнее результаты о поддержке браузеров.</li><li>Ответы с MDN MCP были вдвое быстрее, чем без него.</li></ul><h2>Зачем мы создали MDN MCP</h2><p>Всё больше ИИ-инструментов интегрируется в рабочие процессы веб-разработки, но они могут выдавать устаревшую информацию о веб-платформе из-за обучающих данных и даты знания модели.</p><p>Например, LLM или агент для написания кода может не знать, что существует функция вроде @view-transition CSS at-rule, или не знать, достигла ли она статуса Widely Available в Baseline и безопасна ли для использования во всех браузерах.</p><p>MDN MCP даёт вашему агенту для написания кода доступ к точной и актуальной информации о веб-платформе. Также он упрощает доступ к последней документации, не покидая привычные инструменты.</p><p>Сервер сейчас находится в экспериментальном статусе. Подробности об обработке данных в этой фазе — в нашей <a href="https://developer.mozilla.org/en-US/mcp#privacy_and_data_retention">заметке о приватности</a>.</p><h2>Как использовать MDN MCP</h2><p>MDN MCP server работает с любым MCP-совместимым клиентом, включая:</p><ul><li><b>Редакторы</b>: VS Code, Zed и Cursor.</li><li><b>CLI-агенты</b>: Claude Code, Codex CLI и Antigravity CLI (ранее Gemini CLI).</li><li><b>Чат-приложения</b>: Claude Desktop.</li></ul><p>Ссылки в этом списке ведут к инструкциям по настройке MCP для каждого инструмента. Инструкции по установке и другие детали — на нашей странице <a href="https://developer.mozilla.org/en-US/mcp">MDN MCP server</a>.</p><p>Как быстрый пример, чтобы использовать его с Claude Code, нужно выполнить следующую команду:</p><p>Мы с нетерпением ждём, как вы интегрируете его в свой рабочий процесс веб-разработки и в каких сценариях он окажется наиболее полезен.</p><h2>Какую разницу даёт MCP</h2><p>Учитывая недетерминированную природу LLM и разнообразие доступных моделей, часто сложно сравнивать их поведение с включёнными или выключенными навыками, промптами, инструментами и MCP.</p><p>Мы протестировали Claude Code Opus 4.7 с MDN MCP и без него на нескольких функциях, недавно появившихся в Firefox 150 и 151, спрашивая, как использовать функции и какая у них поддержка браузеров. А именно:</p><ol><li>Как использовать CSS-функцию light-dark() для изображений и какие браузеры её поддерживают?</li><li>Как использовать CSS-псевдокласс :buffering и какие браузеры его поддерживают?</li><li>Как использовать атрибут shadowrootslotassignment на элементе  и какие браузеры его поддерживают?</li><li>Как использовать Web Serial API и какие браузеры его поддерживают?</li></ol><p>Мы заметили определённые закономерности в результатах. В большинстве случаев заметки по использованию от Claude Code с MDN MCP и без него были сопоставимы. Часть ответов, использовавших MCP, была структурирована лучше и полнее. Например, заметки для CSS-функции light-dark() также включали примеры с линейными градиентами, которые не были прямо упомянуты в вопросе, но тоже поддерживаются.</p><p>Когда дело дошло до информации о поддержке браузеров, победитель был очевиден: MDN MCP дал намного точнее и надёжнее результаты. Claude Code без MCP правильно определил поддержку браузеров только в одном случае — для псевдокласса :buffering.</p><p>Например, Claude Code без MCP настаивал, что декларативный атрибут shadowrootslotassignment поддерживается в Chrome 120 и Safari 18.3, возможно, путая его с опцией slotAssignment метода Element.attachShadow(). Но на самом деле Firefox 151 — первый браузер, в котором появилась поддержка этого атрибута.</p><p>Без MCP Claude Code также не дал никакой конкретной информации о поддержке браузеров для использования изображений в функции light-dark(): «поддержка менее однородна, чем вариант с цветом», тогда как с MCP он выдал полную таблицу с указанием Firefox 150 и Chrome (за флагом) как поддерживающих браузеров.</p><p>Худший результат Claude Code без MCP показал на вопросе про Web Serial API. Firefox 151 получил поддержку Web Serial API в мае 2026 года. Однако Claude Code без MCP правильно упомянул браузеры на базе Chromium как поддерживающие эту функцию, но также настаивал, что в Firefox она:</p><blockquote>Не реализовано (и не в планах — см. позицию Mozilla по стандартам: «вредно»).</blockquote><p>С включённым MCP Claude Code правильно определил, что Firefox 151 поставляет поддержку Web Serial API, согласно примечаниям к выпуску.</p><p>Кроме того, мы заметили, что в наших тестах ответы с использованием MDN MCP были вдвое быстрее. Без MCP Claude Code приходилось загружать и парсить немало HTML-страниц, чтобы найти актуальную информацию, что занимало время, но даже тогда не давало точных результатов.</p><h2>Поучаствовать</h2><p>Ваш отзыв помогает нам становиться лучше. Если вы столкнулись с проблемами, есть комментарии или предложения или хотите поделиться, как используете MDN MCP, мы будем рады услышать вас. Заходите в канал platform в нашем Discord. Если заметили проблемы, сообщайте о них в репозиторий <a href="https://github.com/mdn/mcp">mdn/mcp</a> на GitHub.</p><h2>Что дальше</h2><p>По мере того как ИИ-инструменты становятся всё большей частью рабочих процессов веб-разработки, мы стремимся сделать документацию MDN доступной там, где она вам нужна. Этот релиз — один шаг к этой цели, и мы с нетерпением ждём возможности продолжить улучшать опыт с вашей помощью.</p><p>Источник: <a href="https://developer.mozilla.org/en-US/blog/introducing-mdn-mcp-server/">Introducing the MDN MCP server — MDN Blog</a>.</p><p>Попробуйте подключить MDN MCP к своему редактору или агенту и проверьте, насколько точнее станут ответы о веб-платформе.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что важнее технологического стека при создании сайта</title>
      <link>https://tproger.ru/articles/chto-vazhnee-tehnologicheskogo-steka-pri-sozdanii-sajta</link>
      <comments>https://tproger.ru/articles/chto-vazhnee-tehnologicheskogo-steka-pri-sozdanii-sajta?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-vazhnee-tehnologicheskogo-steka-pri-sozdanii-sajta</guid>
      <description><![CDATA[<p>Разбираем, что реально влияет на успех сайта — скорость, хостинг, микроразметка, ИИ-поиск и UX. Проверьте свой фундамент.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-vazhnee-tehnologicheskogo-steka-pri-sozdanii-sajta">Что важнее технологического стека при создании сайта</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 15 Jun 2026 09:00:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы сейчас спорите, на чём писать новый сайт — React, Vue или что-то ещё — остановитесь. <b>Скорее всего, технологический стек, то есть набор инструментов для разработки, не решит, выстрелит проект или нет.</b> Современный сайт можно собрать практически на любом зрелом фреймворке, и он будет работать. Главное теперь не в том, на чём выстроен сайт, а в том, <b>насколько быстро он грузится, насколько удобен для людей и понятен для поисковых и ИИ-систем</b>. В этой статье разберём, почему стек отошёл на второй план и что по-настоящему влияет на успех веб-проекта.</p><h2>Что значит «правильный фундамент сайта»</h2><p>Под фундаментом я понимаю не только сервер и домен, а совокупность факторов: производительность, надёжность инфраструктуры, структурированные данные, качество контента, доступность и удобство использования. Фреймворк — это инструмент; фундамент — это то, ради чего инструмент используется. Плохо оптимизированный сайт на передовом стеке часто проигрывает хорошо сделанному сайту на классическом стеке. Подробнее про метрики скорости — в материале <a href="https://tproger.ru/articles/kak-s-pomoshhju-core-web-vitals-vljubit-v-svoj-sajt-polzovatelej-i-poiskovye-sistemy">о Core Web Vitals на Tproger</a>.</p><ul><li>Выбор фреймворка перестал быть решающим фактором: зрелые инструменты дают схожие возможности.</li><li>Производительность, хостинг, домен и CDN (сеть доставки контента) напрямую влияют на трафик и конверсию.</li><li>Структурированные данные (Schema.org / JSON-LD) помогают поисковикам и ИИ правильно понимать контент.</li><li>ИИ-поиск и ответные системы меняют правила видимости: важны ясность, авторитетность и точные ответы.</li><li>Качественный контент и UX становятся главным конкурентным преимуществом.</li></ul><h2>Технологический стек стал товаром</h2><p>За последнее десятилетие экосистема веб-разработки выросла настолько, что большинство популярных фреймворков предлагают примерно одно и то же: компонентную архитектуру, серверный рендеринг, интеграции с API, аутентификацию и инструменты оптимизации. Разрыв между React, Vue, Svelte, Next.js, Nuxt, Laravel или Django в типичных задачах сократился до предпочтений команды, а не до объективных преимуществ.</p><p>Пользователи не видят, на чём написан сайт. Они видят, загружается ли страница за секунду, работает ли форма на мобильном, понятна ли навигация. Бизнесу важны трафик, заявки, продажи и лояльность — ни один из этих показателей не растёт автоматически от того, что вы переписали проект на модный стек.</p><p><b>Сигнал проверить себя:</b> если команда обсуждает миграцию фреймворка, но у сайта LCP выше 2,5 с, нет CDN и картинки весят по 400 КБ — стоит сначала закрыть очевидные дыры в фундаменте.</p><h2>Производительность всё ещё решает</h2><p>Многочисленные исследования показывают, что задержка загрузки влияет на отказы и конверсию. Даже небольшое увеличение времени ответа заметно снижает вероятность, что пользователь дождётся контента.</p><h3>Что именно оптимизировать</h3><p>Современная оптимизация выходит далеко за «сожми JS». Нужно думать о форматах изображений (WebP, AVIF), ленивой загрузке, кешировании на граничных серверах, CDN, оптимизации шрифтов и времени ответа сервера. Интернет-магазин, который перевёл каталог на WebP, включил lazy loading и раздал статику через CDN, зачастую получит больше прироста, чем если бы переписал витрину с нуля.</p><ul><li>Измеряйте LCP (Largest Contentful Paint — отрисовку крупного контента), INP (Interaction to Next Paint — время реакции на взаимодействие) и CLS (Cumulative Layout Shift — визуальную стабильность) в PageSpeed Insights или Lighthouse.</li><li>Переводите изображения в современные форматы и используйте адаптивные размеры.</li><li>Включайте кеширование статики на CDN (сети доставки контента) как минимум на год.</li><li>Убирайте неиспользуемый CSS и JS: в российских сетях каждый лишний мегабайт бьёт по скорости и по бюджету пользователя.</li></ul><h2>Домены и инфраструктура не теряют значения</h2><p>Разработчики любят обсуждать код, но домен, DNS и регистратор — это цифровое имущество проекта. Неправильно настроенные записи, просроченный домен или взломанный регистратор могут положить сайт быстрее, чем баг в приложении.</p><p>В российском контексте стоит обращать внимание на локальных регистраторов — например, Reg.ru или RU-CENTER. Важны двухфакторная аутентификация в личном кабинете, блокировка переноса домена (domain lock), корректные NS-записи и резервные DNS-серверы. Если ваш бизнес зависит от сайта, отказоустойчивость DNS может спасти репутацию в момент DDoS или аварии хостинга.</p><ul><li>Проверьте срок действия домена и включите автообновление.</li><li>Включите 2FA у регистратора и запретите неавторизованный трансфер.</li><li>Используйте минимум два независимых NS-сервера в разных сетях.</li><li>Мониторьте время отклика DNS: оно влияет на TTFB (Time to First Byte — время до первого байта ответа сервера).</li></ul><h2>Хостинг — это уже не просто сервер</h2><p>Раньше хостинг означал аренду железа и развёртывание кода. Сегодня платформы предлагают глобальные CDN, автомасштабирование, встроенную безопасность, наблюдаемость и автоматизацию развёртывания. Граничные вычисления позволяют отдавать контент ближе к пользователю, снижая задержку.</p><h3>Что спрашивать у провайдера</h3><p>В России это может быть Selectel, Timeweb, Beget, Yandex Cloud или VK Cloud. Выбирая провайдера, смотрите не только на цену CPU/RAM, но и на SLA по доступности, географию CDN-точек, скорость развёртывания, поддержку HTTP/2 и HTTP/3, а также простоту мониторинга. Сайт, который остаётся доступным во время вирального всплеска трафика, приносит больше пользы, чем идеально написанный, но упавший сервис.</p><p><b>Практический контрольный список:</b> есть ли у провайдера CDN (сеть доставки контента) в России, автомасштабирование, бэкапы и DDoS-защита? Если нет — вы платите не за хостинг, а за аренду сервера с самообслуживанием.</p><h2>Структурированные данные перешли из «можно» в «нужно»</h2><p>Поисковые системы и ИИ всё чаще не просто индексируют текст, а пытаются понять <i>смысл</i> страницы. Schema.org / JSON-LD помогает явно указать: это статья, товар, отзыв, событие, организация или рецепт.</p><p>Без микроразметки поисковику приходится догадываться из неструктурированного текста, что повышает риск ошибок. С микроразметкой контент чаще попадает в расширенные сниппеты, карточки знаний и rich results. Для русскоязычных проектов это особенно важно в Яндексе и Google: оба поисковика поддерживают Schema.org.</p><p>Пример разметки статьи на базе Schema.org — в гайде <a href="https://tproger.ru/articles/dobavlenie-schema-org-v-docusaurus-dlya-geo">«Добавляем Schema.org в Docusaurus для GEO»</a>.</p><ul><li>Для статей используйте тип Article с headline, author и datePublished.</li><li>Для товаров — Product с offers, aggregateRating и availability.</li><li>Проверяйте разметку через валидаторы Google Rich Results Test и Яндекс.Вебмастер.</li><li>Добавляйте FAQ и HowTo только там, где они реально отвечают на вопросы пользователей.</li></ul><h2>ИИ-поиск и Answer Engine Optimization</h2><p>Пользователи всё чаще задают вопросы нейросетям и ассистентам вместо того, чтобы вбивать ключевые слова в поисковик. ChatGPT, Perplexity, ЯндексGPT, Google AI Overviews собирают ответы из множества источников и показывают их в диалоговом формате.</p><h3>Как стать источником для ИИ</h3><p>Это меняет правила видимости. Цель уже не только попасть на первую страницу Google, но и стать источником, который ИИ цитирует. Answer Engine Optimization (AEO) — подход, при котором контент структурируется так, чтобы давать прямые, авторитетные и легко извлекаемые ответы.</p><ul><li>Формулируйте ключевые тезисы в первых 100-150 словах статьи.</li><li>Используйте чёткие заголовки H2/H3 с вопросами («Что такое...», «Как проверить...»).</li><li>Добавляйте блоки FAQ и Ключевые выводы: ИИ-системы часто цитируют именно их.</li><li>Подкрепляйте утверждения ссылками на первоисточники и данные.</li></ul><h2>Контент остаётся главной причиной визита</h2><p>Технологии улучшают доставку, но не заменяют смысл. Тонкий контент, заточенный только под ключевые слова, всё хуже ранжируется: поисковики и ИИ всё лучше распознают экспертизу, авторитетность и релевантность.</p><p>Хороший сайт отвечает на реальные вопросы и решает реальные задачи. Это может быть собственное исследование, пошаговый гайд, сравнение инструментов или разбор типичных ошибок. Контент, который демонстрирует экспертизу, чаще получает ссылки, цитаты и репосты — а значит, и органический трафик.</p><blockquote>Поисковые системы всё лучше распознают контент, который действительно отвечает на вопросы пользователей. Техническая оптимизация открывает дверь, но экспертиза заставляет людей возвращаться.</blockquote><h2>Пользовательский опыт — новый дифференциатор</h2><h3>С чего начать проверку</h3><p>Когда технологии доступны всем, преимущество уходит к тому, кто делает продукт удобнее. Интуитивная навигация, отзывчивая вёрстка, доступность для людей с ограниченными возможностями и стабильная работа на мобильных — это не «полировка», а часть функционала.</p><p>Простые вещи работают сильнее сложных: сократите число шагов в корзине, увеличьте целевые зоны кнопок на телефоне, проверьте таб-навигацию и контрастность. Улучшения доступности обычно делают сайт удобнее для всех.</p><ul><li>Проверьте сайт с клавиатуры: можно ли дойти до всех интерактивных элементов?</li><li>Запустите Lighthouse в мобильном режиме и исправьте критичные замечания по доступности.</li><li>Тестируйте на реальных устройствах, а не только в десктопном браузере.</li><li>Собирайте обратную связь от реальных пользователей, а не только метрики.</li></ul><p>Подробнее про инструменты и приёмы проверки доступности — в материале <a href="https://tproger.ru/articles/chto-takoe-dostupnost-sajta-i-kak-ejo-proverit">«Что такое доступность сайта и как её проверить»</a>.</p><h2>Будущее — за результатами, а не фреймворками</h2><p>Индустрия веб-разработки дошла до точки, где любой зрелый фреймворк способен дать отличный результат. Настоящий вызов — собрать сайт, который быстро грузится, легко находится, надёжно работает и понятен людям и машинам.</p><p>Сайты, которые побеждают сегодня, строятся не на модных технологиях, а на сильном фундаменте. Разработчики, которые фокусируются на производительности, инфраструктуре, микроразметке, контенте и UX, создают проекты, которые останутся конкурентоспособными независимо от того, как изменятся поисковики, ИИ или фронтенд-стек.</p><h2>FAQ</h2><h2>Выводы</h2><p>Технологический стек важен, но он перестал быть главным предиктором успеха. В 2026 году сайт выигрывает не потому, что написан на модном фреймворке, а потому что у него сильный фундамент: быстрая загрузка, надёжная инфраструктура, понятная микроразметка, качественный контент и удобный интерфейс.</p><p>Если вы планируете запуск или редизайн, начните не со споров о стеке, а с аудита скорости, инфраструктуры и контента. Это даст больше реальной пользы, чем очередная миграция «на что-то более современное».</p><p><b>Источник:</b> <a href="https://www.freecodecamp.org/news/building-a-website-what-matters-more-than-your-tech-stack/">Manish Shivanandhan, freeCodeCamp — Building a Website in 2026: What Matters More Than Your Tech Stack</a>. Материал подготовлен как авторская переработка идеи с добавлением российского контекста и практических рекомендаций.</p>]]></content:encoded>
    </item>
    <item>
      <title>Фреймворк-независимые дизайн-системы: практический подход к веб-компонентам</title>
      <link>https://tproger.ru/translations/frejmvork-nezavisimye-dizajn-sistemy-prakticheskij-podhod-k-veb-2</link>
      <comments>https://tproger.ru/translations/frejmvork-nezavisimye-dizajn-sistemy-prakticheskij-podhod-k-veb-2?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Картофельный Повелитель]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/frejmvork-nezavisimye-dizajn-sistemy-prakticheskij-podhod-k-veb-2</guid>
      <description><![CDATA[<p>Как построить дизайн-систему без привязки к фреймворку, используя веб-стандарты и веб-компоненты. Пошаговое руководство с примерами кода и документацией. Разбираем на практике.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/frejmvork-nezavisimye-dizajn-sistemy-prakticheskij-podhod-k-veb-2">Фреймворк-независимые дизайн-системы: практический подход к веб-компонентам</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Дизайн]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 14 Jun 2026 07:00:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перевод статьи Scott Riley (Piccalilli), оригинал: https://piccalil.li/blog/framework-agnostic-design-systems-part-1/<br /><br />Прежде чем мы начнём, небольшое примечание: это практическое руководство, которое охватывает управление, создание и упаковку компонентов дизайн-системы. Невозможно углубляться в каждый шаг до мельчайших деталей, не превратив материал в полноценный курс. Предполагается наличие некоторых базовых знаний:</p><ul><li>Базовые знания HTML и CSS</li><li>Базовое понимание веб-компонентов</li><li>Установленные Node.js и npm</li><li>Умение работать в терминале на уровне, достаточном для установки пакетов</li><li>Базовые знания конфигурационных файлов и JSON</li><li>Понимание революционной идеи о том, что &lt;button&gt; — это не &lt;div&gt;</li></ul><p>Наконец, это довольно длинный пост. Считайте каждый h2 приглашением сделать перерыв на чай и подышать свежим воздухом.</p><p><a href="https://www.youtube.com/watch?v=AWM5ZNdWlqw">Okayyyyylet’sgo</a>.</p><h2>Фреймворк-независимые компоненты</h2><p>Из всех недавних хайпов/пузырей/назовите их как хотите в мире технологий тот, что одновременно волновал и ставил в тупик меня в равной степени, — это бум дизайн-систем. Общая концепция определённо фантастическая, и почти любая команда или проект могут извлечь пользу из какой-либо формы централизованного хранилища дизайнерских решений. Но, как и любой другой бум, он породил много <i>странностей</i>. Люди сошлись на определённых способах восприятия дизайна в «эпоху дизайн-систем», слайды <a href="https://atomicdesign.bradfrost.com/chapter-2/">Atomic Design</a> в каждой конференц-презентации стали мемом, а дизайн-токены стали целой личностью для некоторых.</p><p>Этот пост — не обо всех странностях, но нам нужно опереться на что-то более конкретное, чем <i>крутая технология — это круто</i>. И одна из моих наименее любимых странностей из курса «Дизайн-системы: странности 101» довольно специфична, но при этом является источником настоящей физической боли для меня: <i>библиотеки компонентов, привязанные к конкретному фреймворку</i>.</p><p>Идея о том, что наши дизайн-системы могут, и даже должны, работать на компонентах, написанных под конкретный фреймворк, кажется мне дикой. Дизайн-системы, по крайней мере частично, должны быть про универсальность, компонуемость и переносимость. Встраивание привязки к фреймворку в уравнение с самого первого дня абсолютно нелепо.</p><p>Я понимаю, что веб-стандарты немного отставали на заре дизайн-систем, а веб-компоненты и кастомные элементы отставали от всех тех приятных возможностей, которые предлагают реактивные фреймворки с управлением состоянием. К счастью для нас, это больше не так, и существует ряд замечательных инструментов, построенных вокруг создания и потребления стандартных веб-компонентов.</p><p>На самом деле, я бы даже сказал, что на момент написания этого поста веб-компоненты — <i>единственно лучший подход</i> к созданию библиотеки компонентов. Они переносимы, используют веб-стандарты, и любой фреймворк, который не является полным бардаком (и многие, которые являются, смотрю на тебя, React), будет поддерживать их либо напрямую, либо с минимальной конфигурацией.</p><p>Отвлечения в сторону, этот пост будет максимально практичным введением в создание веб-компонентов с использованием веб-стандартов, современного CSS и некоторых удобных инструментов, которые помогут нам ускориться. Он также будет весьма субъективным и сильно опираться на идею, что мы должны поставлять нашу библиотеку вместе с документацией в одном репозитории. Вы не <i>обязаны</i> заниматься всеми этими штуками с документацией, если не хотите, но я настоятельно рекомендую попробовать. Весь код здесь для вас, так почему бы и нет!</p><h2>Принципы</h2><p>Сначала рассмотрим несколько принципов. Если они вам близки — читайте дальше; если нет — можете закрыть вкладку, заварить чай и заняться своими делами.</p><h3>Минимально возможный уровень</h3><p>Хотя существует масса инструментов, которые превращают компоненты для конкретного фреймворка (давайте будем честны — почти всегда это React) в веб-компоненты, я не думаю, что такой подход соответствует тому, что мы <i>говорим</i>, что хотим от наших библиотек компонентов и паттернов по духу.</p><p>Когда мы создаём компоненты и проектируем API компонентов, мы разрабатываем некоторые из самых атомарных элементов дизайн-системы. В таком сценарии, на мой взгляд, есть явная, ощутимая польза от работы максимально близко к платформе доставки. Для веб-продуктов это означает работу непосредственно с веб-стандартами.</p><p>На уровне компонентов я гораздо более настроен на удаление слоёв абстракции и работу ближе к веб-стандартам. Вместо того чтобы сразу прыгать в модный фреймворк, я гораздо больше предпочитаю работать с инструментами сборки и лёгкими обёртками. Это означает, что вы всегда находитесь в «режиме веб-стандартов», идёте прямым путём. Горжусь вами.</p><h3>Максимально простые компоненты</h3><p>Компоненты должны быть максимально примитивными. Даже самый, казалось бы, сложный компонент можно представить как очень простую конечную машину состояний. Мне ещё не встречался компонент, который нельзя было бы выразить таким образом, и вам не нужно по умолчанию обращаться к раздутому фреймворку для простых вариантов компонентов и изолированного состояния.</p><p>Я бы даже сказал, что многие реактивные компоненты — это антипаттерн. Реактивность обычно означает логику, и очень часто это приводит нас в область «бизнес-логики» и общего состояния на уровне контейнера или приложения. Простая реактивность на уровне компонента часто необходима — представьте кнопку, которая показывает спиннер загрузки, пока что-то обрабатывается, и возвращается в исходное состояние, когда всё готово, — но добавление тонн состояний и реактивности в изолированном коде компонента всегда <i>кажется</i> мне красным флагом.</p><p>По моему опыту, компоненты наиболее полезны, когда им явно сообщают, какое состояние они должны отражать и какой контент содержать. Они намеренно ограничены и явно декларативны. Обработка сложного состояния и реактивности в вашем приложении, даже если это означает комбинирование нескольких примитивов в паттерн, специфичный для приложения, гораздо более разумна, чем попытка централизовать сложный громадный компонент, который пытается слишком многое обрабатывать.</p><h3>Максимально устойчиво к будущему</h3><p>Устоявшиеся фреймворки со временем становятся устаревшими технологиями. Учитывая всю работу по «переписыванию Angular-проектов на React», на которой некоторые из нас спокойно прожили целых два года, мы должны это понимать. Сам React становится (можно спорить, <a href="https://adactio.com/journal/20618">уже стал</a>) устаревшей технологией, а «переписывание нашего React-приложения на Solid/Svelte» — теперь обычное дело. Я вполне ожидаю, что это будет повторяться до тошноты.</p><p>Веб-стандарты — хотя, признаюсь, они развиваются медленнее и поддерживаются утомительными, своеобразными процессами выпуска — всегда будут с нами. Веб-стандарты выдержали проверку времени и последовательно доказывают, что они заметно более надёжны, чем ваш проблемный любимый, переусложнённый фреймворк.</p><p>Фреймворки тоже по-настоящему замечательны, когда используются правильно. Говоря по опыту, попытка написать состоятельные, реактивные приложения на ванильном HTML, CSS и JS — закаляющая, но в конечном счёте неразумная задача. Однако примитивные компоненты — это не сложные, состоятельные, реактивные веб-приложения. Это маленькие куски атомарного веб-кода, и создавать их со всеми накладными расходами и своеобразиями полноценного фреймворка — это просто приглашение к будущему устареванию.</p><p>Создавая <i>непосредственно с помощью веб-стандартов</i>, мы получаем более низкоуровневое понимание того, как работают наши компоненты, встроенную защиту от будущего, избегая модного фреймворка, и по сути более прогрессивную, доступную (или, по крайней мере, более легко делаемую доступной) и нативную для веба библиотеку компонентов.</p><p>Разделяя ваши атомарные компоненты дизайн-системы от ваших <i>компонентов приложения</i>, вы получаете лучшее из обоих миров: переносимые, примитивные компоненты на уровне системы; сложные и реактивные компоненты и обёртки на уровне приложения.</p><p>Таким образом, когда вам действительно понадобится переписать приложение на Solid/Svelte, вам хотя бы не придётся переписывать всю библиотеку компонентов вместе с ним.</p><h3>Принимать решения в коде</h3><p>Я абсолютно готов стоять насмерт на этой позиции. Инструменты для дизайна — <i>ужасные</i> места для принятия решений по <i>дизайн-системе</i>. Это отчасти потому, насколько оторваны такие инструменты, как Figma, от того, как на самом деле работают дизайн-системы, вплоть до откровенно катастрофического несоответствия словаря и концепций.</p><p>Как человек, который по сути больше дизайнер, чем разработчик, я создал и работал с более чем дюжиной «дизайн-систем» в Figma. Как человек, который также проводит гораздо больше времени в коде, чем в инструментах дизайна, я считаю себя вправе сказать, что ни одна из них не отражала того, чем должна быть хорошая системная основа. Это не укол в сторону дизайнеров, которые не пишут код, скорее просто показывает, насколько сложной <i>сами инструменты</i> делают эту часть нашей работы.</p><p>Инструменты для дизайна — это места для быстрого тестирования разных идей и экспериментов со стилем и компоновкой. Они абсолютно ужасны для кодификации системных решений, отчасти из-за своей самой природы: они предоставляют очень маленькое, проприетарное подмножество возможностей нашего реального носителя — браузера.</p><blockquote>Так же и браузер, но я рискую укрепиться на том самом холме.</blockquote><p>Окончательные системные дизайнерские решения должны приниматься в браузере. Токены цвета могут использовать современные цветовые пространства. Токены размеров и отступов должны выражаться в относительных единицах, где это возможно. Почти каждый тип токена может выиграть от какой-либо математики, включая логарифмические шкалы для типографики или программные сдвиги оттенка и светлоты для цветов. API компонентов также следует строить с помощью надёжных, хорошо типизированных определений. Инструменты дизайна могут предложить лишь подобие этих концепций.</p><p>Если вы начинаете с Figma — это вполне нормально, но это ужасный источник истины. Воспринимайте свой инструмент дизайна как точный инструмент прототипирования, а не как конечную цель для дизайнерских решений.</p><h3>Документировать по ходу разработки</h3><p>Опираясь на последний принцип, если лучшее место для принятия решений — код, то лучшее время для документирования этих решений — фаза сборки, пока они свежи в вашей голове. Разрабатываете props? Ну посмотрите-ка, у вас уже есть прекрасный набор определений типов для этих props, неплохо было бы добавить туда маленький комментарий <a href="https://jsdoc.app/">JSDoc</a> и заняться своими делами.</p><p>Мне нравится идти дальше и разворачивать библиотеку компонентов прямо в документирующем фреймворке вроде <a href="https://vitepress.dev/">VitePress</a>, активно создавая человекочитаемую документацию параллельно с разработкой самих компонентов. Это не только в итоге станет «официальной» документацией дизайн-системы, но и позволит проверить, насколько переносимы ваши компоненты.</p><p>Это делает мой мозг счастливым, потому что полное кодовое представление моих дизайн-систем (что абсолютно, всегда включает фактическую документацию) живёт в одном репозитории. Всю систему можно развернуть, не жонглируя зависимостями, и это заставляет меня относиться к документации как к необходимому шагу к релизу.</p><h2>Давайте создадим (и задокументируем)</h2><p>Ладно, хватит болтать, давайте на самом деле создадим что-то практичное. Мы соберём основы для централизованной, независимой от фреймворка библиотеки компонентов. Мы будем прорабатывать документацию по мере создания компонентов, что даст нам действительно чистый тестовый стенд для самих компонентов. Настоящий порочный круг, если таковой вообще был.</p><p>Вот что у нас будет в конце этой статьи:</p><ul><li>Основа для нашей гибридной библиотеки компонентов/документации «всё-в-одном» дизайн-системы</li><li>Стильная, хорошо задокументированная кнопка как веб-компонент</li><li>Развёртываемый сайт документации, который показывает, как замечательна наша кнопка</li><li>Готовая к продакшену библиотека компонентов, которую можно опубликовать в вашем любимом пакетном менеджере</li></ul><p>Нам действительно нужно беспокоиться только о двух инструментах: <a href="https://elenajs.com/">Elena</a> для сборки и распространения нашей библиотеки компонентов и <a href="https://vitepress.dev/">VitePress</a> для создания нашей документации.</p><h3>Elena</h3><p>Клей для всего этого проекта — Elena. Фантастическая библиотека от непобедимого <a href="https://arielsalminen.com/">Ariel Salminen</a> для создания прогрессивных веб-компонентов. Я не буду углубляться в философию того, что означает «прогрессивный» в этом контексте, потому что это уже <a href="https://arielsalminen.com/2026/progressive-web-components/">исключительно хорошо задокументировано</a> самим Ariel.</p><p>Elena — это крошечная библиотека, которая делает Just Enough Abstraction™ поверх стандартных веб-компонентов. Мы получаем такие вещи, как props (отражаемые как пользовательские атрибуты), изолированную реактивность, методы жизненного цикла и даже классные штуки вроде миксинов для компонуемости. Мы не будем углубляться <i>слишком</i> сильно в Elena, но следите за ходом мысли и, если вам понравятся основы, я очень рекомендую погрузиться во всё, что она предлагает. Это круто.</p><p>Цитата из <a href="https://elenajs.com/#why-should-i-use-elena">документации Elena</a>:</p><blockquote>[Elena] берёт на себя межфреймворковую сложность (синхронизация prop/атрибута, делегирование событий, совместимость с фреймворками), чтобы вы могли сосредоточиться на создании компонентов, а не на инфраструктуре.</blockquote><p>Именно этого я и хочу от такого инструмента: позвольте мне писать код, не абстрагируйте веб-стандарты, разберитесь со всей странной ерундой, которую я не хочу трогать.</p><h3>VitePress</h3><p>Я не буду тратить много времени на VitePress, потому что, честно говоря, это просто самое удобное готовое решение для документации, которое не называется Storybook. Пара npm install — и у нас есть надёжное, основанное на Markdown решение для документации, готовое к работе.</p><p>Позже мы сделаем несколько классных штук с VitePress, JSDoc и нашим сгенерированным Elena манифестом пользовательских элементов, что поможет ускорить процесс документирования, но, честно говоря, иметь <i>где-то</i> документировать гораздо важнее, чем то, <i>во что</i> мы документируем.</p><h3>Структура проекта</h3><p>Здесь всё может изначально показаться немного странным. Хотя нам нужно собирать и распространять наши компоненты как отдельную библиотеку, нам также нужно их видеть и тестировать. Самый простой способ — это слепить статический сайт и просто свалить все компоненты на одну страницу. Это <i>вполне нормально,</i> и, по сути, я бы поощрил это, если вы просто экспериментируете с Elena, но по причинам, изложенным выше, я считаю, что имеет большой смысл создавать <i>внутри</i> нашей документации.</p><p>У нас по сути будет что-то вроде монорепозитория: Elena будет делать своё дело на уровне компонентов, а сам сайт документации будет статически генерироваться с помощью VitePress.</p><h2>Создание каркаса проекта</h2><p>Здесь довольно много движущихся частей, поэтому вместо того, чтобы просто кидать вам дикую цепочку склеенных npm install, давайте разберём настройку шаг за шагом.</p><p>Для начала создадим папку проекта:</p><p>Замените my-ds на любое название, которое хотите дать своему проекту.</p><p>Затем инициализируем npm:</p><p>Команда npm init -y создаст файл package.json в корне проекта. Эта корневая папка напрямую ничего не будет делать — она просто склеивает наши компоненты и документацию вместе в монорепозитории.</p><p>Приведём в порядок наш package.json:</p><p>Здесь происходит кое-что, что пока не имеет особого смысла (и даже не будет работать) — это станет понятно чуть позже. Настройка workspaces позволит нам обращаться со сборкой библиотеки компонентов как с пакетом, не публикуя его, а скрипты dev, а также различные watch и build позволят нам отслеживать и собирать либо документацию, либо компоненты (либо оба варианта одновременно с помощью команды dev).</p><p>Кстати, давайте установим пару штук:</p><p>Это установит concurrently, который позволит нам запускать команду watch Elena и команду dev VitePress одновременно. Мы будем держать её запущенной, пока работаем. Также установится VitePress и его тема по умолчанию. Если хотите заморочиться — можете использовать другую тему.</p><h3>Настройка VitePress</h3><p>Настроим документацию. Для начала создадим папку docs:</p><p>Затем создайте docs/.vitepress/config.mjs:</p><p>Проверьте расширение!Обратите внимание: мы используем .mjs, а не .js — это заставляет Node трактовать файл как ESM. Это необходимо, потому что мы импортируем из vitepress. Вам не обязательно знать, что это значит. Честно говоря, я не уверен, что сам это понимаю. Просто убедитесь, что используете .mjs. Ладно, спасибо.</p><p>Здесь мы используем postIsolateStyles, чтобы ограничить область действия встроенных стилей .vp-doc VitePress и не дать им просочиться в наши примеры компонентов. Без этого встроенные стили VitePress <i>могут</i> переопределять стили ваших компонентов (включая инкапсулированные сбросы) из-за того, как Vite внедряет таблицы стилей во время выполнения.</p><p>Далее создайте минимальный docs/index.md, чтобы у VitePress была домашняя страница:</p><p>Сейчас хороший момент, чтобы проверить, всё ли работает:</p><p>Вы должны увидеть очень простой локальный сайт на VitePress! По умолчанию он будет доступен по адресу <a href="http://localhost:5173/">http://localhost:5173/</a>.</p><h3>Настройка Elena</h3><p>Теперь, для MVP нашей дизайн-системы, давайте установим Elena. Мы будем использовать Elena для создания компонентов и в конечном итоге распространять их в виде пакета. Именно здесь некоторые вещи из корневого package.json начинают обретать смысл.</p><p>Начнём с создания папки компонентов и инициализации npm для нашего пакета компонентов:</p><p>Далее отредактируйте packages/components/package.json:</p><p>Затем установите Elena:</p><p>Это установит Elena, её бандлер и CLI-инструмент.</p><p>Мы будем использовать CLI-инструмент Elena для создания каркаса наших компонентов. По сути, он проведёт нас через создание компонента, позволяя запустить команду, которая генерирует нужную папку и создаёт js- и css-файлы для любого компонента, который мы захотим создать. Подробнее об этом позже!</p><p>Пока что нам нужно настроить Elena. Во многих случаях можно пропустить этот шаг и просто использовать настройки по умолчанию. Однако мы ведём себя как глупые гуси и совмещаем документацию и компоненты в одном проекте, так что, возможно, придётся кое-что подкрутить. Плюс я люблю, когда конфиги явные, а не невидимые.</p><p>Создайте конфиг Elena по пути packages/components/elena.config.mjs:</p><p>Это говорит Elena, где искать наши компоненты (src), куда выводить собранные компоненты (dist) и где искать точку входа нашей библиотеки (src/index.js). Обратите внимание: все эти пути относительны директории packages/components, <b>а не</b> корня проекта. Наши инструменты Elena и библиотека компонентов самодостаточны.</p><p>Эта точка входа важна, если мы хотим импортировать все наши веб-компоненты через bundle.js, который генерирует Elena. Пока что создадим пустую.</p><p>Создайте packages/components/src/index.js. Пока что он может быть просто пустым или содержать комментарий-заглушку:</p><p>По мере создания компонентов мы сможем добавлять соответствующие export в этот файл, чтобы они попадали в наш production-бандл.</p><p>Убедитесь, что Elena работает: перейдите в корень проекта и выполните:</p><p>К сведениюЕсли вы запускаете это на Mac с Apple Silicon, то, скорее всего, столкнётесь с ошибкой. По моему опыту, это из-за зависимости Elena (lightningcss), которая немного кривая (простите за такую техническую терминологию). Если при попытке сборки вы получаете ошибку 'MODULE_NOT_FOUND', выполните следующее из корня проекта: Code languagebashCopy to clipboard rm -rf node_modules packages/components/node_modules package-lock.json &amp;&amp; npm install Это уничтожит папку node_modules и переустановит зависимости, разложив всё по своим местам. Если эта ошибка случилась однажды, то, скорее всего, придётся запускать это каждый раз при установке новой зависимости. Мне жаль. Управление пакетами — как всегда, Очень Приятное Занятие.</p><h2>И выдохнем…</h2><p>Отойдём на шаг назад, поставим чайник и посмотрим, что у нас есть. Ваша структура проекта должна выглядеть так:</p><p>Наша корневая папка по сути просто контейнер, так что особо беспокоиться о ней не стоит.</p><p>Наша папка docs — это место, где будет жить всё, связанное с VitePress. В конечном итоге это станет полноценной документацией дизайн-системы, и мы будем использовать её для предпросмотра и документирования наших компонентов по мере их создания.</p><p>Наша папка packages/components — это место, где мы будем работать со всем, связанным с компонентами. Папка packages/components/src — это место, где мы будем создавать компоненты, а index.js в ней — точка входа нашей библиотеки, где мы просто будем export'ировать любые компоненты, которые хотим включить в бандл.</p><p>Наша папка dist в packages/components — это место, где будут храниться собранная библиотека компонентов и манифест кастомных элементов. Затем мы сможем импортировать отсюда в наш проект VitePress так, будто это установленный пакет.</p><p>Однако чтобы дойти до этого, нам нужны какие-то реальные компоненты для распространения.</p><h2>Создаём наш первый компонент</h2><p>Теперь, когда всё настроено, мы наконец-то можем начать создавать компоненты! В этой статье мы будем держать всё просто и сосредоточимся на, возможно, самом распространённом компоненте: прекрасной кнопке.</p><p>По невероятному стечению обстоятельств ваш собственный веб-мастер Piccalilli, <a href="https://piccalil.li/author/andy-bell/">Andy Bell</a>, уже написал <i>великолепную</i> статью о <a href="https://piccalil.li/blog/how-i-build-a-button-component/">создании компонентов кнопок</a> на стандартном HTML и CSS. Мы будем опираться на эти принципы здесь, с небольшими изменениями, чтобы получить максимум от нашей настройки веб-компонентов.</p><p>Статья Andy отлично объясняет <i>почему</i> стоят за многими семантическими и структурными решениями, касающимися самих кнопок, поэтому я не буду углубляться в это слишком сильно. Andy прошёл путь, чтобы мы могли бежать. Какой человек.</p><h3>Композитные, примитивные и декларативные компоненты</h3><p>В основе концепции Elena «прогрессивные веб-компоненты» лежит разделение компонентов на три основные категории: <a href="https://elenajs.com/components/overview#_1-composite">композитные</a>, <a href="https://elenajs.com/components/overview#_2-primitive">примитивные</a> и <a href="https://elenajs.com/components/overview#_3-declarative">декларативные</a>. Документация Elena прекрасно объясняет различия подробно, но важно помнить, <i>что все это всё ещё просто веб-компоненты.</i> Нас не заставляют принимать нестандартные концепции или методы, скорее нас поощряют <i>думать</i> о наших компонентах в этих терминах.</p><p>Я позволю документации Elena сделать основную работу с этими определениями, но вот основные моменты:</p><ul><li><b>Композитные</b> компоненты оборачивают и расширяют свой внутренний HTML. Они отлично подходят для таких вещей, как слайдеры, аккордеоны, карточки и многослойные макеты — там, где вы чаще всего позволяете HTML и CSS делать основную работу и расширяете возможности с помощью JS в нужной области. Композитные компоненты также отлично подходят для <i>паттернов</i>, где мы можем захотеть объединить примитивные компоненты и HTML в переиспользуемые <i>«макро»</i> компоненты с определённым поведением. Подумайте о таких вещах, как диалоги, fieldsets и баннеры уведомлений — там, где структура и поведение фиксированы, но содержимое внутри остаётся гибким и определяется потребителем.</li><li><b>Примитивные</b> компоненты объявляют и рендерят свой собственный HTML и поставляются с собственной функцией render(). Это, вероятно, самые распространённые компоненты, которые мы будем использовать в дизайн-системе — подумайте о таких вещах, как кнопки, поля ввода, индикаторы загрузки, бейджи и т.д.</li><li><b>Декларативные</b> компоненты — это комбинация обоих типов и могут объединять Light DOM и декларативный Shadow DOM. Если мы не знаем, что нам <i>действительно</i> нужна инкапсуляция с Shadow DOM, мы можем практически игнорировать его для библиотек компонентов. Я не углублялся <i>слишком</i> сильно в это, но мои первые мысли таковы, что декларативные компоненты были бы отличны для полностью инкапсулированных компонентов, таких как веб-редакторы контента или блоки кода с подсветкой синтаксиса/редакторы, где инкапсуляция и изоляция часто критичны.</li></ul><p>На этот раз мы строим примитивный компонент. Наша кнопка будет объявлять и рендерить свой собственный HTML, и мы будем стилизовать её с помощью CSS в ограниченной области.</p><h3>Создаём каркас компонента</h3><p>Мы будем использовать CLI-помощник Elena для генерации папки и файлов, которые нам нужны для нашего компонента.</p><p>Пространства имён компонентов и пользовательские элементыМы используем сугубо учебный префикс my- для нашей кнопки, но зачем вообще нужен префикс? Это возвращает нас к тому, как пользовательские элементы требуют наличия - в имени тега, чтобы избежать конфликтов с нативными HTML-элементами. Если бы у нас был полный контроль, и мы создали компонент &lt;button&gt;, мы бы конфликтовали с настоящим HTML-элементом &lt;button&gt;, и у нас было бы Очень Плохое Время. Поэтому мы просто не можем этого делать — все наши пользовательские элементы должны быть в формате &lt;{prefix}-{component}&gt;.Жёсткого требования, чтобы наши файлы тоже были с дефисом, нет, но лично мне нравится аккуратность, когда имена файлов и папок совпадают с нашим фактическим элементом. Так что выберите префикс и придерживайтесь его. Для моей дизайн-системы Mindful Design я использую префикс md- — так что все мои пользовательские элементы выглядят примерно как &lt;md-button&gt;, &lt;md-card&gt; и т.д. Web Awesome использует wa-. Вы можете использовать всё, что пожелает ваше сердце. Главное — будьте последовательны.</p><p>Из папки packages/components выполните:</p><p>Затем вам будет предложено выбрать, какие функции и язык вы хотите. Для нашей кнопки нужно выбрать:</p><ul><li>Props</li><li>CSS-переменные</li><li>CSS-инкапсуляция</li><li>Комментарии в коде</li></ul><p>Нажмите Enter, затем выберите JavaScript в качестве языка.</p><p>Установите выходную директорию в src/. По умолчанию Elena использует src/components/, но нам не нужен такой уровень вложенности.</p><p>Это создаст каркас наших файлов с несколькими примерными значениями и комментариями, так что мы не будем смотреть на пустые файлы. Нажмите Enter после выбора функций, языка и директории, и Elena сгенерирует папку my-button с соответствующими JS и CSS файлами. О стилизации мы позаботимся позже, сейчас мы хотим спроектировать API нашего компонента.</p><p>Откройте следующий файл:</p><p>Здесь происходит много всего для простого boilerplate, но мы разберём каждый раздел по мере продвижения!</p><h3>Добавление props</h3><p>Компонентные <a href="https://elenajs.com/components/props">props</a> позволят нам управлять стилизацией и поведением компонента декларативным образом. Затем мы можем использовать эти props для создания вариантов наших компонентов. Для нашей кнопки давайте упростим и используем следующие props:</p><ul><li>variant: стилевой вариант нашей кнопки, например «primary», «danger»</li><li>disabled: отключена ли кнопка или нет</li><li>href: куда должна вести кнопка, также определяет, будет ли кнопка рендериться как ссылка или как кнопка</li></ul><p>Это небольшое подмножество props, которые потребуются кнопке в продакшене, но этого достаточно, чтобы двигаться дальше. Если после этого вы почувствуете себя уверенно, можете вернуться и добавить больше props — size или icon prop были бы отличной отправной точкой!</p><p>Давайте добавим эти props в наш компонент кнопки:</p><p>Объявление static props позволяет нам определить конечный массив props, которые будет принимать наш компонент. По умолчанию все эти props будут отражаться на нашем отрендеренном компоненте как HTML-атрибуты. Вам почти всегда нужно, чтобы это было так, особенно если вы используете нестандартные атрибуты вроде disabled, download и т.д.</p><p>Прямо под этим массивом вы найдёте заготовленные значения props по умолчанию, каждое с небольшим комментарием сверху. Давайте последуем примеру Elena и установим значения по умолчанию для добавленных нами props:</p><p>Комментарии над каждым определением — это JSDoc-комментарии. Они могут выглядеть немного непривычно, но позволяют документировать наши компоненты и props и могут служить источником истины для документирования API наших компонентов. Это также даёт нам немного «мягкой типизации» без необходимости использовать TypeScript. Большинство IDE будут подсвечивать или предупреждать вас, если вы установите prop в значение/тип, не указанный в синтаксисе JSDoc.</p><p>В приведённом выше примере мы определяем наш prop variant, задаём ему значение по умолчанию «default» и мягко типизируем его с помощью определения @type. В данном случае мы принимаем только одно из четырёх перечисленных значений.</p><p>На этом этапе это может показаться немного бессмысленным, но следите за своими JSDoc-комментариями по мере создания компонентов. Мы будем использовать их позже. Пока мы на этом, мы могли бы также задать более точное описание для нашего компонента.</p><p>Измените верхний комментарий в следующем файле:</p><p>Мы также удалили определения @cssprop из этого комментария. Они были сгенерированы, потому что мы выбрали «CSS Variables» при создании нашего компонента, и позволяют нам раскрыть кастомные свойства, используемые для стилизации наших компонентов. Если вы работаете над темизируемой или headless библиотекой компонентов, вы, возможно, захотите оставить их, в противном случае я предпочитаю пропускать определение этих свойств и не раскрывать их в своей документации.</p><p>Давайте взглянем на нашу функцию render():</p><p>Если у вас нет тяжёлого случая React Brain, вы, возможно, заметите хотя бы одну из пары проблем: во-первых, button — это не div. Дико, правда? Это не вина Elena, мы просто создали базовый компонент, и div — это, безусловно, самый распространённый HTML-элемент. Нам нужно самим отрендерить правильную, семантическую, доступную разметку.</p><p>Во-вторых, мы только что добавили href как prop, а это атрибут a, а не button. Нам нужно условно рендерить <i>либо</i> a, <i>либо</i> button в зависимости от того, установлен ли href.</p><h3>Условный рендеринг</h3><p>Дискуссия «должны ли ссылки когда-либо стилизоваться как кнопки?» старше, чем бородка вашего отчима, и точно так же как-то ещё сохраняется сквозь века. Я слишком стар и устал, чтобы беспокоиться об этом, а реальность такова, что кнопки-ссылки CTA — одна из самых распространённых вещей, которые вы увидите на сайте, в конкуренции только с баннерами cookie и плохой доступностью в своей повсеместности.</p><p>Так что вы будете делать это, нравится нам это или нет, и вам лучше делать это правильно.</p><p>Самый чистый подход к этому — абстрагировать наш рендеринг, добавив две новые функции:</p><p>Затем мы можем заменить функцию render() нашего компонента:</p><p>Супер просто: если href присутствует, это ссылка, если нет — это кнопка. Нам не нужно добавлять новые props, просто используем тот, что у нас уже есть.</p><p>Мы используем nothing в этой функции, и если вы попробуете собрать/запустить watch прямо сейчас, вы получите ошибку. Это потому, что nothing — это помощник Elena для безопасного рендеринга, ну, <i>ничего</i>.</p><p>Давайте импортируем его в начало нашей кнопки. Отредактируйте первую строку следующего файла:</p><p>Теперь давайте соберём нашу библиотеку компонентов, чтобы включить нашу новую кнопку в продакшенный bundle.js. Отредактируйте packages/components/src/index.js:</p><p>Затем из корня проекта выполните:</p><p>Если повезёт, сборка пройдёт без проблем, и мы наконец-то сможем встроить нашу кнопку в документацию.</p><h3>Предпросмотр нашей кнопки</h3><p>На данный момент у нас есть всё необходимое, чтобы отрендерить нашу кнопку и увидеть её на странице. Потребовалось немного настроек, чтобы дойти до этого, но мы сделали это!</p><p>Благодаря тому, как наш проект настроен, мы теперь можем подключать наши собранные компоненты так, как будто они являются отдельным пакетом. Нам просто нужно настроить VitePress для импорта бандла, который генерирует Elena, и сказать ему обрабатывать наши импортированные компоненты как веб-компоненты (по умолчанию VitePress ожидает Vue-компоненты).</p><p>Создайте docs/.vitepress/theme/index.js:</p><p>Это говорит нашей теме VitePress импортировать файлы бандла, которые сгенерировала Elena. @my-ds/components загружается асинхронно, так как это клиентская часть, а VitePress по умолчанию использует серверный рендеринг. @my-ds/components/dist/bundle.css импортируется напрямую в начале нашего файла, потому что это просто старый добрый CSS.</p><p>Примечание о серверном рендеринге (SSR)Если вы знаете, что вам нужен SSR, есть несколько способов включить его с Elena. В зависимости от вашего фреймворка/генератора сайта на выбор, вам, возможно, потребуется выполнить несколько дополнительных шагов конфигурации. Обратитесь к документации Elena за советами по SSR и на страницу интеграций с фреймворками для более продвинутых интеграций.</p><p>Далее обновите docs/.vitepress/config.mjs:</p><p>Это немного хакерский способ, но по сути он говорит VitePress рассматривать любой тег с - как пользовательский элемент вместо Vue-компонента. Учитывая, что пользовательские элементы требуют -, чтобы избежать конфликтов с нативными HTML-элементами, этого достаточно для наших целей.</p><p>Теперь давайте соберём нашу фактическую документацию по кнопке. Создайте docs/components/button.md:</p><p>Это должно дать нам всё необходимое для предпросмотра нашей кнопки! Запустите процесс разработки, если вы ещё этого не сделали:</p><p>Это запустит документацию VitePress в режиме разработки и одновременно запустит скрипт watch Elena, давая нам довольно удобный опыт live-reload. Перейдите на <a href="http://localhost:5173/components/button.html">http://localhost:5173/components/button.html</a>, и вы должны увидеть свою прекрасную кнопку!</p><p>Держите сервер разработки запущеннымКоманда npm run dev запустит ваш dev-сервер документации и будет держать Elena в фоне, отслеживая изменения компонентов. Вы будете получать live reloads всякий раз, когда вносите изменения, и теперь вы можете плавно вносить и тестировать изменения компонентов и документации.</p><p>Если вы откроете инспектор браузера и посмотрите на отрендеренную кнопку, вы увидите что-то вроде этого:</p><p>Наш хост-элемент &lt;my-button&gt; оборачивает разметку из своей функции render(), и мы имеем наш первый веб-компонент, отрендеренный в браузере! Я знаю, я знаю. Это выглядит совсем не круто, но оно там есть! Давайте придадим ему стиль.</p><h2>Стилизация нашей кнопки</h2><p>Если вы дошли до этого места, то, возможно, заметили явное отсутствие дискуссий о дизайн-токенах. Не потому, что они неважны, а потому что управление токенами и их распространение — это крайне объёмная тема, а эта статья и без того получается очень уж длинной. Скорее всего, мы разберём рабочие процессы с токенами в отдельном посте!</p><p>Пока что мы будем придерживаться простого подхода и использовать стили с ограниченной областью видимости Elena. Это позволяет нам частично нейтрализовать каскад в CSS и гарантировать, что стили не выйдут за пределы оформления отдельного компонента.</p><p>Мы также сделаем кое-что, чего я <b>не рекомендую</b> для production-компонентов, особенно если вы хотите строить темизируемые дизайн-системы, наследующие разумные глобальные стили (спойлер: вы хотите), — а именно, сбросим стили компонента перед применением собственных. В итоге мы получаем компонент, который не пропускает стили наружу (благодаря ограниченной области видимости) и не позволяет глобальным стилям проникать внутрь (благодаря сбросу на уровне компонента).</p><h3>Стили с ограниченной областью видимости</h3><p>Откройте следующий файл:</p><p>По умолчанию Elena генерирует at-правило @scope для любого создаваемого компонента. Вы <i>не обязаны</i> использовать стили с ограниченной областью видимости. Важно помнить: это <b>всё обычный CSS</b>. Мы не делаем ничего дикого или хрупкого вроде CSS-in-JS, мы просто используем конкретную стандартную возможность CSS. Вы с таким же успехом можете писать неограниченный CSS с пространствами имён и получить в целом те же результаты.</p><p>Более того, если вам нужно поддерживать браузеры, которые не поддерживают @scope, то использование пространств имён может быть тем самым подходом, который вам нужен. Для этого примера (и для моей собственной production-работы) меня вполне устраивает @scope — я считаю его гораздо более чистым способом стилизации компонентов.</p><p>Поскольку при создании компонента мы выбрали «CSS Encapsulation», вы видите, что Elena сгенерировала следующее:</p><p>По сути это означает, что наш компонент не будет наследовать стили из более высоких уровней каскада. В зависимости от вашего подхода к стилизации в дизайн-системе, это может быть как тем, что нужно, так и нет. Для <i>этого конкретного сценария</i> это самый простой способ гарантировать полный контроль над каждым компонентом. Однако во многих реальных сценариях вам действительно стоит <i>хотеть</i> некоторой степени наследования или стилей по умолчанию в компонентах.</p><p>Примечание об инкапсулированном сбросеИспользование all: unset и display: revert сбросит любые стили, определённые до тех пор, пока эти правила не встретятся. Это не предотвратит применение дальнейших неограниченных стилей в файлах или тегах </p>]]></content:encoded>
    </item>
    <item>
      <title>IPv6-зоны в URL: почему Go падает на fe80::%eth0 и как это чинить</title>
      <link>https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit</link>
      <comments>https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit</guid>
      <description><![CDATA[<p>Разбираем, как IPv6 link-local адреса с зонами ломают парсинг URL в Go, nginx и Python. Почему % нужно кодировать как %25 по RFC 6874 с 2013 года. Узнайте, как правильно собирать URL и не сломать продакшен.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit">IPv6-зоны в URL: почему Go падает на fe80::%eth0 и как это чинить</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Сетевые протоколы]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 05 Jun 2026 12:56:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>В URL с IPv6 link-local адресами символ % зоны интерфейса нужно кодировать как %25 — иначе парсер Go выбросит ошибку. Если вы пишете сервис, который ходит по локальной сети через IPv6, и ловите странную ошибку парсинга URL, скорее всего, вы столкнулись с одним из самых неочевидных граничных случаев современной работы с сетями.</p><p>В IPv6 каждый сетевой интерфейс получает <b>link-local адрес</b> из диапазона fe80::/10 (первые 10 бит фиксированы, остальное — адрес интерфейса). Если у машины два интерфейса — например, Ethernet и Wi-Fi — оба будут в одном и том же префиксе. Вопрос: как операционная система понимает, к какому именно интерфейсу адресовать пакет? Ответ — <b>зоны (scopes)</b>.</p><p>В IPv6 зона интерфейса записывается через %: fe80::4%eth0. Это нужно, чтобы различать link-local адреса на разных сетевых интерфейсах.</p><p>В URL зона попадает внутрь квадратных скобок: [fe80::4%eth0]:80. Но символ % в URL — это начало percent-encoding, поэтому парсер ломается.</p><p>Решение — экранировать % как %25: [fe80::4%25eth0]:80. Это поведение зафиксировано в RFC 6874.</p><p>Проблема затрагивает не только Go, но и nginx, Python requests и браузеры. Поддержка зон в HTTP-клиентах остаётся фрагментарной.</p><h2>Как зоны работают в IPv6</h2><p>Зона (или scope ID) — это механизм, позволяющий ядру отличать адреса из пересекающихся диапазонов. Для link-local адресов fe80::/10 он критичен: без него роутинговая таблица не поймёт, через какой интерфейс отправлять трафик.</p><p>Формат зоны зависит от ОС. В Linux это имя интерфейса — eth0, wlan0, ens192. В Windows — числовой идентификатор интерфейса. Полный адрес выглядит так:</p><p>Квадратные скобки отделяют хост от порта — иначе двоеточия IPv6-адреса спутаются с разделителем порта.</p><h2>Конфликт зон и URL</h2><p>Теперь вставим этот адрес в URL. На первый взгляд всё просто:</p><p>Но попробуем распарсить его в Go:</p><p>Получаем ошибку:</p><p>Что произошло? В URL любой символ, не входящий в разрешённый набор, должен быть <b>percent-encoded</b>. Пробел превращается в %20, кириллица — в последовательности вроде %D0%90. Парсер видит %e и пытается декодировать его как hex-последовательность. et — не валидный байт, поэтому URL отклоняется.</p><h2>Почему Go падает и как это чинить</h2><p>С точки зрения стандарта Go ведёт себя корректно. RFC 3986 определяет URL-грамматику, а RFC 6874 специально дополняет её для IPv6-зон: символ % перед zone ID должен быть сам закодирован как %25.</p><p>Правильный URL выглядит так:</p><p>Проверяем в Go:</p><p>Вывод:</p><p>Go корректно декодирует %25 обратно в % при извлечении хоста. То есть библиотека поддерживает RFC 6874, но <b>требует от вызывающего кода заранее закодировать зону</b>.</p><h2>RFC 6874: это не баг, а фича</h2><p>В RFC 6874 формально описан синтаксис IPv6-адресов с зонами в литералах URL. Ключевой фрагмент:</p><p>То есть зона записывается не как %eth0, а как %25eth0. Это выглядит ужасно с точки зрения пользовательского опыта, но таково решение стандартизации: совместимость с существующей URL-грамматикой важнее эргономики.</p><blockquote>Наша индустрия меня удивляет. Стандарт говорит: чтобы записать обычный символ процента в адресе, нужно его самого закодировать процентами. Это ужасно, но, похоже, это граничный случай, который касается не только Go.</blockquote><p>И действительно, та же проблема есть и в других инструментах:</p><ul><li><b>nginx</b> — <a href="https://trac.nginx.org/nginx/ticket/623">тикет #623</a>, созданный более десяти лет назад; проблема отсутствия поддержки link-local адресов с зонами до сих пор актуальна.</li><li><b>Python requests</b> — <a href="https://github.com/psf/requests/issues/6808">issue #6808</a>: даже при ручном кодировании % как %25 библиотека некорректно обрабатывает IPv6-зоны в URL, потому что urllib3 декодирует %25 обратно в %.</li><li><b>Браузеры</b> — draft Schinazi объясняет, почему зоны ломают концепцию origin, и рекомендует использовать mDNS вместо прямого указания link-local адресов в URI.</li></ul><h2>Что делать разработчику</h2><p>Если ваше Go-приложение работает с локальными IPv6-адресами — например, подключается к сервисам в Docker-сети, IoT-устройствам или внутренним API через link-local — учитывайте следующее:</p><ol><li>Перед передачей IPv6-адреса с зоной в url.Parse всегда экранируйте % как %25.</li><li>Используйте net.JoinHostPort для сборки host:port — он корректно оборачивает IPv6 в скобки, но не кодирует зону. Дополнительное кодирование остаётся на вас.</li><li>Если адрес приходит от пользователя, валидируйте его до парсинга: зона должна содержать только допустимые символы (имя интерфейса в Linux, числовой ID в Windows).</li><li>Тестируйте на реальных интерфейсах с разными зонами, чтобы убедиться, что кодирование работает корректно в вашей среде.</li></ol><p><b>На заметку:</b><br />Если вы пишете HTTP-клиент для embedded-устройств или промышленных контроллеров, которые общаются через link-local IPv6, ручное кодирование зоны — не костыль, а необходимость. Большинство библиотек не делают этого автоматически.</p><h2>FAQ</h2><h2>Выводы</h2><p>IPv6-зоны — редкий, но живучий граничный случай. Если вы пишете сетевой код на Go, который должен работать в гетерогенных средах — Docker, Kubernetes, embedded-системы, промышленные сети — знайте, что fe80::1%eth0 в URL превращается в fe80::1%25eth0. Это не баг парсера, а требование стандарта RFC 6874.</p><p>Инкапсулируйте кодирование зоны во вспомогательную функцию и всегда прогоняйте IPv6-адреса через неё перед сборкой URL. Экономия пяти минут сейчас обернётся часом отладки в продакшене, когда сервис внезапно не сможет достучаться до соседнего контейнера по link-local.</p><p><b>Источники:</b><br />• <a href="https://xeiaso.net/notes/2026/ipv6-zones-go-url/">Xe Iaso — IPv6 zones in Go URLs</a><br />• <a href="https://datatracker.ietf.org/doc/html/rfc6874">RFC 6874 — Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers</a><br />• <a href="https://datatracker.ietf.org/doc/html/draft-schinazi-httpbis-link-local-uri-bcp-03">draft-schinazi-httpbis-link-local-uri-bcp-03 — IPv6 Link-Local URIs</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Пора прощаться с ESLint? Как Oxlint меняет правила игры в JavaScript-разработке</title>
      <link>https://tproger.ru/articles/pora-proshhatsya-s-eslint-kak-oxlint-menyaet-pravila-igry-v-javasc</link>
      <comments>https://tproger.ru/articles/pora-proshhatsya-s-eslint-kak-oxlint-menyaet-pravila-igry-v-javasc?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pora-proshhatsya-s-eslint-kak-oxlint-menyaet-pravila-igry-v-javasc</guid>
      <description><![CDATA[<p>Oxlint на Rust обгоняет ESLint в 50–100 раз по скорости и требует минимальной настройки. Разбираем бенчмарки и сценарии миграции.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pora-proshhatsya-s-eslint-kak-oxlint-menyaet-pravila-igry-v-javasc">Пора прощаться с ESLint? Как Oxlint меняет правила игры в JavaScript-разработке</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 04 Jun 2026 12:05:14 GMT</pubDate>
      <content:encoded><![CDATA[<p>Линтер <b>Oxlint</b>, написанный на Rust, в 50–100 раз быстрее привычного ESLint и работает сразу после установки. Разбираем, когда миграция оправдана, а когда лучше подождать.</p><p><b>ESLint</b> — это де-факто стандарт статического анализа JavaScript-кода. Инструмент работает поверх Node.js и V8, поддерживает сотни плагинов и позволяет настраивать правила под любой проект. По данным опроса State of JavaScript 2025, ESLint остаётся самым популярным вспомогательным инструментом среди фронтенд-разработчиков.</p><p>Новый проект развивается в рамках экосистемы <b>Oxc</b>, поддерживаемой командой <b>VoidZero</b>.</p><p>Oxlint на Rust обгоняет ESLint в 50–100 раз на крупных репозиториях вроде Vue Core и React Router.</p><p>Из коробки включено 107 правил, тогда как ESLint требует ручной настройки даже для базовых сценариев.</p><p>Поддержка ESLint-плагинов экспериментальная, но список доступных правил постоянно растёт.</p><p>Миграция возможна постепенно: оба линтера можно запускать параллельно.</p><p>Если ваш проект завязан на редкие плагины или пользовательские правила — спешить не стоит.</p><h2>Почему ESLint начинает раздражать</h2><p>Несмотря на зрелость экосистемы, у ESLint накопился приличный багаж архитектурных ограничений:</p><ul><li>Производительность. Код ESLint выполняется в однопоточном режиме поверх JavaScript-движка. В небольших проектах это незаметно, но в монорепозиториях с сотнями тысяч строк проверка легко растягивается на две минуты и больше.</li><li>Конфигурационный ад. Новичкам приходится разбираться в иерархии конфигов, flat config, shared presets и compatibility layers. Документация исчерпывающая, но порог входа остаётся высоким.</li><li>Минимум из коробки. Базовая установка ESLint практически ничего не проверяет. Для получения хоть какой-то пользы нужно ставить плагины, изучать правила и собирать конфигурацию с нуля — в отличие от Prettier или Biome, которые работают сразу после установки.</li></ul><h2>Чем Oxlint лучше привычного линтера</h2><h3>Скорость, которую можно измерить</h3><p>Главное преимущество Oxlint — скорость. В тестах на репозитории <b>Vue Core</b> с type-aware правилами Oxlint справляется за <b>1,3 секунды</b>, тогда как ESLint с typescript-eslint тратит <b>133,8 секунды</b>. Это почти в 100 раз быстрее. На репозитории <b>React Router</b> разрыв меньше, но всё равно впечатляет: <b>435 мс</b> против <b>29,5 с</b> — ускорение в 68 раз.</p><h3>Type-aware линтинг без тормозов</h3><p>ESLint для type-aware правил использует typescript-eslint, который перед проверкой запускает полный анализ через tsc. Это наследует все накладные расходы компилятора TypeScript. Oxlint делает это иначе: type-aware функциональность реализована через oxlint-tsgolint на Go, который в связке с TypeScript 7 и компилятором tsgo работает в 20–40 раз быстрее привычного пайплайна.</p><h3>Настройка за минуту, а не за час</h3><p>После установки Oxlint сразу активирует 107 правил. Конфигурация проще, документация понятнее, а сообщения об ошибках структурированы так, что и человек, и LLM-ассистент разберутся с первого взгляда.</p><h3>Постепенная миграция без боли</h3><p>Oxlint не требует выбросить ESLint в один день. Инструменты можно запускать параллельно: Oxlint берёт быструю проверку на pre-commit, а ESLint остаётся в CI до полного перехода. Экспериментальная поддержка JavaScript-плагинов ESLint уже работает, хотя и не покрывает всю экосистему.</p><h2>Реальные цифры: бенчмарки на популярных репозиториях</h2><p>Автор оригинального материала воспроизвёл тесты на ноутбуке HP EliteBook 1040 G7 (16 ГБ ОЗУ, 4 физических ядра, 8 потоков). Результаты для Vue Core с type-aware правилами:</p><p>Результаты для React Router (без type-aware правил):</p><p>Цифры подтверждают заявленные разработчиками 50–100-кратное ускорение. Для разработчика это разница между «пойду за кофе, пока линтер работает» и «результат на экране мгновенно».</p><h2>Когда ESLint всё ещё нужен</h2><p>Несмотря на впечатляющие цифры, спешить со сносом ESLint не всегда разумно. Вот сценарии, где старый инструмент остаётся предпочтительнее:</p><ul><li>Редкие плагины и пользовательские правила. Если ваш проект завязан на специфические ESLint-плагины, которых ещё нет в Oxlint, миграция потребует дополнительной работы.</li><li>Малые проекты. В репозиториях до 10–20 тысяч строк разница между 1 секундой и 30 секундами линтинга не критична.</li><li>Сложные рабочие процессы. Глубокая интеграция ESLint в CI/CD, пользовательские форматтеры и специфические пайплайны могут быть дорого переносить.</li><li>Сообщество и экосистема. ESLint остаётся доминирующим линтером. Вокруг него больше обучающих материалов, примеров конфигураций и поддержки со стороны LLM-ассистентов.</li></ul><h2>Как мигрировать с ESLint на Oxlint</h2><p>Команда Oxlint подготовила утилиту @oxlint/migrate, которая автоматически преобразует конфигурацию ESLint в формат Oxlint. Выбор пути зависит от текущего состояния проекта:</p><ol><li>Для ESLint v9/v10+ с flat config: запустите npx @oxlint/migrate — утилита преобразует поддерживаемые правила и сообщит о несовместимых.</li><li>Для ESLint v8 и старше (в v10 поддержка legacy-конфигов полностью удалена): сначала мигрируйте на flat config через npx @eslint/migrate-config, затем примените @oxlint/migrate.</li><li>Если нужны type-aware правила: добавьте флаг --type-aware к команде npx @oxlint/migrate и установите oxlint-tsgolint.</li><li>Для экспериментальной поддержки JS-плагинов: используйте флаг --js-plugins в команде npx @oxlint/migrate.</li><li>Не уверены в безопасности? Запустите оба линтера параллельно на несколько недель и сравните результаты.</li></ol><p><b>Совет:</b><br />Начните миграцию с новых модулей или микрофронтендов, а не с устаревшего кода, где линтер и так давно отключён.</p><h2>Выводы</h2><p>ESLint не умер, но его эпоха безраздельного господства подходит к концу. Oxlint демонстрирует, что статический анализ JavaScript может быть быстрым, простым в настройке и дружелюбным к разработчику. Для большинства современных проектов переход уже оправдан экономикой времени: сэкономленные минуты на каждом коммите за год превращаются в десятки часов продуктивной работы.</p><blockquote>Для большинства современных проектов Oxlint — это уже не перспективная альтернатива, а вполне зрелый инструмент по умолчанию.</blockquote><p>Источник: <a href="https://blog.logrocket.com/retire-eslint-migrate-oxlint/" rel="noopener noreferrer">LogRocket — Retire ESLint: How (and why) to migrate to Oxlint</a></p><p>Репозиторий проекта: <a href="https://github.com/oxc-project/oxc" rel="noopener noreferrer">github.com/oxc-project/oxc</a>. Документация: <a href="https://oxc.rs" rel="noopener noreferrer">oxc.rs</a>.</p><p>Попробуйте запустить npx @oxlint/migrate на своём проекте и сравните цифры. Возможно, вы больше никогда не захотите ждать, пока закончится npm run lint.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как правильно использовать поля HTML-форм: гайд для разработчиков</title>
      <link>https://tproger.ru/articles/kak-pravilno-ispolzovat-polya-html-form-polnyj-gajd</link>
      <comments>https://tproger.ru/articles/kak-pravilno-ispolzovat-polya-html-form-polnyj-gajd?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-pravilno-ispolzovat-polya-html-form-polnyj-gajd</guid>
      <description><![CDATA[<p>Разбираем типы полей HTML-форм, правила доступности, ARIA-атрибуты и лучшие практики. Узнайте, как создавать удобные и конверсионные формы для любых устройств.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-pravilno-ispolzovat-polya-html-form-polnyj-gajd">Как правильно использовать поля HTML-форм: гайд для разработчиков</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Фронтенд-разработка с нуля]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 04 Jun 2026 09:55:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>Неправильно свёрстанная форма — серьёзный источник раздражения пользователей на сайте. Поле email без подходящей клавиатуры на телефоне, чекбокс без label, который невозможно попасть пальцем, или форма, которая отправляется при случайном нажатии Enter — всё это ежедневно встречается даже на крупных проектах. Разбираем, как избежать этих ошибок и сделать формы удобными для всех пользователей.</p><h2>Что такое поля форм</h2><p>Поля форм — это интерактивные элементы HTML, через которые пользователь взаимодействует с веб-страницей. Браузер отображает их по-разному в зависимости от типа: для email показывает клавиатуру с символом @, для даты — календарь, для файла — диалог выбора документа.</p><p>Главное правило: под каждую задачу существует своё поле. Использовать универсальный &lt;input type="text"&gt; везде — значит лишать пользователя встроенных удобств браузера.</p><p>{'id': 'a94adbf9d2', 'data': {'text': '<b>Правильный тип input</b> — залог удобства: браузер сам подставит нужную клавиатуру и проверит формат.'}, 'type': 'paragraph'}</p><p>{'id': 'd3748dda0e', 'data': {'text': '<b>Label обязателен</b> для каждого поля: связывайте его через атрибут for с id поля.'}, 'type': 'paragraph'}</p><p>{'id': 'c924682827', 'data': {'text': '<b>Группируйте связанные поля</b> в &lt;fieldset&gt; с &lt;legend&gt; — это помогает средствам чтения с экрана и структурирует форму.'}, 'type': 'paragraph'}</p><p>{'id': '49afc5a27c', 'data': {'text': '<b>Не забывайте name</b>: без него данные не попадут в запрос при отправке формы.'}, 'type': 'paragraph'}</p><p>{'id': 'ab33c8052b', 'data': {'text': '<b>Используйте &lt;button type="submit"&gt;</b> вместо устаревшего &lt;input type="submit"&gt; — это гибче и семантичнее.'}, 'type': 'paragraph'}</p><h2>Основные элементы форм</h2><h3>input — универсальный инструмент ввода</h3><p>Элемент &lt;input&gt; — самый распространённый в формах. Его внешний вид и поведение полностью зависят от атрибута type. Браузер поддерживает свыше 20 типов: от классического text до специализированных date, tel, range и даже color.</p><p>Когда вы выбираете конкретный тип, браузер берёт на себя три задачи: отображает подходящий интерфейс, показывает оптимальную экранную клавиатуру на мобильных устройствах и применяет встроенную проверку. Например, type="email" проверит наличие символа @ до отправки на сервер.</p><p>Вот типы input, которые стоит знать каждому фронтенд-разработчику:</p><ul><li>text — текстовая строка, базовый тип.</li><li>email — проверяет наличие @ и домена, показывает email-клавиатуру.</li><li>tel — цифровая клавиатура на мобильных устройствах.</li><li>number — ограничивает ввод числами, добавляет стрелки.</li><li>date — нативный календарь браузера.</li><li>checkbox и radio — выбор одного или нескольких вариантов.</li><li>file — загрузка файлов с нативным диалогом выбора.</li><li>range — ползунок для выбора значения из диапазона.</li><li>color — нативный выбор цвета.</li><li>search — поле поиска с кнопкой очистки.</li></ul><p>Атрибут required делает поле обязательным для заполнения, а pattern позволяет задать регулярное выражение для проверки введённых данных без JavaScript.</p><h3>label — связываем текст с полем</h3><p>Без подписи поле ввода теряет смысл. Элемент &lt;label&gt; решает эту задачу и одновременно делает форму доступной для пользователей с ограничениями зрения.</p><p>Есть два способа связать label с полем. Первый — явный: атрибут for на label должен совпадать с id на input. Второй — вложенный: input размещается внутри label. Оба варианта работают, но явная связь через for гибче: позволяет располагать label и input в разных частях разметки.</p><p><b>Важно:</b><br />Клик по label автоматически переводит фокус в связанное поле. Это удобно на десктопе и критично на мобильных устройствах, где площадь касания имеет значение.</p><h3>textarea — когда одной строки мало</h3><p>Для длинных текстов — комментариев, отзывов, описаний — используйте &lt;textarea&gt;. В отличие от &lt;input&gt;, он поддерживает переносы строк и растягивается по содержимому. Атрибуты rows и cols задают начальные размеры, а CSS — финальное оформление.</p><h3>select и datalist — выбор из вариантов</h3><p>Когда нужно предложить пользователю готовый список вариантов, на помощь приходит &lt;select&gt;. Он отображает выпадающий список, в котором можно выбрать один или несколько пунктов. По умолчанию выбран первый элемент, но через атрибут selected можно задать другой.</p><p>Альтернатива — &lt;datalist&gt;. Он работает как автодополнение: пользователь может как выбрать вариант из списка, так и ввести свой собственный текст. Это удобно для полей вроде «профессия» или «название компании», где невозможно предусмотреть все варианты.</p><h3>fieldset и legend — группируем поля</h3><p>Формы с десятком полей выглядят как стена текста. Чтобы структурировать их, используйте &lt;fieldset&gt; с обязательным дочерним элементом &lt;legend&gt;. Такая группировка помогает пользователям ориентироваться и критична для средств чтения с экрана: они объявляют legend перед каждым полем в группе.</p><h3>ARIA-атрибуты для сложных форм</h3><p>Для скринридеров и пользователей с ограничениями зрения важно не только правильное использование label, но и дополнительные ARIA-атрибуты. Например, aria-required="true" сообщает о необходимости заполнения, а aria-describedby связывает поле с текстом подсказки или сообщения об ошибке.</p><p>Атрибут aria-live="polite" на контейнере с ошибками позволяет скринридеру озвучить сообщение без прерывания текущего действия пользователя. Это особенно важно для динамических форм, где ошибки появляются после асинхронной проверки на сервере.</p><h3>Как отправить форму</h3><p>Для отправки данных используйте &lt;button type="submit"&gt;. Это семантично, стилизуется гибче, чем &lt;input type="submit"&gt;, и поддерживает вложенный HTML-контент — например, иконку рядом с текстом.</p><p><b>Важно:</b><br />Если у кнопки не указан атрибут type, браузер считает её кнопкой отправки по умолчанию. Чтобы избежать случайной отправки, всегда явно указывайте type="button" для кнопок, которые не должны отправлять форму.</p><p>Помимо клика по кнопке, форма отправляется при нажатии клавиши Enter в однострочных полях ввода. В многострочном &lt;textarea&gt; Enter добавляет перенос строки. Это стандартное поведение браузера, которое стоит учитывать при проектировании многошаговых форм: случайная отправка на середине заполнения раздражает пользователей.</p><h2>Чек-лист: правильная форма за 5 минут</h2><ul><li>Каждое поле имеет связанный &lt;label&gt; через for и id.</li><li>Выбран подходящий type для &lt;input&gt; — не везде text.</li><li>У всех полей есть атрибут name, иначе данные не уйдут на сервер.</li><li>Связанные поля объединены в &lt;fieldset&gt; с &lt;legend&gt;.</li><li>Для длинных текстов используется &lt;textarea&gt;, а не многострочный input.</li><li>Кнопка отправки — &lt;button type="submit"&gt;, а не устаревший input.</li><li>Форма работает без JavaScript: базовая проверка и отправка происходят на уровне HTML.</li></ul><h2>Выводы</h2><p>Поля HTML-форм — это не просто визуальные элементы, а полноценный интерфейс взаимодействия пользователя с вашим приложением. Правильный выбор типов input, связь через label, группировка в fieldset, ARIA-атрибуты и семантичная кнопка отправки — всё это влияет на удобство, доступность и конверсию.</p><blockquote>Доступность не добавляется в проект в конце — она закладывается на этапе разметки. Правильно свёрстанная форма работает для всех пользователей без дополнительных усилий.</blockquote><p>Если хотите углубиться в тему — изучите <a href="https://web.dev/learn/forms/">полный курс по формам от Google</a>. Там разбираются проверка данных, оформление, доступность и даже usability-тестирование поведения пользователей при заполнении форм.</p><p>Источник: <a href="https://web.dev/learn/forms/form-fields/">web.dev — Help users enter data in forms</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое REST API и почему ваш — вероятно, не REST</title>
      <link>https://tproger.ru/translations/chto-takoe-rest-api-i-pochemu-vaw-veroyatno-ne-rest</link>
      <comments>https://tproger.ru/translations/chto-takoe-rest-api-i-pochemu-vaw-veroyatno-ne-rest?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/chto-takoe-rest-api-i-pochemu-vaw-veroyatno-ne-rest</guid>
      <description><![CDATA[<p>6 ограничений Филдинга и почему большинство JSON API соответствуют лишь 2–3 из них. Проверьте, сколько из них выполняет ваш API — с примерами кода.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/chto-takoe-rest-api-i-pochemu-vaw-veroyatno-ne-rest">Что такое REST API и почему ваш — вероятно, не REST</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Паттерны проектирования]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 14 May 2026 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Большинство разработчиков хотя бы раз строили «REST API». Мало кто читал диссертацию, которая его определяет. Этот разрыв между популярным пониманием и оригинальной спецификацией порождает повторяющиеся архитектурные проблемы и нестабильность API.</p><p>REST API — это веб-сервис, удовлетворяющий шести архитектурным ограничениям, выведенным Роем Филдингом в докторской диссертации «Architectural Styles and the Design of Network-based Software Architectures» (UC Irvine, 2000 год). Начав с «нулевого стиля» — пустого набора без ограничений — Филдинг добавлял каждое из них последовательно, анализируя порождаемые ими свойства распределённых гипермедиа-систем (систем, где переходы между состояниями описаны прямо в ответах сервера). Результат получил название «Передача репрезентативного состояния» (Representational State Transfer).</p><p>Индустрия взяла название и проигнорировала большинство ограничений. «REST» теперь означает «любой API, который отправляет JSON по HTTP». Если вы строите публичный API или API для команд за пределами вашей организации — пропущенные ограничения начинают стоить денег.</p><p>REST — это шесть архитектурных ограничений, сформулированных Роем Филдингом в 2000 году, а не «любой JSON-over-HTTP API».</p><p>Большинство API выполняют лишь 2–3 ограничения из шести: клиент-сервер, stateless и частично слоистую систему.</p><p>Самое игнорируемое ограничение — HATEOAS: сервер передаёт клиенту список доступных действий прямо в ответе.</p><p>HATEOAS решает три дорогостоящие проблемы: пагинацию, версионирование API и обнаруживаемость ресурсов.</p><p>Для небольшой команды с одним потребителем пропуск HATEOAS оправдан. Для публичного API — нет.</p><h2>Шесть ограничений REST API: разбор по порядку</h2><h3>Ограничение 1: Клиент-сервер</h3><p>Клиент и сервер имеют разные зоны ответственности. Клиент отвечает за интерфейс, сервер — за данные и логику. Большинство API справляются с этим по умолчанию. Нарушение появляется, когда сервер начинает диктовать, как клиент должен <i>отображать</i> информацию.</p><p>Например, если API возвращает displayOrder: 3 и buttonColor: "#ff0000" для какого-либо действия — это нарушение. Порядок отображения должен следовать из позиции элементов в ответе. Цвет должен определяться семантическим свойством вроде class: ["danger"], которое каждый клиент интерпретирует самостоятельно.</p><h3>Ограничение 2: Stateless (без состояния)</h3><p>Каждый запрос содержит всю информацию, необходимую серверу для его обработки. Сервер не хранит состояние сессии между вызовами.</p><p>Если вы отправляете GET /path-1 с сессионной cookie, и сервер ищет её в памяти, чтобы получить ваш ID пользователя — это серверное состояние. Stateless-версия включает ID прямо в запрос: JWT или тело POST-запроса переносят его вместе с запросом и могут вернуть в ответе для повторного использования клиентом.</p><h3>Ограничение 3: Кэшируемость</h3><p>Ответы должны быть явно или неявно помечены как кэшируемые или некэшируемые. Клиент или промежуточный узел может повторно использовать закэшированные ответы, не обращаясь к серверу. Филдинг рассматривал кэшируемость как архитектурную задачу первого класса, повышающую эффективность и воспринимаемую производительность за счёт снижения средней задержки.</p><p>Большинство JSON API полностью игнорируют кэширование. Вы отправляете GET /articles/42, а в ответе нет ни Cache-Control, ни ETag, ни Last-Modified. Клиент обращается к серверу каждый раз, даже если статья не менялась неделями.</p><h3>Ограничение 4: Единый интерфейс (Uniform Interface)</h3><p>Это главное ограничение. Филдинг разбил его на четыре подограничения — три описываются ниже, четвёртое (HATEOAS) вынесено в отдельный раздел из-за его значимости.</p><p><b>4.1 URI идентифицируют ресурсы.</b> Единообразие здесь — это сама спецификация URI: схема, authority, путь, запрос, фрагмент. Ограничение ничего не говорит о структуре сегмента пути: /articles/42, /x?id=42 и /a/b/c — всё это валидные URI. «Используйте чистые URL-пути» — популярное соглашение и хороший SEO-инструмент, но не то, что требует Филдинг.</p><p><b>4.2 Управление ресурсами через представления.</b> Вы выполняете GET в /whatever, чтобы получить представление ресурса. Заголовок Content-Type сообщает серверу формат тела запроса. Заголовок Accept сообщает, какие медиатипы (форматы обмена данными) поддерживает клиент для ответа.</p><p><b>4.3 Самоописывающие сообщения.</b> Ответ с Content-Type: application/vnd.collection+json сообщает клиенту, как разбирать тело, без каких-либо предположений.</p><h3>Ограничение 4.4: HATEOAS — то, что пропускают почти все</h3><p>HATEOAS (Hypermedia As The Engine Of Application State) — четвёртое подограничение Uniform Interface. С первыми тремя большинство API справляются. HATEOAS — место, где останавливается почти каждый.</p><p>Разница хорошо видна на примере API для списка чтения. Без HATEOAS вы получаете просто данные, похожие на запись в базе:</p><p>Клиент ничего не знает о том, что он может сделать дальше. Чтобы отметить статью как прочитанную, клиент уже должен знать endpoint: PATCH /articles/42 с {"status": "read"}. Разработчик захардкодил эти знания, прочитав документацию. Сам API их не сообщил.</p><p>С HATEOAS сервер сообщает клиенту о доступных действиях в стандартизированном виде. Вот тот же ответ с использованием <a href="https://github.com/kevinswiber/siren">Siren</a> — одного из стандартизированных медиатипов для гипермедиа-API:</p><p>Клиент не хардкодит URL и HTTP-методы. Массив actions сообщает, что можно сделать. Навигация приходит из links. Если статья уже прочитана — сервер исключает действие mark-as-read из ответа. Кнопка исчезает в UI. Без единого условного выражения в клиентском коде.</p><p>Сервер добавляет новое действие — и каждый клиент подхватывает его при следующем запросе, без деплоя. Это принципиальное отличие: сервер управляет доступными переходами состояния.</p><h3>Ограничение 5: Слоистая система</h3><p>Клиент не может определить, общается ли он с конечным сервером или с промежуточным узлом. Балансировщики нагрузки, CDN и API-шлюзы должны быть прозрачны для вызывающей стороны. Большинство API выполняют это ограничение автоматически. Самый распространённый вид нарушения — когда сообщения об ошибках раскрывают имя хоста бэкенд-сервиса, тем самым нарушая прозрачность слоёв.</p><h3>Ограничение 6: Код по требованию (необязательное)</h3><p>Сервер может передавать исполняемый код клиенту. Думайте о JavaScript, подключаемом через тег &lt;script&gt; на веб-странице. Для API это ограничение почти не применимо. Филдинг сделал его единственным необязательным.</p><h2>Что HATEOAS решает на практике</h2><p>Филдинг разработал HATEOAS для решения тех самых проблем, с которыми API-команды сейчас борются вручную, многократно и каждый раз по-разному.</p><h3>Пагинация</h3><p>Без HATEOAS каждый API изобретает собственную схему. Один использует page и pageSize. Другой — offset и limit. Третий — токены на основе курсора. С HATEOAS сервер включает ссылку с отношением «следующая страница». Клиент следует этому отношению. Схема пагинации может измениться, не сломав ни одного клиента: клиент не знал деталей схемы и не знает формата URL.</p><h3>Версионирование</h3><p>Без HATEOAS команды версионируют API через URL-пути (/v1/, /v2/) или кастомные заголовки вроде X-API-Version. Поддержка нескольких версий занимает месяцы, клиенты привязываются к версии и ломаются при её выводе из эксплуатации. С HATEOAS сервер вводит новые действия, добавляя ссылки. Старые ссылки продолжают работать.</p><h3>Обнаруживаемость</h3><p>Без HATEOAS первый шаг разработчика — чтение Swagger-документации, второй — хардкодинг каждого endpoint в клиент. С HATEOAS корень API возвращает ссылки на все доступные ресурсы. Клиент исследует API так же, как браузер исследует веб-сайт.</p><h2>Сколько ограничений выполняет ваш API</h2><p>Итого шесть ограничений. Большинство API удовлетворяют двум-трём: клиент-сервер, слоистую систему и частичную безгосударственность. Большинство нарушают кэшируемость по умолчанию. Большинство полностью игнорируют HATEOAS.</p><ul><li><b>Клиент-сервер</b> — разделение ответственности за интерфейс и данные</li><li><b>Stateless</b> — каждый запрос самодостаточен, без серверных сессий</li><li><b>Кэшируемость</b> — явные заголовки Cache-Control, ETag, Last-Modified</li><li><b>Единый интерфейс</b> — URI, представления, самоописывающие сообщения и HATEOAS</li><li><b>Слоистая система</b> — прозрачность промежуточных узлов</li><li><b>Код по требованию</b> — опционально, для API почти не применимо</li></ul><p>Это не оценка. Это карта компромиссов, которые вы приняли — намеренно или случайно. Для небольшой команды с одним потребителем и Slack-каналом для координации пропуск HATEOAS оправдан. Публичный API с сотнями потребителей платит за каждый пропущенный раунд миграции версий. Подробнее об эволюции REST-архитектуры — в <a href="https://ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">главе 5 диссертации Филдинга</a>.</p><h2>Выводы</h2><blockquote>Я разочарован тем, что многие не знакомы с 15-летними исследованиями в области гипермедиа, которые стоят за REST. Большинство так называемых REST API — это просто удалённые вызовы процедур через HTTP.</blockquote><p>Пройдитесь по шести ограничениям и посчитайте, сколько из них выполняет ваш API. Это даст не оценку, а карту принятых компромиссов — осознанных или случайных. Упражнение отвечает на один вопрос: ваш API — это Representational State Transfer или просто HTTP-транспорт, закрытый для расширения?</p><p>Оригинальная статья: <a href="https://fagnerbrack.com/what-is-a-rest-api-and-why-yours-probably-isnt-one-7e5fb65ece4d">Fagner Brack — What Is a REST API, and Why Yours Probably Isn't One</a>. Первоисточник: <a href="https://ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">Глава 5 диссертации Роя Филдинга, UC Irvine</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Denwer SE: Возрождение легендарного локального веб-сервера на современном стеке</title>
      <link>https://tproger.ru/articles/denwer-se-vozrozhdenie-legendarnogo-lokalnogo-veb-servera-na-so</link>
      <comments>https://tproger.ru/articles/denwer-se-vozrozhdenie-legendarnogo-lokalnogo-veb-servera-na-so?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Александр Тишов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/denwer-se-vozrozhdenie-legendarnogo-lokalnogo-veb-servera-na-so</guid>
      <description><![CDATA[<p>Помните диск Z:, иконку джентльмена и магию Run.exe? Денвер вернулся. Denwer SE: Python вместо Perl, HTTPS без красных экранов, свежий PHP и портативность. И да, он всё ещё помещается на флешку.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/denwer-se-vozrozhdenie-legendarnogo-lokalnogo-veb-servera-na-so">Denwer SE: Возрождение легендарного локального веб-сервера на современном стеке</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Для продвинутых]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[CMS]]></category>
      <category><![CDATA[Laravel]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 May 2026 10:11:34 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы начинали веб-разработку в середине 2000-х, то наверняка помните Denwer — «джентльменский набор веб-разработчика». Иконка в виде человека в шляпе, виртуальный диск Z:, папка <i>home/localhost/www</i> — всё это было ритуалом, который упрощал жизнь тысячам разработчиков. Но оригинальный Denwer безнадёжно устарел: Perl-скрипты, 32-битные сборки, поддержка только древних версий PHP и MySQL. Ему на смену пришли громоздкие комбайны вроде Open Server или сложные для новичков Docker-контейнеры.</p><p>Однако недавно проект получил второе дыхание. Разработчик Александр Тишов (Amro) — создатель <a href="https://seditio.org" rel="nofollow">CMS Seditio</a> и основатель веб-студии <a href="https://avego.org" rel="nofollow">«Авего»</a>  — выпустил <a href="https://seditio.org/dev/denwer-se-lokalnyj-veb-stek-dlya-windows-apache-php-mysql-mariadb" rel="nofollow">Denwer SE (Second Edition)</a>. Это не просто обновление, а полный реинжиниринг с сохранением классической философии: портативность, скорость работы и привычная структура каталогов.</p><p>В этой статье разберём, что изменилось под капотом, почему панель управления переехала с Perl на Python, как работает автоматический HTTPS с собственным корневым сертификатом и зачем нужен зоопарк версий PHP от 5.6 до 8.5.</p><h2>Краткий экскурс: от Denwer 3 до Denwer SE</h2><p>Оригинальный Denwer (сокращение от Джентельменский Набор Веб-разработчика) появился в начале 2000-х. Он представлял собой связку Apache + PHP + MySQL, упакованную в самораспаковывающийся архив. Главные фишки:</p><ul><li>Виртуальный диск (по умолчанию Z:), который монтировался через subst.</li><li>Автоматическое создание виртуальных хостов по именам папок в home.</li><li>Консольные exe-файлы (Run, Stop, Restart) без графического окна.</li></ul><p>Проблемы оригинала:</p><ul><li>Управление на Perl — медленно, тяжело поддерживать в Windows.</li><li>Только 32-битные компоненты.</li><li>Невозможно быстро переключать версии PHP или БД.</li><li>Отсутствие нормального HTTPS (только самоподписанные сертификаты с ошибками в браузере).</li><li>Поддержка прекратилась в 2016 году.</li></ul><p>Denwer SE решает все эти проблемы, оставаясь при этом таким же портативным — достаточно скопировать папку на флешку или в облачный каталог.</p><h2>Архитектура: Python вместо Perl</h2><p>Denwer SE — панель управления написана на Python и скомпилирована в один EXE-файл (через PyInstaller).</p><p>Внутри служебной папки <b>denwer\</b> лежат:</p><ul><li>DLL-версия Python — интерпретатор, который использует основной исполняемый файл.</li><li>Скомпилированные модули .pyd — в том числе GUI на базе Tcl/Tk для оконного интерфейса и системного трея.</li><li>Минимальный набор библиотек для управления службами, правки hosts и генерации сертификатов.</li></ul><p>Это даёт несколько преимуществ:</p><ul><li>Портативность — панель ищет соседние папки home и usr, поэтому каталог со стеком можно переносить куда угодно без переустановки.</li><li>Скорость — Python-скрипты запускаются быстрее, чем Perl, особенно на холодном старте.</li><li>Читаемость кода — разработчику проще поддерживать и расширять функционал.</li></ul><h2>Полный переход на x64</h2><p>Оригинальный Denwer навсегда остался 32-битным, что в современных реалиях просто неприемлемо. Denwer SE собирается исключительно под x64:</p><ul><li>Apache (версия 2.4.x) — 64-битный.</li><li>Все модули PHP (от 5.6 до 8.5) — Thread Safe x64.</li><li>MySQL / MariaDB — 64-битные сборки.</li></ul><p>Системные требования — Windows 7/8/10/11 (x64). Для работы компонентов потребуются Microsoft Visual C++ Redistributable (VC11, VC12, VC14, VC15). Разработчик положил установщики этих пакетов в папку <b>vcredist\</b> — при необходимости можно доустановить вручную.</p><h2>Структура каталогов: преемственность и гибкость</h2><p>Denwer SE сохранил классическую структуру, чтобы старые пользователи не ломали голову:</p><p>Главный конфиг — usr\configuration.txt. В нём задаются пути без жёсткой привязки к букве диска, например:</p><p>При старте панель монтирует виртуальный диск (по умолчанию Z:) и динамически подставляет путь через переменную <b>subst_drive</b>.</p><h2>Управление версиями PHP и БД без танцев с бубном</h2><p>В Denwer SE встроен менеджер версий. Вы просто выбираете из выпадающего списка нужную версию PHP (например, 8.3 или 5.6) — панель сама правит конфигурацию Apache.</p><p>Как это работает под капотом:</p><p>В папке usr/local/apache/php лежат подкаталоги php5.6, php7.4, php8.3 и т.д..</p><p>В каждом из них есть файл php-denwer.conf— шаблон для подключения модуля к Apache. При выборе версии этот файл копируется в <b>conf/extra/httpd-denwer.conf</b>, который затем включается в основной httpd.conf.</p><p>Если вы хотите добавить свою сборку PHP (например, PHP 8.4-rc), достаточно:</p><ul><li>Распаковать x64 Thread Safe версию в отдельный каталог внутри php\.</li><li>Создать php-denwer.conf по образцу.</li><li>Убедиться, что все DLL от VC++ установлены.</li></ul><p>Аналогично для баз данных: переключение между MySQL 5.7 и MariaDB 11.8 происходит через тот же интерфейс. В каталоге СУБД может лежать файл <b>db-denwer.conf</b>, который при старте копируется в <b>my.ini</b>.</p><h2>HTTPS, который не бесит: локальный Root CA</h2><p>Самое болезненное место при локальной разработке это самоподписанные сертификаты. Браузеры постоянно ругаются, приходится кликать «Принять риск». Для командной разработки это вообще катастрофа: каждый участник должен сгенерировать свой сертификат и добавить в исключения.</p><p>Denwer SE решает проблему элегантно — он создаёт собственный корневой центр сертификации (CA) и подписывает им сертификаты для всех ваших локальных доменов.</p><p>Как это работает:</p><ol><li>При первом запуске (если найден OpenSSL) панель генерирует ключи denwer-ca.key и сертификат denwer-ca.crt в папку usr/local/apache/conf/cert/denwer-ca/.</li><li>Для каждого виртуального хоста (папки в home/) автоматически создаётся сертификат в conf/cert/&lt;domain&gt;/.</li><li>Все сертификаты хостов подписаны локальным CA.</li></ol><p>Чтобы браузер доверял им, нужно один раз установить <b>denwer-ca.crt</b> в хранилище «Доверенные корневые центры сертификации» Windows. Для этого в панели есть специальная кнопка (требует прав администратора).</p><p>После этого любые HTTPS-запросы к локальным хостам работают без единого предупреждения.</p><h2>Удобства для разработчика (DX)</h2><p>В версии 1.2.4 добавили несколько фич, которые экономят время каждый день:</p><ul><li>Лог с таймштампами — каждая строка в окне панели имеет префикс [чч:мм:сс]. Теперь видно, сколько секунд сервер поднимается и где возможны задержки.</li><li>Прямой доступ к php.ini и my.cnf — рядом со списками версий появились кнопки, открывающие конфигурацию именно активной версии.</li><li>Автоматическое ведение hosts — панель в реальном времени сканирует home/, находит новые домены и прописывает их в C:\Windows\System32\drivers\etc\hosts. Журнал добавляемых записей сохраняется в usr\AddedHosts.txt. При остановке стека лишние строки удаляются.</li><li>Для смены версии PHP или базы данных панель требует полной остановки всех служб. Вы нажимаете «Стоп», меняете версию в списке, затем «Старт» — и стек поднимается уже с новыми настройками. Автоматический перезапуск без вашего участия работает только для Apache: когда вы добавляете новый домен в папку home/, панель сама переписывает vhosts.conf и перезапускает веб-сервер, не трогая БД.</li></ul><h2>Почему не Open Server или Docker?</h2><p>Этот вопрос закономерно возникает у всех, кто видит очередной локальный веб-сервер. Ведь есть уже давно Open Server Panel, Laragon, XAMPP, а для продвинутых — Docker. Зачем ещё один?</p><p><b>Open Server</b> — мощный и удобный комбайн с десятками версий PHP и настройками «на века». Но он разворачивается в системе не портативно: создаёт папки в ProgramData, пишет в реестр, а запуск может занимать 5–10 секунд. Denwer SE, напротив, полностью переносим: скопировал папку на флешку или в облачный каталог — и всё работает. Запуск стека — буквально 1–2 секунды, что критично, когда вы десятки раз за день перезапускаете сервер для тестов.</p><p><b>Docker</b> — индустриальный стандарт для изоляции и воспроизводимости окружений. Но для локальной разработки простого сайта он часто избыточен. Вам нужно разобраться в образах, контейнерах, пробросе портов, volume’ах и docker-compose.yml. А в Denwer SE вы просто создали папку в home/ — и готово. Никакой работы с командной строкой, никакого потребления гигабайт ОЗУ на фоновую службу Docker Desktop.</p><p><b>Laragon</b> — быстрый, портативный, поддерживает не только PHP, но и Node.js, Python, Go. Но он ориентирован на современные фреймворки, особенно Laravel. Denwer SE же сделан для тех, кто вырос на классическом Денвере: виртуальный диск Z:, папка home/имя_домена/www, минимум настроек. Не нужно переучиваться — просто распаковал и работаешь как 10 лет назад, но с новыми версиями PHP и HTTPS.</p><h2>Как начать пользоваться Denwer SE</h2><ol><li>Скачать архив с <a href="https://seditio.org/dev/denwer-se-lokalnyj-veb-stek-dlya-windows-apache-php-mysql-mariadb" rel="nofollow">официального сайта автора</a>.</li><li>Распаковать в любое место, например C:\web\DenwerSE\.</li><li>Запустить DenwerSE.exe — если нет прав администратора, попросит их для монтирования диска и правки hosts.</li><li>Нажать «Запустить» — появится виртуальный диск Z:, а в системном трее иконка.</li><li>Создать папку сайта — например, home\myproject.local и положить туда index.php.</li><li>Открыть в браузере http://myproject.local/ (или https://myproject.local/). HTTPS будет работать сразу после установки корневого сертификата (кнопка в панели).</li></ol><p>По умолчанию пароль к MySQL/MariaDB — пустая строка (пользователь <b>root</b>). При желании его можно сменить через phpMyAdmin.</p><h2>Заключение</h2><p>Denwer SE — это не просто ностальгический проект. Это действительно современный инструмент, который доказывает, что концепция «локального сервера в одну папку» всё ещё актуальна. Отказ от Perl в пользу Python, менеджер версий PHP/БД, нормальный HTTPS, портативность и мгновенный запуск — всё это делает его отличным выбором для быстрого прототипирования, тестирования легаси-кода или обучения веб-разработке.</p><p>Если вы устали ждать, пока Open Server применит настройки, или не хотите разбираться в Docker Compose — попробуйте <b>Denwer SE</b>. Вероятно, он напомнит вам старые добрые времена, но уже без боли устаревших технологий.</p><ul><li>Автор проекта: Александр Тишов
	(Amro), разработчик CMS Seditio.</li><li>Лицензия: Freeware.</li><li>Совместимость: Windows 7/8/10/11 x64.</li></ul><p>Исходники панели управления не открыты (распространяется скомпилированный EXE), но архитектура и конфиги полностью прозрачны. В планах — добавить поддержку Nginx в качестве альтернативы. Следите за обновлениями.</p>]]></content:encoded>
    </item>
    <item>
      <title>ИТ-аутстаффинг: когда он выгоднее найма в штат</title>
      <link>https://tproger.ru/articles/it-autstaffing-kogda-on-vygodnee-najma-v-wtat</link>
      <comments>https://tproger.ru/articles/it-autstaffing-kogda-on-vygodnee-najma-v-wtat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Андрей Бойко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/it-autstaffing-kogda-on-vygodnee-najma-v-wtat</guid>
      <description><![CDATA[<p>Разбираем, чем ИТ-аутстаффинг отличается от штатного найма: скорость, затраты, риски. Когда провайдер выгоднее — и когда нет.
</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/it-autstaffing-kogda-on-vygodnee-najma-v-wtat">ИТ-аутстаффинг: когда он выгоднее найма в штат</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Мобильная разработка]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Фронтенд-разработка с нуля]]></category>
      <category><![CDATA[Фулстек-разработка: полный цикл]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 May 2026 05:44:09 GMT</pubDate>
      <content:encoded><![CDATA[<p>ИТ-аутстаффинг — это модель найма, при которой специалист работает на заказчика и отвечает перед его менеджерами, но официально числится в штате другой компании — провайдера. Последний при этом берёт на себя кадровую часть: трудовой договор, налоги, страховые взносы, документооборот.</p><p>Почему эта схема вообще появилась? Из-за дефицита кадров в ИТ, который давно превратился в постоянный фон для компаний, занимающихся цифровыми продуктами. Найти миддла или синьора занимает два-три месяца, а в узких технологических стеках — и того дольше. Пока идёт поиск, проекты стоят или перегружают команду. И тогда возникает спрос на альтернативные способы работы с ИТ-персоналом.</p><p>Разберём, как устроен аутстаффинг, чем он отличается от аутсорсинга ИТ-специалистов и при каких задачах находить кадры через провайдера  – хорошее решение.</p><h2>ИТ-аутстаффинг и штат: в чем разница</h2><p>Штатный найм — это прямые трудовые отношения. Работодатель оформляет сотрудника к себе и ответственен за налоги, взносы, отпуска, больничные и кадровое сопровождение. Специалист становится частью корпоративной структуры и, как правило, видит своё дальнейшее развитие внутри этой компании. Это привычная схема для обеих сторон.</p><p>При ИТ-аутстаффинге компания-провайдер трудоустраивает специалиста у себя и передаёт его заказчику — на срок или под проект. Схема иначе выстраивается юридически, но с точки зрения ежедневной работы разницы нет. Заказчик ставит задачи и требует результатов. Провайдер отвечает за зарплату, кадровый учёт и трудовые гарантии.</p><p>Отличия двух моделей — в таблице:</p><figure><img src="https://media.tproger.ru/user-uploads/115144/2026-04-29/47cc0077-fd40-4ec5-93ea-f60334dd6354.webp" alt="" /><figcaption>Отличия двух моделей</figcaption></figure><p>Ещё один вопрос, который нередко возникает: чем аутстаффинг отличается от аутсорсинга. При аутсорсинге заказчик отдаёт задачу внешней команде и принимает результат — без погружения в то, как команда работает изнутри. При аутстаффинге он получает конкретного человека и управляет им сам. Это разные форматы с разной логикой применения: первый — про готовый результат, второй — про ресурсы.</p><p>А как вообще контролировать человека, которого не нанимал? Да ровно так же — через задачи, метрики, совместные инструменты. Трудовой договор тут ни при чём. Меняется только то, кто его подписывает и кто несёт кадровые обязательства.</p><h2>Преимущества аутстаффинга разработчиков</h2><p>Классический рекрутинг никуда не уходит, но иногда аутстаффинг гораздо эффективнее. Итак, каковы же преимущества этой формы найма?</p><h2>Аутстаффинг в ИТ: быстрое масштабирование без кадровой нагрузки</h2><p>Найти сильного специалиста в команду в среднем занимает два-три месяца — и это при активном поиске. Часто бывает так, что людей в команде не хватает, потому что проект стремительно растет. Запуск нескольких параллельных процессов поиска кадров рискует затянуться. И тогда бизнес обращается к провайдеру, чтобы добрать нужное количество специалистов. Провайдер предлагает кандидатов, имеющих релевантный опыт в конкретном технологическом стеке, уже через одну-две недели, иногда – быстрее. Разница ощутима, особенно когда дата запуска проекта уже стоит в календаре.</p><p>Особенно это важно, когда приходится одновременно масштабировать несколько направлений. Привлечь четверых-пятерых специалистов через провайдера — это один договор и один процесс согласования, а не пять отдельных рекрутинговых потоков с непредсказуемыми сроками.</p><h2>Экономит бюджет и снижает операционные затраты</h2><p>Содержание штатного сотрудника — это не только зарплата. К ней добавляются расходы на рекрутинг (в среднем одна-три месячные выплаты), обустройство рабочего места, обучение, страховые взносы, налоги и кадровое администрирование. При аутстаффинге эти статьи уходят к провайдеру — заказчик платит прозрачную ставку по договору.</p><p>По завершении проекта не нужно думать о выходных пособиях или процедурах сокращения. Вопрос закрывается условиями договора с провайдером. При сравнимой квалификации специалиста совокупные расходы на аутстаффинге нередко оказываются ниже, чем на штатного сотрудника — если считать в полном объёме.</p><h2>Дает доступ к широкому пулу технических компетенций</h2><p>Провайдеры, предоставляющие аутстаф разработки, держат в базе специалистов самых разных профилей — серверные разработчики, системные</p><p>архитекторы, тестировщики, технические аналитики. Для заказчика это означает возможность подобрать человека с нужным стеком без ограничений локального рынка.</p><p>Именно поэтому аутстафф программистов особенно востребован у компаний, работающих с редкими или нестандартными технологиями. Найти такого специалиста «в штат» часто сложнее и дороже, чем привлечь через провайдера с обновляемой базой кандидатов — особенно если речь о нишевых стеках с ограниченным предложением на рынке труда.</p><h2>Специалисты с разнообразными опытом</h2><p>Разработчики на аутстаффинге, как правило, обладают более широким техническим кругозором, чем их штатные коллеги: они успели поработать в разных командах, с разными стеками и типами задач. Это даёт им гибкость мышления и насмотренность, которую сложно получить, годами работая в одном продукте.</p><p>Кроме того, проектный формат держит таких специалистов в тонусе: нет возможности погрязнуть в рутине.</p><h2>Снижение административной нагрузки</h2><p>Прежде чем новый штатный разработчик напишет первую задачу в трекере, кадровый отдел потратит время на оформление, бухгалтер — на налоговый учёт, юрист — проверит трудовой договор. Это нормально для штатного найма — но это реальные часы и ресурсы. При аутстаффинге вся эта работа остаётся за провайдером.</p><p>Для компаний, которые одновременно закрывают несколько направлений, это особенно ощутимо. Пятеро специалистов через провайдера — это пять ставок в одном договоре. Пятеро штатных — это пять кадровых дел, пять налоговых расчётов, пять пакетов документов. Разница в операционной нагрузке очевидна.</p><h2>Когда аутстаффинг выгоднее штатного найма</h2><p>Модель аутстаффинга в ИТ работает лучше всего в нескольких конкретных ситуациях — давайте суммируем, когда лучше всего задуматься именно об этом варианте найма.</p><ul><li>Проектная работа с ограниченным горизонтом. Нанимать разработчика в штат на полгода-год — нецелесообразно: по завершении проекта появляются расходы на сокращение или переобучение. Аутстаффинг закрывает задачу без лишних обязательств на выходе.</li><li>Срочный рост команды. Продукт запускается через три месяца, а нужны ещё три специалиста прямо сейчас. Классический рекрутинг не успеет. Провайдер может дать команду параллельно, без разрыва в темпе разработки.</li></ul><p>Нишевые технологии и редкие стеки. Когда нужен человек с узкой экспертизой, которых на локальном рынке единицы — провайдер с</p><ul><li>широкой базой найдёт быстрее и, скорее всего, дешевле, чем собственный подбор.</li><li>Тест гипотезы без обязательств. Компания запускает новое направление, но не уверена в его горизонте. Аутстаффинг позволяет собрать команду, быстро оценить гипотезу и выйти без кадровых последствий, если направление не пошло.</li></ul><p>У модели есть и ограничения, которые важно учитывать. Главный риск — зависимость от провайдера: если партнёрство прерывается досрочно, специалист уходит вместе с накопленным знанием о проекте. Для критически важных функций это серьёзно. Поэтому разумный подход — смешанный: ключевые роли закрывать штатом, а аутстаффинг подключать для расширения команды под конкретные задачи с понятным сроком.</p><h2>Штатный найм: когда он по-прежнему эффективен</h2><p>Задач, с которыми штатный найм справляется лучше, немало. Особенно это заметно, когда продукт живёт годами и ключевые решения принимаются людьми, которые понимают его историю. Посмотрим на преимущества найма.</p><ul><li>Погружение в продукт. Человек, который работает с одним продуктом год или два, знает его глубже, чем тот, кого привлекли на полгода. Этот контекст нельзя передать через документацию или онбординг — он накапливается постепенно, через участие во всех стадиях и решениях.</li><li>Лояльность. Штатный сотрудник думает о своей карьере внутри компании, заинтересован в её развитии. Это сложно воспроизвести в модели временного сотрудничества — здесь у специалиста другие приоритеты.</li><li>Корпоративная память. Внутренние специалисты накапливают базу знаний, обучают новых коллег, передают экспертизу. При аутстаффинге существует риск, что с окончанием контракта вместе со специалистом уйдут и знания о проекте — если не выстроить процесс передачи.</li><li>Стабильность команды. Долгие проекты требуют предсказуемого состава: меньше перестановок, меньше потерь контекста. Штатный найм даёт более высокую вероятность сохранить команду на горизонте нескольких лет.</li></ul><p>Штатная модель незаменима там, где важны стратегическая непрерывность и инженерная культура: развитие ключевого продукта, техническая архитектура, формирование внутренней экспертизы. Всё это требует людей, которые связывают своё развитие с компанией, — аутстаффинг эту связь не создаёт. При выборе формата стоит честно оценить горизонт задач и то, насколько важна долгосрочная вовлечённость специалиста.</p><h2>Не вместо, а вместе: гибкие форматы и штатный найм техкадров</h2><p>Аутстаффинг не вытеснит штатный найм, так как решает иные задачи. Когда нужны скорость, гибкость, доступ к экспертизе без долгосрочных обязательств — он работает. Когда важны глубина погружения, лояльность и накопление знаний внутри команды — штат не заменить.</p><p>Компании, прошедшие через опыт масштабирования технической команды, как правило, не задаются вопросом «аутстаффинг или штат» — они комбинируют. Устойчивое ядро в штате, расширение под конкретные задачи — через провайдера.</p><p>Подробнее о том, как организована работа с внешними техническими кадрами, — в профильных материалах компаний, например, в разделе <a href="https://selecty.ru/it-outsourcing" rel="follow">ИТ-аутсорсинг</a> на сайте Selecty, где описаны конкретные форматы взаимодействия заказчика с провайдером.</p><p>Гибкие форматы работы с техническими кадрами сегодня — уже не просто тренд, а устойчивая норма рынка. Компании, которые умеют подбирать инструмент под задачу, получают ощутимое операционное преимущество. ИТ-аутстаффинг при правильном применении — один из таких инструментов.</p><p>Реклама. ООО Селекти, ИНН 7736313541, erid: 2W5zFJYUtvD</p>]]></content:encoded>
    </item>
    <item>
      <title>Как JetBrains избавляются от фризов в IntelliJ-IDE: перевод статьи про background write-действия</title>
      <link>https://tproger.ru/translations/kak-jetbrains-izbavlyayutsya-ot-frizov-v-intellij-ide-perevod-stat</link>
      <comments>https://tproger.ru/translations/kak-jetbrains-izbavlyayutsya-ot-frizov-v-intellij-ide-perevod-stat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Картофельный Повелитель]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/kak-jetbrains-izbavlyayutsya-ot-frizov-v-intellij-ide-perevod-stat</guid>
      <description><![CDATA[<p>Перевод статьи JetBrains Platform: как за 7 лет перенесли write-действия с UI-потока в фон. В IntelliJ 2025.3 доля UI-блокировок упала в 3,5 раза.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/kak-jetbrains-izbavlyayutsya-ot-frizov-v-intellij-ide-perevod-stat">Как JetBrains избавляются от фризов в IntelliJ-IDE: перевод статьи про background write-действия</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 18 Apr 2026 11:45:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если у вас при правке большого проекта в IntelliJ IDEA, WebStorm или PyCharm IDE периодически замирает — шестерёнка приколочена к UI-потоку, и за ней стоит очередь из операций, которые нельзя распараллелить. JetBrains вычищают её уже семь лет, и только что отчитались об очередном шаге: доля времени UI-потока, занятая write-действиями, упала с 1,83% до 0,53% между версиями 2025.2 и 2025.3 — в три с половиной раза.</p><p>Это перевод <a href="https://blog.jetbrains.com/platform/2026/04/road-to-responsive-ides/">оригинальной статьи</a> от Patrick Scheibe (по мотивам внутренней статьи Konstantin Nisht) на блоге JetBrains Platform про многолетнюю работу команды по перекладыванию write-операций в фон. Для разработчиков, которые пишут плагины под IntelliJ Platform или просто борются с фризами в IDE — это редкая возможность заглянуть под капот.</p><ul><li>Корень фризов IntelliJ-IDE — single read-write lock на общие структуры данных (PSI, Document, VFS) и single UI-поток AWT (EDT)</li><li>С 2019 года JetBrains переносят write-действия в фон, с паузой в 2020-2022 годах</li><li>В 2024 году появился новый cancellable lock по результатам совместной работы с JetBrains Research</li><li>В 2025 году Konstantin Nisht решил проблему modality (модальные диалоги) — первые write-действия ушли в фон</li><li>Мигрировали: Workspace Model, VFS refresh, document commit</li><li>2025.2 → 2025.3: доля времени UI на write-lock упала с 1,8276% до 0,5298%, в 1% худших случаев — с 5% до 3%</li></ul><p><b>TL;DR</b> от авторов: это технический пост про многолетнюю работу над отзывчивостью IntelliJ-based IDE. JetBrains строят инструменты и API, которые позволяют выполнять нагрузочные операции вне UI-потока. UI-поток теперь держит write-блокировку примерно в три раза меньше времени, чем раньше. Если технические детали не интересуют — листайте к графикам в конце.</p><p>Одна из самых частых жалоб на IntelliJ-based IDE — производительность. Мы знаем. И работаем над тем, чтобы сделать IDE более отзывчивой. Это не всегда просто: платформе IntelliJ 25 лет, и некоторые архитектурные решения впаяны в неё намертво. Именно они делают ряд оптимизаций сложными.</p><h2>Смертоносное переплетение</h2><p>IntelliJ Platform — многопоточный фреймворк, построенный вокруг единой <a href="https://plugins.jetbrains.com/docs/intellij/threading-model.html">read-write-блокировки (RW lock)</a>. IDE работает с несколькими ключевыми структурами данных: <a href="https://plugins.jetbrains.com/docs/intellij/psi.html">синтаксическими деревьями (PSI)</a>, текстовым представлением файлов (Document subsystem) и представлением файловой системы ОС (Virtual File System, VFS). Доступ к этим структурам защищён RW-блокировкой. Операции делятся на read actions и write actions. В каждый момент времени может существовать только одно write-действие; read-действий может быть параллельно сколько угодно, но read- и write-действие одновременно идти не могут.</p><p>Ещё наши IDE — это UI-приложения. Значит, они используют UI-фреймворк. В IntelliJ Platform это Java AWT с единственным UI-потоком: Event Dispatch Thread (EDT). Этот поток обрабатывает пользовательский ввод и отрисовывает интерфейс. Java также позволяет запускать там бизнес-логику. Производительность EDT напрямую определяет ощущение отзывчивости приложения: если поток быстро обрабатывает события перерисовки и ввод — IDE кажется шустрой.</p><p>Отсюда и берутся фризы. Само write-действие может их вызывать: некоторые write-действия, например пересбор синтаксического дерева или обновление представления файловой системы, тяжёлые сами по себе. Другой, менее очевидный источник фризов — ожидание write-блокировки. Поскольку read- и write-действия не могут идти параллельно, запуск write-действия означает ожидание завершения всех активных read-действий. Мы много работали над тем, чтобы read-действия можно было отменять, но проблема не уходит полностью: если хоть одно read-действие неотменяемо — страдает вся IDE.</p><p>Это и привело нас к ключевой цели: <b>перенести write-действия с UI-потока в фон</b>.</p><h2>С благими намерениями</h2><p>Работа над фоновыми write-действиями началась в 2019 году. Этим занялись Valentin Fondaratov, Andrew Kozlov и Peter Gromov.</p><p>Долгие годы код на EDT имел удобный прямой доступ к моделям IntelliJ Platform. С фоновыми write-действиями эта удобная особенность становится проблемой: UI-код больше не может считать, что доступ к модели всегда безопасен без явной координации. Чтобы сохранить совместимость, нужно было заставить работать большое количество старого UI-кода и при этом сделать все зависимости явными.</p><p>Было и другое осложнение. Код на EDT мог сразу запустить write-действие. Для обычных явных read-действий это не так — write-действие не может просто начаться посередине read-действия.</p><p>Здесь в игру вступает write-intent. Это состояние блокировки, которое всё ещё допускает параллельные read-действия, но может быть взято только одним потоком одновременно и атомарно апгрейдится до полноценного write-действия. Такой режим хорошо подходит EDT-коду, которому может потребоваться перейти к write-действию. Его внедрение в платформу стало важным шагом к поддержке фоновых write-операций без ломки текущего поведения.</p><p>В 2020 году проект поставили на паузу — объём требуемых изменений оказался колоссальным. Много UI-компонентов, особенно редактор, опирались на давние допущения о доступе к моделям с EDT.</p><h2>Большой рефакторинг</h2><p>Проект не бросили, а в 2022 году работу возобновили Lev Serebryakov и Daniil Ovchinnikov.</p><p>На этом этапе IntelliJ Platform отрефакторили так, чтобы вывести наружу множество неявных допущений, на которых она держалась. Это уменьшило зависимость части UI-кода от неявной блокировки.</p><p>Другой важной частью стала совместная работа с командой JetBrains Research. Прежняя реализация блокировки предполагала, что write-действия выполняются только на EDT. Перенос их в фон требовал другого типа блокировки, а обычный ReentrantReadWriteLock не подходил под наши нужды. Результат — новая отменяемая (cancellable) блокировка, которая теперь управляет платформой (см. <a href="https://arxiv.org/abs/2504.11389">статью исследования</a>).</p><p>Этот этап длился до конца 2024 года.</p><h2>Когда одной блокировки недостаточно</h2><p>В начале 2025 года эту часть проекта возглавил Konstantin Nisht. К тому моменту мы почти были готовы запустить первые фоновые write-действия. Оставалась одна крупная проблема — modality (модальность).</p><p>Некоторые UI-элементы IDE должны блокировать пользователю возможность взаимодействовать с чем-то другим. Это модальные диалоги, например диалог Settings. В IntelliJ Platform модальность влияет и на модель: пока виден модальный диалог, не связанные с ним write-действия не должны запускаться. Исторически большую часть этого обеспечивал EDT-планировщик — он просто не запускал UI-работу из немодального контекста, пока модальный диалог открыт.</p><p>Фоновые write-действия в эту модель автоматически не вписывались.</p><p>Если на EDT показан модальный диалог, держащий write-intent, то наивная попытка запустить фоновое write-действие может привести к дедлоку. При этом мы хотим, чтобы вычисления внутри диалога двигались вперёд и их не тормозила работа, не связанная с диалогом.</p><p>Чтобы это решить, мы ввели стратегию блокировок с учётом модальности — она разделяет, что происходит внутри модального диалога, а что снаружи. Это сохраняет гарантии, на которые опираются модальные диалоги, и позволяет фоновым write-действиям выполняться.</p><p>Подход также работает для вложенных модальных вычислений — что важно, потому что настоящие модальные процессы не всегда плоские. С этим на месте мы наконец смогли запустить первые фоновые write-действия.</p><h2>Переносим работу, не ломая плагины</h2><p>Первые write-действия перенести в фон было относительно легко. Они жили в Workspace Model и в основном использовались для инвалидации кешей. После этого наступила очередь чего-то посерьёзнее: VFS refresh.</p><p>VFS refresh — это процесс синхронизации событий изменения файлов от операционной системы с внутренними структурами IDE. Помимо применения этих событий refresh вызывает листенеры — код плагинов, реагирующий на изменения файловой системы. Традиционно VFS refresh выполняется в write-действии, и эти листенеры вызываются там же.</p><p>Возникает проблема совместимости. За много лет большое количество кода листенеров стало предполагать, что выполняется на EDT. Некоторые из них естественным образом лезут в UI. Многие живут в плагинах, которыми мы не управляем — поэтому просто взять и изменить модель выполнения в надежде, что всё продолжит работать, нельзя.</p><p>Задача была не только перенести само write-действие в фон, но и сделать это так, чтобы не сломать длинный хвост существующего плагинного кода.</p><p>Базовая идея проста: держать write-действие в фоне, но при необходимости совместимости возвращать конкретную работу листенеров на EDT. Swing даёт для этого синхронную передачу управления через invokeAndWait(...).</p><p>К сожалению, за этим на первый взгляд простым подходом прячется дедлок. Если фоновое write-действие пытается синхронно передать работу на EDT, а EDT в этот момент сам блокирован ожиданием lock — IDE может замереть.</p><p>Чтобы этого избежать, мы ввели внутренний механизм совместимости, который позволяет определённым UI-событиям продолжать продвигаться во время таких ожиданий. Это дало возможность мигрировать инкрементно: перенести тяжёлую write-работу с EDT, при этом сохранив совместимость для листенеров, которые ещё от него зависят.</p><p>Этот подход оказался одним из важнейших кусков проекта. Он позволил мигрировать листенеры постепенно, сохранить совместимость для внешних плагинов — и при этом получить большую часть выигрыша в производительности, перенося в первую очередь самые медленные участки.</p><p>После VFS refresh мы мигрировали и процесс document commit — тот, который перестраивает PSI из документов. Когда базовая инфраструктура фоновых write-действий была на месте, перенос оказался значительно проще.</p><h2>А давайте потом</h2><p>Фоновые write-действия — не панацея. Они сокращают время, которое EDT проводит за выполнением write-действий, но автоматически не убирают время, которое EDT тратит на ожидание блокировок.</p><p>Даже если write-действия выполняются в фоне, EDT всё ещё может попросить доступ на read или write-intent. Пока идёт write-действие — или пока оно ждёт write-lock — такие запросы способны зафризить UI. Отсюда вторая часть проекта: убрать с EDT как можно больше взятий блокировок.</p><p>Особенно проблемной была область редактора. Редактор отрисовывает контент на основании своих моделей — позиции курсора, фолдингов, текста документа. Но модификация документа защищена RW-lock, а редактору всё ещё нужен доступ к этим данным на EDT. Долгое время read-действия были в редакторе повсюду, включая пути отрисовки. Это серьёзная проблема, потому что отрисовка может происходить в любой момент — и редактор мог требовать read-доступ именно тогда, когда нам больше всего нужно, чтобы UI-поток был свободен.</p><p>Здесь мы пошли на прагматичный компромисс. Мы ослабили часть требований к блокировкам на EDT-путях редактора, но сохранили часть записей документа на EDT ради консистентности. Так отрисовка редактора стала менее зависимой от блокировок — хотя мы пока и не перенесли все модификации документа в фон. Это ещё предстоит.</p><p>Ещё одним источником давления на блокировки в EDT был наш API для асинхронных вычислений. Ради совместимости многие такие вычисления всё ещё были связаны с захватом write-intent, а значит, могли зафризить EDT в непредсказуемые моменты.</p><p>Наблюдение здесь простое: если кто-то планирует работу на выполнение асинхронно в UI-потоке — обычно его не волнует точная микросекунда начала. Значит, не всегда нужно блокировать EDT в ожидании write-intent. Во многих случаях можно просто отложить вычисление до момента, когда этот доступ станет доступным. После ряда изменений в планировке UI проблема стала намного менее актуальной.</p><h2>Результаты, планы и благодарности</h2><p>Фоновые write-действия сложны, потому что касаются фундаментальных контрактов IntelliJ Platform. Мы всё ещё строим API и инструменты, которые помогут плагинам отвязать свою логику от EDT. Работа не закончена, но вот где мы сейчас.</p><p>Как метрику мы отслеживаем, сколько времени EDT тратит на выполнение write-действий. Данные собираются через неделю после каждого релиза.</p><p>Например, в 2025.2 у 1% пользователей write-действия занимали 5% UI-времени. В 2025.3 тот же перцентиль — уже 3%. А ожидаемая общая доля времени UI на write-locks на EDT упала с <b>1,8276% в 2025.2</b> до <b>0,5298% в 2025.3</b> — примерно в три с половиной раза.</p><p>В будущем работа сосредоточится на том, чтобы убрать с EDT больше использования write-intent. Мы хотим убрать блокировки из таких частых взаимодействий, как набор текста. Это сложная цель, потому что она требует переосмысления фундаментальных структур — Actions, PSI, Documents. Сложно, но, как мы думаем, выполнимо.</p><p>Спасибо всем, кого мы ещё не упомянули, кто прямо или косвенно участвовал в проекте: Anna Saklakova, Dmitrii Batkovich, Vladimir Krivosheev, Moncef Slimani, Lev Serebryakov, Nikita Koval и другим. Пост начинался как внутренняя статья Konstantin Nisht и был адаптирован для публичного блога Patrick Scheibe — с меньшим количеством breaking changes, чем обычно.</p><h2>Что это значит для разработчиков плагинов</h2><p>Если вы разрабатываете плагин под IntelliJ Platform — изменения в модели блокировок затрагивают вас напрямую. Три практических вывода из статьи:</p><ul><li><b>Листенеры на VFS refresh и document commit теперь могут выполняться в фоне.</b> Если код листенера предполагал EDT — он будет перенесён через механизм совместимости, но ценой общей производительности. Лучше пройтись по своим листенерам и убрать из них прямую работу с Swing, где это возможно</li><li><b>Долгие некооперативные read-действия — самое больное место.</b> Один плагин с неотменяемым read-действием может тормозить всю IDE. Если пишете код, читающий PSI — поддержите отмену (ProgressManager.checkCanceled) и уведомляйте платформу</li><li><b>Write-intent на EDT больше не безопасно захватывать «на всякий случай».</b> Если вашему коду нужна запись — лучше явно запросить фоновое выполнение, чем держать write-intent на UI-потоке. Конкретные API меняются от релиза к релизу — следите за изменениями в документации IntelliJ Platform</li></ul><p>Для обычных пользователей IDE итог простой: если вы обновитесь с 2025.2 на 2025.3 — фризов должно стать меньше, особенно на крупных Gradle- или Maven-проектах. Конкретный эффект зависит от набора плагинов: те, что ещё не адаптированы, могут работать в старом режиме совместимости и не дать полного выигрыша.</p><h2>Выводы</h2><p>Главный урок статьи не технический, а архитектурный. JetBrains семь лет переделывают фундаментальный контракт платформы, и даже сейчас работа не закончена. Переход с модели «всё на EDT» на «write-действия в фоне» — это не оптимизация, а смена условий, на которых держалась вся плагинная экосистема. И они делают это, не ломая внешние плагины.</p><p>Для разработчиков это один из лучших публичных кейсов, как мигрировать большую систему с глубоко зашитыми допущениями. Для пользователей — маленькое утешение: фризы в IDE с новым релизом станут заметно короче.</p><blockquote>Мы хотим убрать блокировки из таких частых взаимодействий, как набор текста. Это сложная цель, потому что она требует переосмысления фундаментальных структур — Actions, PSI, Documents. Сложно, но мы думаем, что это выполнимо.</blockquote><p>Оригинал статьи — на <a href="https://blog.jetbrains.com/platform/2026/04/road-to-responsive-ides/">блоге JetBrains Platform</a>, авторы: <a href="https://github.com/halirutan">Patrick Scheibe</a> и Konstantin Nisht (внутренняя версия), академическая статья про cancellable lock — на <a href="https://arxiv.org/abs/2504.11389">arXiv</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub Copilot с 24 апреля обучается на вашем коде по умолчанию — как отключить</title>
      <link>https://tproger.ru/news/github-copilot-s-24-aprelya-obuchaetsya-na-vawem-kode-po-umolchaniyu</link>
      <comments>https://tproger.ru/news/github-copilot-s-24-aprelya-obuchaetsya-na-vawem-kode-po-umolchaniyu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-copilot-s-24-aprelya-obuchaetsya-na-vawem-kode-po-umolchaniyu</guid>
      <description><![CDATA[<p>С 24 апреля GitHub Copilot Free, Pro и Pro+ начинает собирать код и промпты для обучения моделей. Как сделать opt-out за минуту — инструкция.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-copilot-s-24-aprelya-obuchaetsya-na-vawem-kode-po-umolchaniyu">GitHub Copilot с 24 апреля обучается на вашем коде по умолчанию — как отключить</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 18 Apr 2026 10:30:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы пользуетесь GitHub Copilot Free, Pro или Pro+ — до 24 апреля нужно зайти в настройки и отключить передачу кода в обучение моделей GitHub. После этой даты opt-out по-прежнему работает, но уже собранные данные из тренировочного датасета обратно не забирают — поэтому откладывать нельзя.</p><p>GitHub <a href="https://github.blog/news-insights/company-news/updates-to-github-copilot-interaction-data-usage-policy/">анонсировал</a> изменение политики 25 марта: 30 дней на раздумья, opt-out через настройки, у Business и Enterprise всё по-старому. Сейчас идут последние дни — до дедлайна меньше недели.</p><ul><li>С 24 апреля 2026 года данные Copilot Free, Pro и Pro+ уходят в обучение моделей по умолчанию</li><li>Opt-out — на <a href="https://github.com/settings/copilot/features">github.com/settings/copilot/features</a>, опция «Allow GitHub to use my data for AI model training»</li><li>Business и Enterprise НЕ затронуты — у них запрет в контракте</li><li>Студенты и преподаватели с бесплатным Copilot Pro защищены отдельной политикой GitHub Education</li><li>Приватные репозитории «в покое» не читаются, но пока вы активно работаете — код из них уходит GitHub</li><li>Данные могут передаваться Microsoft и другим компаниям группы, но не сторонним AI-провайдерам</li></ul><h2>Что именно будет уходить в датасет</h2><p>В анонсе перечислен полный список. Опция включает передачу в обучение моделей:</p><ul><li><b>Выходы Copilot</b> — ваши принятые и отредактированные варианты кода</li><li><b>Входы</b> — сами промпты и фрагменты кода, которые показываются модели</li><li><b>Код вокруг курсора</b> — полный контекст, который Copilot видит при подсказке</li><li><b>Комментарии и документация</b>, которые вы пишете в редакторе</li><li><b>Имена файлов, структура репозитория</b>, паттерны навигации</li><li><b>Все взаимодействия с фичами Copilot</b> — чаты, инлайн-саджесты</li><li><b>Оценки подсказок</b> — лайки и дизлайки по результатам</li></ul><p>Что явно исключено: контент issues, discussions и приватных репозиториев «в покое» (at rest). Но GitHub уточняет отдельно: «Copilot обрабатывает код из приватных репозиториев, пока вы активно используете Copilot. Эти данные нужны для работы сервиса и могут быть использованы для обучения — если вы не сделаете opt-out».</p><p>Фактически это означает: пока вы пишете код в приватном репозитории с включённой опцией, все фрагменты, которые видит Copilot, могут уйти в тренировочный датасет. Приватность в этом режиме ограничивается отсутствием массового сканирования репозитория — но не отсутствием ваших команд в логах.</p><h2>Кого касается, а кого нет</h2><ul><li><b>Затронуты:</b> Copilot Free, Copilot Pro, Copilot Pro+</li><li><b>Исключены:</b> Copilot Business и Copilot Enterprise — запрет в контракте</li><li><b>Исключены:</b> студенты и преподаватели с бесплатным Copilot Pro</li><li><b>Исключены:</b> пользователи, которые ранее отписались от сбора «для улучшения продукта» — preference переносится автоматически</li></ul><p>То есть если у вашей команды корпоративная подписка Business или Enterprise — волноваться не о чем, контракт защищает. А вот у фрилансеров и мелких команд на Pro-тарифе — по умолчанию сбор включён.</p><h2>Как сделать opt-out за минуту</h2><p>Шаги для обычной учётной записи GitHub:</p><ol><li>Открыть <a href="https://github.com/settings/copilot/features">github.com/settings/copilot/features</a></li><li>Найти секцию «Privacy»</li><li>Снять галочку «Allow GitHub to use my data for AI model training»</li><li>Сохранить настройки</li></ol><p>Можно сделать opt-out и после 24 апреля, но GitHub предупреждает: с этого момента сбор прекращается, но ранее собранные данные из обучающих датасетов уже не удаляются. Поэтому правильная последовательность — сначала отключить, потом проверить, потом продолжать работу.</p><p>У Copilot есть и другие настройки приватности, которые стоит просмотреть за один раз: ограничение на приватные репозитории, телеметрия редактора, история чата. Подробности — в <a href="https://docs.github.com/copilot/how-tos/manage-your-account/managing-copilot-policies-as-an-individual-subscriber">документации GitHub</a>.</p><h2>Что думает сообщество</h2><p>Реакция на анонс в обсуждении GitHub Community — преимущественно негативная. Из всех комментариев публично поддержал инициативу только VP developer relations Martin Woodward — остальные напоминают, что Codex в основе Copilot и так обучен на публичном коде GitHub без разрешения авторов, и критикуют сам паттерн opt-out. Европейская норма противоположная: opt-in, то есть по умолчанию данные не собираются, а пользователь должен явно согласиться.</p><blockquote>Политика соответствует принятым в индустрии практикам и улучшит производительность модели для всех пользователей. Участвуя, вы помогаете нашим моделям лучше понимать рабочие процессы разработки, предлагать более точный и безопасный код и находить потенциальные баги до попадания в прод.</blockquote><p>В FAQ GitHub ссылается на то, что Anthropic, JetBrains и Microsoft ведут похожие политики. Это правда — у большинства крупных ИИ-продуктов opt-out, а не opt-in. Но для разработчиков, которые хранят в приватных репозиториях коммерческий код, это не очень утешительный аргумент: прецедент важнее отраслевого консенсуса.</p><h2>Что это значит для российских разработчиков</h2><p>Прямого ограничения GitHub Copilot в России нет — инструмент формально работает, хотя оплата Pro-подписки из РФ затруднена. Российские разработчики массово пользуются Copilot Free и Pro через зарубежные платёжные сервисы или триал-подписки — и именно они сейчас в группе риска. Если вы работаете с коммерческим или чувствительным кодом через личный GitHub-аккаунт — opt-out нужен в первую очередь вам, потому что корпоративного договора, который защитит от передачи данных, у вас нет.</p><p>Альтернативы, которые не передают код в обучение по умолчанию:</p><ul><li><a href="https://www.cursor.com/">Cursor</a> — платные тарифы не используют ваш код для обучения (privacy mode)</li><li><a href="https://codeium.com/">Codeium</a> и Windsurf — у Enterprise-тарифа обучение на коде отключено</li><li><a href="https://tabby-inc.com/">Tabby</a> и self-hosted аналоги — локальное выполнение, код не покидает сеть</li><li>Qwen3.6-35B-A3B и аналогичные open-weight модели через vLLM или Ollama — полностью локально, без третьих сторон</li></ul><h2>Что в итоге</h2><p>Изменение политики GitHub — не просто мелкий тумблер в настройках. Это разворот дефолта: раньше, чтобы отдать код на обучение, нужно было согласиться, теперь — нужно отказаться. Для публичных проектов это слабо что меняет. Для приватных — вопрос того, что именно уходит в тренировочный датасет Microsoft. Есть и обратная сторона: если все массово сделают opt-out, Copilot будет хуже догонять конкурентов — но это забота GitHub, а не разработчика, которому нужно защитить код клиента.</p><p>Если вы используете Copilot Free, Pro или Pro+ — сегодня самое время открыть <a href="https://github.com/settings/copilot/features">github.com/settings/copilot/features</a> и снять галочку. Займёт минуту; гарантирует, что ваш коммерческий код не уйдёт в тренировочный датасет Microsoft.</p><p>Политику разбирает <a href="https://www.theregister.com/2026/03/26/github_ai_training_policy_changes/">The Register</a>, официальные детали — в <a href="https://github.blog/news-insights/company-news/updates-to-github-copilot-interaction-data-usage-policy/">анонсе GitHub Blog</a> и <a href="https://github.com/orgs/community/discussions/188488">FAQ в GitHub Community</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Anthropic запустила Claude Design — ИИ собирает прототипы, слайды и лендинги в диалоге</title>
      <link>https://tproger.ru/news/anthropic-zapustila-claude-design-ii-sobiraet-prototipy-slajd</link>
      <comments>https://tproger.ru/news/anthropic-zapustila-claude-design-ii-sobiraet-prototipy-slajd?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/anthropic-zapustila-claude-design-ii-sobiraet-prototipy-slajd</guid>
      <description><![CDATA[<p>Anthropic запустила Claude Design на Opus 4.7: прототипы, слайды и лендинги в диалоге, с handoff в Claude Code. Разбираем, что умеет.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/anthropic-zapustila-claude-design-ii-sobiraet-prototipy-slajd">Anthropic запустила Claude Design — ИИ собирает прототипы, слайды и лендинги в диалоге</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 18 Apr 2026 09:15:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вам нужно быстро собрать прототип интерфейса, питч-дек или лендинг, но вы не дизайнер — теперь это можно делать в диалоге с Claude. Anthropic Labs 17 апреля запустила <a href="https://www.anthropic.com/news/claude-design-anthropic-labs">Claude Design</a>: отдельный продукт внутри экосистемы Claude, который собирает макеты, прототипы, слайды и маркетинговые ассеты по текстовому описанию и дальше правится голосом, комментариями и ползунками.</p><p>Claude Design работает на Claude Opus 4.7 — самой мощной мультимодальной модели Anthropic на сегодня. Он доступен в research preview (ранний доступ с возможными ограничениями) всем подписчикам Claude Pro, Max, Team и Enterprise на <a href="https://claude.ai/design">claude.ai/design</a>.</p><ul><li>Новый продукт Anthropic Labs для визуального дизайна через диалог с Claude</li><li>Под капотом — Claude Opus 4.7, сильнейшая vision-модель Anthropic</li><li>Доступен в research preview для Claude Pro, Max, Team и Enterprise</li><li>Поддерживает прототипы, слайды (PPTX, Canva), лендинги и макеты</li><li>Читает кодовую базу и дизайн-файлы, применяет фирменные стили автоматически</li><li>Handoff в Claude Code — передаёт готовый прототип на реализацию одной командой</li></ul><h2>Что такое Claude Design</h2><p>Это не замена Figma или Canva, а слой над Claude, который превращает разговор в визуальный артефакт. Вы пишете «сделай лендинг для SaaS-продукта в нашем стиле с тремя тарифами и FAQ» — Claude собирает первую версию. Дальше её можно редактировать тремя способами: кликнуть на элемент и оставить комментарий, исправить текст прямо в макете или крутить ползунки. Причём ползунки — не из фиксированного набора: Claude создаёт их под задачу, «от этой версии к той версии» или «от плотного к воздушному».</p><p>Claude собирает фирменный стиль не из абстрактного описания. При настройке команда подключает свою кодовую базу и дизайн-файлы — модель вытаскивает оттуда цвета, типографику, компоненты и применяет их к каждому новому проекту. У команды может быть несколько систем одновременно — например, отдельная для B2B-продукта и отдельная для маркетинга.</p><h2>Что можно делать</h2><ul><li><b>Интерактивные прототипы.</b> Дизайнер превращает статичный макет в кликабельный прототип без PR-а и ревью кода</li><li><b>Wireframes и mockups.</b> Продакт рисует флоу фичи и передаёт их в Claude Code на имплементацию или дизайнеру на доработку</li><li><b>Design explorations.</b> Дизайнер за одну сессию получает десяток разных направлений макета, а не два-три из-за нехватки времени</li><li><b>Питч-деки и презентации.</b> Основатель превращает черновик в готовую on-brand презентацию и экспортирует её в PPTX или в Canva</li><li><b>Маркетинговые ассеты.</b> Маркетолог делает лендинги, соцсети, креативы для кампаний и отдаёт дизайнеру на полировку</li><li><b>Прототипы нового поколения.</b> Макеты со встроенным кодом: голосовой ввод, видео, шейдеры, 3D и ИИ — то, что обычно рисуют через Three.js и вложенные iframe</li></ul><h2>Как это работает внутри</h2><p>Импорт материалов гибкий. Можно начать с текстового промпта, загрузить картинки, DOCX, PPTX или XLSX, показать Claude репозиторий или дать ему «поймать» элемент прямо с сайта через web capture tool — чтобы прототип выглядел как настоящий продукт.</p><p>Совместная работа идёт по модели, привычной по Figma и Google Docs: документ может быть приватным, доступным по ссылке всем в организации или с правом редактирования — тогда коллеги могут одновременно править макет и общаться с Claude в групповом чате.</p><p>Экспорт — внутренняя ссылка, папка, Canva, PDF, PPTX или HTML-файл. Самое интересное для разработчиков — <b>handoff в Claude Code</b> (передача макета в кодогенератор): система упаковывает макет, дизайнерский замысел (design intent) и ассеты в bundle, который уходит в Claude Code одной инструкцией. Фронтенду не нужно угадывать отступы и цвета — всё приходит вместе с намерением дизайнера.</p><h2>Что говорят первые пользователи</h2><blockquote>Наши самые сложные страницы, которые в других инструментах требовали 20+ промптов, в Claude Design собираются за 2. Прыжок от прототипа к продакшену через Claude Code стал бесшовным.</blockquote><p>Anthropic отдельно подчёркивает партнёрство с Canva: дизайны из Claude Design переносятся в Canva одним кликом и там превращаются в полностью редактируемые проекты для публикации.</p><h2>Как получить доступ</h2><p>Claude Design входит в существующие подписки Claude: Pro, Max, Team, Enterprise. Дополнительных лицензий покупать не нужно — продукт использует лимиты вашего тарифа.</p><p>У Enterprise-организаций Claude Design по умолчанию выключен — администратор включает его в Organization settings. Это сделано, чтобы команды безопасников успели оценить, что модель читает дизайн-файлы и кодовую базу.</p><p>Рассылка в research preview идёт постепенно: Anthropic раскатывает доступ по подписчикам в течение 17-18 апреля. Стартовая точка — <a href="https://claude.ai/design">claude.ai/design</a>.</p><h2>Что это значит для рынка</h2><p>Claude Design попадает в горячий сегмент «агенты для визуального дизайна и фронта». Прямые конкуренты — <a href="https://v0.dev/">v0 от Vercel</a>, <a href="https://www.figma.com/make/">Figma Make</a>, <a href="https://bolt.new/">Bolt</a>, <a href="https://lovable.dev/">Lovable</a>, Framer AI. Отличие Anthropic — ставка на интеграцию с Claude Code: прототип уходит в агентного кодогенератора в ту же минуту, в том же разговоре.</p><p>Анонс взлетел в топ Hacker News — и ключевая история там не про «ещё один ИИ-дизайнер», а про «ещё один слой для Claude Code, который закрывает дыру на дизайнерской стороне». То есть сообщество реагирует в первую очередь на handoff-сценарий, а не на генерацию макетов.</p><h2>Что в итоге</h2><p>Claude Design — не «ещё один AI для картинок», а попытка Anthropic закрыть рабочий стык между дизайном и кодом. Для команд, которые уже сидят на Claude, это означает меньше инструментов и меньше handoff-а: макет рождается, обсуждается и уходит в реализацию в одном окне.</p><p>Для российских разработчиков и продактов, у которых уже есть доступ к Claude, это сокращает путь от идеи до прототипа — без переключения между инструментами и форматами. Дизайнерам же Claude Design — повод сместить фокус с рутинного прототипирования к системному дизайну и фирменным стилям, которые ИИ пока не придумывает самостоятельно.</p><p>Источники: <a href="https://www.anthropic.com/news/claude-design-anthropic-labs">анонс Anthropic Labs</a>, <a href="https://news.ycombinator.com/item?id=46115600">обсуждение на Hacker News</a>, страница продукта <a href="https://claude.ai/design">claude.ai/design</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Alibaba открыла веса Qwen3.6-35B-A3B — MoE-модель с 1М контекста для локальных ИИ-агентов</title>
      <link>https://tproger.ru/news/alibaba-otkryla-vesa-qwen3-6-35b-a3b-moe-model-s-1m-konteksta</link>
      <comments>https://tproger.ru/news/alibaba-otkryla-vesa-qwen3-6-35b-a3b-moe-model-s-1m-konteksta?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/alibaba-otkryla-vesa-qwen3-6-35b-a3b-moe-model-s-1m-konteksta</guid>
      <description><![CDATA[<p>Alibaba открыла веса Qwen3.6-35B-A3B — MoE на 3 млрд активных параметров, контекст 1 млн токенов. Разбираем архитектуру и как подключить к Claude Code.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/alibaba-otkryla-vesa-qwen3-6-35b-a3b-moe-model-s-1m-konteksta">Alibaba открыла веса Qwen3.6-35B-A3B — MoE-модель с 1М контекста для локальных ИИ-агентов</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 18 Apr 2026 08:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если у вас на столе стоит машина с RTX 4090 или серверным GPU, а в кармане кончаются кредиты на Claude Code или Cursor — теперь можно подключить их к локальному агенту. Alibaba выложила веса <b>Qwen3.6-35B-A3B</b> на <a href="https://huggingface.co/Qwen/Qwen3.6-35B-A3B">Hugging Face</a> — это первая open-weight модель из линейки Qwen3.6.</p><p>В марте Alibaba уже выпустила <a href="https://tproger.ru/news/alibaba-vypustila-qwen3-6-plus---ii-model-dlya-agentnogo-kodinga">Qwen3.6-Plus</a> — закрытую flagship-модель с API-доступом через OpenRouter. Теперь у серии появилась открытая ветка: архитектура Mixture of Experts, 35 млрд параметров всего, но при генерации токена активируются только 3 млрд. Поэтому модель можно запустить на одной современной видеокарте — правда, с квантизацией до 4 бит, о требованиях подробнее ниже.</p><p>Саймон Уиллисон (создатель Datasette и автор утилиты llm) <a href="https://simonwillison.net/2026/Apr/16/qwen-beats-opus/">отметил</a>, что Qwen3.6-35B-A3B в его популярном тесте «pelican on a bicycle» сгенерировала SVG-иллюстрацию лучше, чем свежий закрытый Claude Opus 4.7 от Anthropic. Уиллисон гонял квантизованную версию модели (~21 ГБ) на MacBook Pro M5 через LM Studio. Тест полушутливый, но показательный: open-weight-ветка догоняет топ-проприетарные.</p><ul><li>Первая open-weight модель линейки Qwen3.6 под лицензией Apache 2.0</li><li>Архитектура MoE: 35 млрд параметров всего, из 256 экспертов активны 8 роутящихся + 1 общий (всего 3 млрд параметров на токен)</li><li>Нативный контекст 262 144 токена, через YaRN-растяжение — до 1 010 000</li><li>Мультимодальная: текст + картинки (Vision Language Model)</li><li>На Terminal-Bench 2.0 — 51,5 балла, прирост +11 относительно предшественника Qwen3.5-35B-A3B</li><li>Работает через vLLM, SGLang, KTransformers и Hugging Face Transformers</li></ul><h2>Что внутри: MoE и гибридные слои</h2><p>Qwen3.6-35B-A3B — это Mixture of Experts. Суффикс <b>A3B</b> в названии означает <i>Active 3 Billion</i>: при генерации каждого токена модель выбирает 8 «экспертов» из 256 плюс один общий, суммарно 3 млрд активных параметров из 35 млрд.</p><p>Архитектура гибридная: 10 повторяющихся блоков, в каждом три последовательности Gated DeltaNet → MoE и одна — Gated Attention → MoE. Gated DeltaNet — вариант линейного внимания, он даёт быструю обработку длинного контекста. Gated Attention с полным квадратичным вниманием стоит там, где линейная аппроксимация теряет точность.</p><p>Контекст нативно 262 144 токена. Для длинных сессий (до 1 010 000 токенов) Alibaba рекомендует YaRN-растяжение RoPE, иначе модель теряет фокус на хвосте.</p><h2>Что нового относительно Qwen3.5</h2><p>В карточке модели Alibaba выделяет две главные линии улучшений.</p><p><b>Agentic Coding.</b> Модель лучше держит фронтенд-воркфлоу и рассуждает про репозиторий целиком, а не по отдельным файлам. По внутренним бенчмаркам Alibaba — прирост на коде относительно Qwen3.5-35B-A3B:</p><ul><li>Terminal-Bench 2.0: 51,5 против 40,5 — +11 баллов</li><li>SWE-bench Verified: 73,4 против 70,0</li><li>SWE-bench Pro: 49,5 против 44,6</li><li>QwenWebBench (фронтенд-генерация, Elo): 1397 против 978</li></ul><p><b>Thinking Preservation.</b> В Qwen3.5 reasoning-токены модели не сохранялись между шагами диалога — модель каждый раз начинала рассуждать заново. В 3.6 появилась опция оставлять reasoning-контекст в истории сообщений, она включается через параметр сэмплера. Для многошаговых агентных сценариев это означает, что промежуточные выводы переходят между шагами, и агент не теряет «почему» на шаге 5, если оно возникло на шаге 2.</p><h2>Как читает картинки</h2><p>Qwen3.6-35B-A3B — Vision Language Model, визуальный энкодер встроен в саму модель. По внутренним замерам Alibaba, на большинстве визуальных бенчмарков модель обгоняет закрытый Claude Sonnet 4.5 — включая MMMU, Mathvista, RealWorldQA и HallusionBench. Самые заметные разрывы:</p><ul><li>RealWorldQA — 85,3 vs 70,3 у Claude Sonnet 4.5</li><li>HallusionBench (устойчивость к галлюцинациям на картинках) — 69,8 vs 59,9 у Claude Sonnet 4.5</li></ul><p>Для агентов, которые читают скриншоты интерфейсов или диаграммы из документации, это важное сочетание: open-weight плюс конкурентоспособное визуальное разумение. Раньше открытых моделей такого уровня на визуальных задачах почти не было.</p><h2>Как запустить локально</h2><p>Официально поддерживаются четыре способа инференса: Hugging Face Transformers, vLLM, SGLang и KTransformers. Для локального сервера с OpenAI-совместимым API проще всего взять vLLM:</p><p>Требования к железу определяются активной частью модели — 3 млрд параметров. В BF16 модель целиком занимает около 70 ГБ VRAM, но с квантизацией (AWQ/GPTQ 4-бит) и FlashAttention инференс помещается на одну RTX 4090 (24 ГБ) или L40S (48 ГБ). Для полного контекста 1 млн токенов и пакетной обработки лучше две карты или серверный A100/H100.</p><p>После старта vLLM модель принимает запросы по OpenAI-совместимому API на http://localhost:8000/v1. В Aider и Cursor этот URL подставляется напрямую. Claude Code ждёт Anthropic-совместимый протокол, поэтому для него нужен прокси — например, <a href="https://github.com/musistudio/claude-code-router">claude-code-router</a>, он конвертирует OpenAI-ответы vLLM в формат Anthropic. Модель поддерживает нативный function calling, так что работать она будет как полноценный агент, а не как plain-LLM.</p><h2>Для кого это</h2><ul><li>Команды с чувствительным кодом, которым нельзя отправлять репозиторий в сторонние API</li><li>Разработчики, которые хотят независимость от биллинга и лимитов Claude, OpenAI, Cursor</li><li>Российские пользователи: модель скачивается с Hugging Face без VPN и санкционных рисков, лицензия Apache 2.0</li><li>Исследователи — для файн-тюнинга, дистилляции и экспериментов с ин-контекстным обучением</li></ul><h2>Что это значит</h2><p>Qwen3.6-35B-A3B — одно из крупных open-weight событий апреля 2026 года. В связке с vLLM модель можно подключить к Aider, Cursor или Claude Code через прокси и получить автономного кодового агента на собственном железе — без биллинга Anthropic или OpenAI. А в визуальном разумении она ещё и обгоняет закрытый Claude Sonnet 4.5.</p><p>Главный вывод: открытая ветка Qwen 3.6 готова к реальной агентной работе — не как игрушка, а как замена топ-проприетарных моделей в части задач.</p><p>Источники: <a href="https://huggingface.co/Qwen/Qwen3.6-35B-A3B">карточка модели на Hugging Face</a>, заметка <a href="https://simonwillison.net/2026/Apr/16/qwen-beats-opus/">Саймона Уиллисона от 16 апреля</a>, наш материал о закрытой <a href="https://tproger.ru/news/alibaba-vypustila-qwen3-6-plus---ii-model-dlya-agentnogo-kodinga">Qwen3.6-Plus</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>CSS Studio: визуальный редактор, который правит ваш код руками ИИ-агента</title>
      <link>https://tproger.ru/news/css-studio-vizualnyj-redaktor-kotoryj-pravit-vaw-kod-rukami-i</link>
      <comments>https://tproger.ru/news/css-studio-vizualnyj-redaktor-kotoryj-pravit-vaw-kod-rukami-i?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/css-studio-vizualnyj-redaktor-kotoryj-pravit-vaw-kod-rukami-i</guid>
      <description><![CDATA[<p>Автор Motion выпустил CSS Studio — визуальный редактор стилей в dev-сборке. Правите CSS руками, изменения через MCP уходят в Claude Code или Cursor.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/css-studio-vizualnyj-redaktor-kotoryj-pravit-vaw-kod-rukami-i">CSS Studio: визуальный редактор, который правит ваш код руками ИИ-агента</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 10 Apr 2026 17:15:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы регулярно объясняете <a href="https://claude.com/claude-code">Claude Code</a> или <a href="https://cursor.com">Cursor</a> текстом, какой именно padding вам нужен, — вот инструмент, который делает это за вас руками. Мэтт Перри, автор библиотеки <a href="https://motion.dev">Motion</a> (бывший Framer Motion), выпустил <a href="https://cssstudio.ai/">CSS Studio</a> — визуальный редактор стилей, который живёт прямо в вашей dev-сборке и шлёт изменения в ваш ИИ-агент через MCP. Запуск вылетел в топ Show HN.</p><ul><li>CSS Studio — визуальный WYSIWYG-редактор, который встраивается в ваш dev-сайт через npm-пакет.</li><li>Вы двигаете padding, шрифты, отступы, анимации руками; изменения через MCP-сервер уходят в Claude Code, Cursor или любой другой агент с MCP-поддержкой.</li><li>Агент правит код по месту: классы в Tailwind-проектах, объект стилей в CSS-in-JS, селектор в стайлшитах. Специальной поддержки Tailwind-токенов пока нет — token-режим в планах.</li><li>Цена: $99 за одно место.</li></ul><h2>Что это и зачем</h2><p>Сейчас типичный ИИ-воркфлоу для фронтенда выглядит так: вы открываете сайт в браузере, замечаете кривой отступ, идёте в чат агента и пишете «сделай padding у кнопки-подписки на два пикселя меньше и выровняй по базовой линии». Агент угадывает, какой компонент вы имели в виду, промахивается, вы поправляете. Через десять сообщений нужный padding наконец встал куда надо.</p><p>CSS Studio заменяет эту итерацию прямым редактированием. Вы добавляете npm-пакет в dev-сборку, запускаете её, в углу страницы появляется панель редактора. Кликаете на элемент, двигаете ползунки или тянете за точки — padding меняется в реальном времени в браузере. Когда результат нравится, нажимаете «Apply» (или включаете auto-apply). В этот момент подключённый ИИ-агент через MCP получает JSON-патч с описанием изменений и дописывает реальные файлы.</p><p>То есть вы получаете WYSIWYG-редактор, но результат приземляется в ваш настоящий код. Что с Tailwind — отдельный вопрос. Специальной интеграции с ним пока нет: визуальная панель показывает вычисленные CSS-значения, а агент уже сам догадывается, как их вернуть в исходник, — вслепую, без понимания Tailwind-токенов. Перри пообещал token/strict-режим с распознаванием Tailwind-классов и CSS-переменных, но это пока план. С CSS-in-JS и обычными стайлшитами проще: агент дотягивается до объекта стилей в компоненте или до нужного селектора в файле.</p><h2>Как это работает технически</h2><p>Всё завязано на <a href="https://modelcontextprotocol.io/">Model Context Protocol</a> — стандарт от Anthropic, который позволяет агентам подключаться к локальным инструментам (файлы, БД, сервисы) как к плагинам, без кастомной интеграции под каждый. CSS Studio поднимает локальный MCP-сервер рядом с вашим dev-сервером (подружиться с Vite получилось сразу, судя по отзыву разработчика mpeg на HN).</p><p>В Claude Code или Cursor вы запускаете команду /studio — и агент начинает слушать MCP-сервер. Когда вы в браузере двигаете слайдер padding, CSS Studio стримит агенту JSON вида «компонент такой-то, свойство такое-то, новое значение — вот такое, плюс информация о viewport и URL». Агент видит текущий контекст проекта, находит нужный файл и вносит правку по правилам кодовой базы.</p><p>Перри также упоминает, что для низкой задержки MCP-сервер может использовать Claude Channels — малоизвестную фичу Claude Code для стриминга. В обычном режиме агент периодически опрашивает MCP-сервер; Claude Channels снимают эту задержку.</p><h2>Что умеет</h2><ul><li><b>Стили</b> — padding, margin, цвета, шрифты, тени, бордеры, flex/grid-настройки через визуальные контролы.</li><li><b>Текст и контент</b> — прямое редактирование содержимого элементов без захода в файлы.</li><li><b>Лейаут</b> — добавление и удаление элементов, перестановка.</li><li><b>Анимации</b> — таймлайн-редактор для motion-эффектов (что логично от автора Motion).</li><li><b>Breakpoints</b> — редактор понимает, в каком брейкпоинте вы сейчас правите; canvas-режим для параллельного просмотра нескольких вьюпортов Перри дорабатывает прямо сейчас.</li><li><b>Рисование</b> — инструмент для набросков новых блоков на странице, потом отдаёте агенту на реализацию.</li></ul><h2>Кому полезно</h2><p>Первый очевидный сценарий — фронтендеры, которые уже сидят на ИИ-агентах для написания кода и устали от словесных описаний CSS-правок. Второй — дизайнеры и продакт-менеджеры, у которых нет доступа к репозиторию, но им нужно быстро подкрутить что-то на лендинге. Раньше они писали тикет, теперь — двигают слайдеры сами, агент пишет изменения в файлы.</p><p>Третий — QA и владельцы агентств, которые собирают десятки маркетинговых сайтов: визуальные правки через браузер с автоматической синхронизацией в код ускоряют финальную полировку. В комментариях на HN несколько человек отдельно отметили, что до этого сами писали похожие инструменты «на коленке» — значит потребность назрела.</p><h2>Что не так</h2><p>Цена — $99 за одно место, и комьюнити на HN это обсуждает активно. Сравнивают с Figma (около $160 за место) и с Cursor (те же $20 в месяц). Для команды из пяти человек выходит $495 в год. Перри в комментариях пообещал подумать над ценообразованием, а пока рассчитывает на ранних энтузиастов.</p><p>Второе — лендинг. Несколько комментаторов заметили, что сайт продукта для дизайна выглядит «как сгенерированный LLM» — слишком много фиолетового, шаблонная композиция, анимации fade-in. Для инструмента, который продаёт дизайн, это, мягко говоря, неловко. Перри признал и пообещал переделать.</p><p>Третье — зависимость от ИИ-агента с MCP. Если вы не сидите на Claude Code / Cursor / Windsurf и не планируете, CSS Studio для вас пока бесполезен: он не генерирует код самостоятельно, а только командует вашим агентом. Отдельная боль для российских разработчиков — оплата: Stripe из РФ не работает, нужна зарубежная карта или сервис-посредник. Зато живое демо на сайте cssstudio.ai доступно без регистрации, попробовать можно.</p><h2>Что это значит</h2><p>CSS Studio — один из первых публичных примеров того, как MCP превращается в инструмент «человек рисует, агент кодирует». До этого WYSIWYG-редакторы либо жили в отдельной вселенной (как Figma и Webflow), либо редактировали код напрямую, но теряли контекст проекта. MCP даёт третий путь: визуальный фронтенд + реальный агент с доступом к вашей кодовой базе.</p><p>Если такой подход взлетит, ждите аналогичных инструментов для других доменов: визуальный редактор схемы базы данных → агент правит миграции, визуальный редактор API → агент правит OpenAPI и генерирует клиент, визуальный редактор Grafana-дашбордов → агент правит Terraform. Базовая механика одна и та же.</p><p>Источники: <a href="https://cssstudio.ai/">cssstudio.ai</a>, <a href="https://news.ycombinator.com/item?id=47702196">обсуждение на Hacker News</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>9 нативных API браузера вместо npm-пакетов</title>
      <link>https://tproger.ru/translations/9-nativnyh-api-brauzera-vmesto-npm-paketov</link>
      <comments>https://tproger.ru/translations/9-nativnyh-api-brauzera-vmesto-npm-paketov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/9-nativnyh-api-brauzera-vmesto-npm-paketov</guid>
      <description><![CDATA[<p>9 встроенных API браузера вместо npm-пакетов: requestIdleCallback, :focus-within, container queries, dialog, Speech API и другие — с примерами кода.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/9-nativnyh-api-brauzera-vmesto-npm-paketov">9 нативных API браузера вместо npm-пакетов</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 10 Apr 2026 07:45:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы привыкли ставить npm-пакет под каждую задачу — вот девять вещей, под которые давно существует нативный API браузера. Кода меньше, багов меньше, бандл легче. Статья польской разработчицы Sylwia Łask собрала самые показательные примеры — перевели и адаптировали для русскоязычного читателя.</p><ul><li>requestIdleCallback — запустить фоновую задачу, когда браузер простаивает</li><li>:focus-within — стилизовать родителя, внутри которого есть элемент в фокусе</li><li>navigator.onLine + события offline/online — детектировать пропажу интернета</li><li>requestAnimationFrame — плавная анимация без рывков</li><li>Container queries — адаптив относительно размеров контейнера, а не viewport</li><li>crypto.getRandomValues — криптографически стойкие случайные ID без коллизий</li><li>&lt;dialog&gt; — нативный модал с доступностью из коробки</li><li>Web Speech API — распознавание речи без библиотек (только Chromium)</li><li>@supports — CSS feature detection без костылей</li></ul><h2>1. «Запустим это потом» → requestIdleCallback</h2><p>Хотите собирать аналитику, предзагружать данные или генерировать что-то в фоне, не конкурируя с рендером 200 компонентов? requestIdleCallback запускает ваш код в те моменты, когда браузер простаивает. На первый взгляд это кажется узкоспециальной фичей, но на практике кейсов много: сбор аналитики о поведении пользователя, несрочная фоновая обработка картинок, предварительная подготовка данных, которые пригодятся позже.</p><p>Поддержка: современные браузеры. В Safari исторически отсутствовал, так что fallback на setTimeout всё ещё полезен.</p><h2>2. «Почему мой input не подсвечивается?» → :focus-within</h2><p>Стилизовать элемент с фокусом — просто. А как стилизовать родителя, внутри которого какой-то элемент получил фокус, — задача, которую обычно решают сорока строками JavaScript со слушателями focus и blur. Всё это не нужно: :focus-within делает то же самое одной CSS-строкой.</p><p>Поддержка: везде, где это хоть сколько-нибудь важно.</p><h2>3. «Покажем офлайн-режим» → navigator.onLine</h2><p>Вечная боль любого PWA — что делать, когда у пользователя пропал интернет (он уехал в лес или зашёл в лифт). Можно писать сложные if-ы — а можно просто слушать события offline и online. На offline складываем данные в IndexedDB, на online отправляем на сервер.</p><p>Поддержка: широкая. Одна оговорка: «онлайн» не равно «ваш бэкенд доступен». Это проверка уровня сетевого соединения, а не доступности конкретного сервиса.</p><h2>4. «Плавная анимация, но проклятая» → requestAnimationFrame</h2><p>Хотите, чтобы анимация не дёргалась на слабых ноутбуках, а батарея садилась медленнее? Привычка «60 fps = setInterval каждые 16 мс» — плохая идея, и вот почему. Классика, которую все видели:</p><p>Интуитивно понятно, что это плохая идея. Лагает. К счастью, есть requestAnimationFrame — он синхронизирован с циклом перерисовки браузера, поэтому анимация действительно плавная.</p><p>Поддержка: везде.</p><h2>5. «Карточка должна адаптироваться, но только здесь» → container queries</h2><p>Одну и ту же карточку можно положить в узкий сайдбар, в основную ленту или в лайтбокс — и чтобы она корректно подстраивалась под каждое место без знания о том, на каком она экране. Раньше media queries были привязаны к размеру viewport, то есть «ко всей странице». Container queries позволяют применять стили в зависимости от размера конкретного контейнера. Компонент становится самодостаточным: куда положили — под то и подстроился.</p><p>Поддержка: современные браузеры. Если целитесь в старые — добавьте fallback через обычные media queries.</p><h2>6. «Случайный ID, что может пойти не так?» → crypto.getRandomValues</h2><p>Именно так рождаются баги:</p><p>Выглядит как «достаточно случайная» криптография с AliExpress — и работает, пока не перестаёт. Во-первых, всё зависит от реализации движка, мы не знаем, что происходит под капотом. Во-вторых, определённые паттерны вполне возможны, а при большом количестве ID вы фактически напрашиваетесь на коллизии.</p><p>К счастью, есть нативное решение. Не серебряная пуля, но crypto.getRandomValues заметно лучше: больше энтропии, нет странных паттернов, вероятность коллизий резко снижается. Браузер просто делает это правильно. А если вам нужен не произвольный набор байтов, а именно UUID, в современных браузерах есть ещё короче: crypto.randomUUID() выдаёт готовый UUID v4 одной строкой — тоже криптографически стойко и без ручной возни с байтами.</p><p>Поддержка: широкая.</p><h2>7. «Нам нужен модал» → dialog</h2><p>Больше не нужно ставить 12-килобайтную библиотеку ради модального окна, которое так любят пользователи. Нативный &lt;dialog&gt; даёт клавиатурную навигацию, фокус-трап и корректную работу со скринридерами прямо из коробки — всё то, что в самописных модалах обычно забывают или делают криво.</p><p>Поддержка: современные браузеры.</p><h2>8. «Голосовой ввод был бы крутой фичей» → Web Speech API</h2><p>Собирались ставить transformers.js, потому что понадобилось распознавание речи? У браузера для этого уже есть Web Speech API. Chromium-браузеры поддерживают его напрямую, Safari — через префиксную версию webkitSpeechRecognition (код ниже как раз это учитывает), в Firefox поддержки нет. Для демо и ассистивных фич — отлично, в проде лучше иметь запасной план на случай Firefox.</p><p>Поддержка: Chromium и Safari (через webkit-префикс), в Firefox до сих пор нет.</p><h2>9. «Не сломает ли это CSS?» → @supports</h2><p>Хотите выкатить backdrop-filter или :has() и при этом не сломать вёрстку в браузере, где фича ещё не поддерживается? Оборачиваем в @supports — и спокойны: браузер, который знает фичу, получит красивую версию, остальные — дефолтный fallback.</p><p>Поддержка: очень хорошая.</p><h2>Когда всё-таки нужна библиотека</h2><p>Библиотеки — это отлично, и иногда они действительно необходимы. Но иногда вы ставите зависимость на то, что браузер решил годы назад. Перед npm install полезно спросить себя (или поискать в MDN): «А браузер не умнее меня в этом вопросе?» Иногда ответ — да. И это нормально.</p><p>Источник: <a href="https://dev.to/sylwia-lask/9-things-youre-overengineering-the-browser-already-solved-them-o99">Sylwia Łask — 9 things you're overengineering: the browser already solved them</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Alibaba выпустила Qwen3.6-Plus — ИИ-модель для агентного кодинга с контекстом в 1 млн токенов</title>
      <link>https://tproger.ru/news/alibaba-vypustila-qwen3-6-plus---ii-model-dlya-agentnogo-kodinga</link>
      <comments>https://tproger.ru/news/alibaba-vypustila-qwen3-6-plus---ii-model-dlya-agentnogo-kodinga?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/alibaba-vypustila-qwen3-6-plus---ii-model-dlya-agentnogo-kodinga</guid>
      <description><![CDATA[<p>Alibaba выпустила Qwen3.6-Plus с контекстом 1 млн токенов. Обгоняет Claude Opus на бенчмарках Terminal-Bench и OmniDocBench. Бесплатна на OpenRouter.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/alibaba-vypustila-qwen3-6-plus---ii-model-dlya-agentnogo-kodinga">Alibaba выпустила Qwen3.6-Plus — ИИ-модель для агентного кодинга с контекстом в 1 млн токенов</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 16:23:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Alibaba выпустила <a href="https://openrouter.ai/qwen/qwen3.6-plus-preview">Qwen3.6-Plus</a> — новую языковую модель, ориентированную на агентные задачи: автономное написание кода, работу с длинными документами и многошаговые сценарии. Модель доступна бесплатно в preview-режиме на OpenRouter.</p><p>Qwen3.6-Plus поддерживает контекстное окно в 1 млн токенов (около 2000 страниц текста) и генерирует до 65 536 выходных токенов. По ранним тестам, модель работает по замерам пользователей OpenRouter, примерно в 3 раза быстрее Claude Opus 4.5.</p><ul><li>Qwen3.6-Plus — новая модель Alibaba для агентного кодинга и длинных документов</li><li>Контекст 1 млн токенов, до 65 536 выходных токенов</li><li>Поддерживает режим цепочечного мышления (thinking mode) и нативный вызов функций</li><li>Обгоняет Claude 4.5 Opus на Terminal-Bench 2.0 (61,6 vs 59,3) и OmniDocBench (91,2 vs 87,7)</li><li>Бесплатна в preview на OpenRouter, но free tier собирает промпты для обучения</li></ul><h2>Бенчмарки: где Qwen3.6-Plus выигрывает</h2><p>По опубликованным результатам Qwen3.6-Plus показывает сильные результаты на агентных и документных бенчмарках:</p><ul><li><b>Terminal-Bench 2.0</b> (агентный кодинг в терминале) — 61,6 vs 59,3 у Claude 4.5 Opus</li><li><b>OmniDocBench v1.5</b> (распознавание документов) — 91,2 vs 87,7 у Claude 4.5 Opus</li><li><b>RealWorldQA</b> (рассуждение по изображениям) — 85,4 vs 77,0 у Claude 4.5 Opus</li><li><b>SWE-bench Verified</b> (исправление багов в реальных репозиториях) — 78,8, уступает Claude 4.5 Opus (80,9)</li></ul><p>Модель поддерживает обработку изображений в контексте документных и аналитических задач, но не предназначена для генерации изображений.</p><h2>Архитектура и скорость</h2><p>Qwen3.6-Plus построена на гибридной архитектуре нового поколения. Ранние пользователи отмечают, что модель «более решительна» в ответах — использует меньше токенов для достижения результата и показывает лучшую надёжность в многошаговых агентных сценариях.</p><p>Скорость генерации — примерно в 3 раза выше, чем у Claude Opus 4.6 по ранним замерам сообщества. Однако time-to-first-token на бесплатном тире составляет в среднем 11,5 секунд, что ощутимо влияет на интерактивные сценарии.</p><h2>Доступность и ограничения</h2><ul><li>Доступна на <a href="https://openrouter.ai/qwen/qwen3.6-plus-preview">OpenRouter</a> бесплатно в preview-режиме</li><li>Бесплатный тир собирает промпты и ответы для обучения — учитывайте при работе с конфиденциальными данными</li><li>Платный API-доступ без сбора данных также доступен</li><li>Нативный вызов функций (function calling) — можно использовать как агента без дополнительных обёрток</li></ul><h2>Выводы</h2><p>Qwen3.6-Plus — сильная модель для агентных задач, особенно в кодинге и работе с документами. Бесплатный preview на OpenRouter подходит для прототипирования и личных проектов, для production — платный API.</p>]]></content:encoded>
    </item>
    <item>
      <title>Доля Linux в Steam впервые превысила 5% — это вдвое больше, чем у macOS</title>
      <link>https://tproger.ru/news/dolya-linux-v-steam-vpervye-prevysila-5----eto-vdvoe-bolwe--chem-</link>
      <comments>https://tproger.ru/news/dolya-linux-v-steam-vpervye-prevysila-5----eto-vdvoe-bolwe--chem-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/dolya-linux-v-steam-vpervye-prevysila-5----eto-vdvoe-bolwe--chem-</guid>
      <description><![CDATA[<p>Steam Survey за март 2026: Linux достиг рекордных 5,33%, вдвое обогнав macOS. Разбираемся в причинах скачка и что это значит для игр и разработчиков.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/dolya-linux-v-steam-vpervye-prevysila-5----eto-vdvoe-bolwe--chem-">Доля Linux в Steam впервые превысила 5% — это вдвое больше, чем у macOS</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Юмор]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 15:21:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>Доля Linux в <a href="https://store.steampowered.com/hwsurvey/">ежемесячном опросе Steam</a> за март 2026 года впервые в истории превысила 5%, достигнув 5,33%. Это абсолютный рекорд для Linux-гейминга и более чем двукратное превосходство над macOS.</p><p>Скачок на 3,1 процентного пункта за месяц частично объясняется коррекцией данных по Steam China, но органический рост Linux в Steam — устойчивый тренд последних лет.</p><ul><li>Linux достиг 5,33% в Steam Survey за март 2026 — исторический максимум</li><li>Рост на 3,1 п.п. за месяц — с 2,23% в феврале до 5,33% в марте</li><li>macOS — 2,35% (+1,19%), Linux теперь вдвое популярнее Mac для гейминга</li><li>Windows потерял 4,28%, снизившись до 92,33%</li><li>Часть скачка объясняется коррекцией данных Steam China</li></ul><h2>Что за скачок и почему сразу +3%</h2><p>Часть скачка <a href="https://www.phoronix.com/news/Steam-On-Linux-Tops-5p">объясняется</a> тем, что Valve скорректировала данные по Steam China. Доля упрощённого китайского языка упала на 31,85%, а доля английского выросла на 16,82% до 39,09%. Это влияет на общую статистику, так как Steam China работает преимущественно на Windows.</p><p>Тем не менее тренд реален: Linux стабильно растёт в Steam уже несколько лет, благодаря Proton, Steam Deck и улучшению совместимости с играми.</p><h2>Почему Linux растёт в гейминге</h2><ul><li><b>Steam Deck</b> — портативная консоль Valve работает на SteamOS (Arch Linux), и каждый проданный Deck увеличивает долю Linux</li><li><b>Proton</b> — слой совместимости позволяет запускать Windows-игры на Linux без танцев с бубном. По данным ProtonDB, более 80% топ-100 игр Steam работают на Linux</li><li><b>SteamOS на десктопах</b> — Valve постепенно расширяет SteamOS за пределы Steam Deck</li><li><b>Улучшение драйверов</b> — AMD и Intel активно развивают open-source драйверы для Linux</li></ul><h2>Что это значит для разработчиков игр</h2><p>5% — это психологический барьер. При 2-3% Linux-поддержку можно было игнорировать. При 5%+ — это уже значимая аудитория.</p><p>Для инди-разработчиков это сигнал: тестирование на Linux через Proton (или нативные билды) окупается.</p><h2>Выводы</h2><p>5,33% — новая веха для Linux в гейминге. Даже с учётом статистической коррекции, органический рост очевиден. Steam Deck, Proton и SteamOS делают Linux всё более серьёзной игровой платформой.</p>]]></content:encoded>
    </item>
    <item>
      <title>LinkedIn тайно сканирует компьютеры пользователей и передаёт данные третьим сторонам — расследование BrowserGate</title>
      <link>https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan</link>
      <comments>https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan</guid>
      <description><![CDATA[<p>Расследование BrowserGate: LinkedIn сканирует ПО и расширения, выявляя религию и поиск работы. Данные уходят третьим сторонам. Подробности и как защититься.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan">LinkedIn тайно сканирует компьютеры пользователей и передаёт данные третьим сторонам — расследование BrowserGate</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Юмор]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 14:25:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ассоциация коммерческих пользователей LinkedIn — <a href="https://browsergate.eu/">Fairlinked e.V.</a> — опубликовала расследование под названием BrowserGate. Согласно их данным, LinkedIn тайно сканирует компьютеры пользователей, определяя установленное ПО и передаёт результаты третьим сторонам.</p><p>Каждый раз, когда любой из миллиарда пользователей LinkedIn заходит на сайт, скрытый код проверяет, какие программы и расширения браузера установлены на компьютере. Результаты отправляются на серверы LinkedIn и третьим компаниям, включая американо-израильскую фирму HUMAN Security (ранее PerimeterX). Пользователя не предупреждают и не спрашивают согласия.</p><ul><li>LinkedIn тайно сканирует установленное ПО на компьютерах пользователей при каждом визите на сайт</li><li>Сканирование выявляет религиозные убеждения, политические взгляды, инвалидность и поиск работы — через расширения браузера</li><li>LinkedIn определяет более 6000 продуктов, включая 200+ конкурирующих инструментов продаж</li><li>Данные передаются третьим сторонам без уведомления и согласия</li><li>По мнению исследователей, это нарушает GDPR и может быть уголовным преступлением в ЕС</li></ul><h2>Что именно сканирует LinkedIn</h2><p>По данным расследования, LinkedIn сканирует расширения браузера, которые раскрывают чувствительную информацию о пользователях:</p><ul><li>Религиозные убеждения — расширения для практикующих мусульман</li><li>Политическая ориентация — расширения, связанные с политическими предпочтениями</li><li>Нейроотличность — расширения для пользователей с СДВГ, аутизмом и другими особенностями</li><li>Поиск работы — 509 инструментов для поиска вакансий, которые выдают тех, кто тайно ищет новое место</li></ul><p>Поскольку LinkedIn знает реальное имя, работодателя и должность каждого пользователя, это не анонимное сканирование — это сбор данных о конкретных людях в конкретных компаниях.</p><h2>Корпоративный шпионаж: сканирование конкурентов</h2><p>LinkedIn сканирует более 200 продуктов, напрямую конкурирующих с его собственными инструментами продаж — Apollo, Lusha, ZoomInfo и другие. Зная работодателя каждого пользователя, платформа может составить карту: какие компании используют какие конкурирующие продукты.</p><p>По утверждению исследователей, LinkedIn уже использует эти данные — отправляет угрозы пользователям сторонних инструментов, идентифицируя их через скрытое сканирование. Список сканируемых продуктов вырос с около 461 в 2024 году до более чем 6000 к февралю 2026 года.</p><h2>Обман европейских регуляторов</h2><p>В 2023 году ЕС признал LinkedIn регулируемым гейткипером по Digital Markets Act и обязал открыть платформу для сторонних инструментов. LinkedIn опубликовал два ограниченных API, обрабатывающих около 0,07 запросов в секунду. При этом внутренний API Voyager, на котором работают все продукты LinkedIn, обрабатывает 163 000 запросов в секунду.</p><p>В 249-страничном отчёте Microsoft для Еврокомиссии слово «API» встречается 533 раза. Слово «Voyager» — ноль раз.</p><blockquote>ЕС потребовал от LinkedIn впустить сторонние инструменты. LinkedIn построил систему слежки, чтобы находить и наказывать каждого пользователя этих инструментов.</blockquote><h2>Передача данных третьим сторонам</h2><p>LinkedIn загружает невидимый трекинговый элемент от HUMAN Security — нулевой ширины, скрытый за пределами экрана — который устанавливает куки без ведома пользователя. Отдельный скрипт фингерпринтинга работает с серверов LinkedIn. Третий скрипт от Google выполняется молча при каждой загрузке страницы. Всё зашифровано. Ничего не раскрыто в политике конфиденциальности.</p><p><b>Важный контекст:</b> сканирование расширений браузера — известная техника борьбы с ботами и мошенничеством. HUMAN Security (PerimeterX) — именно anti-bot компания. LinkedIn может аргументировать, что сканирование нужно для защиты платформы. Расследование Fairlinked e.V. представляет одну сторону — независимая верификация их утверждений пока не проводилась.</p><h2>Правовые последствия</h2><p>Исследователи утверждают, что действия LinkedIn нарушают GDPR, поскольку сканирование выявляет данные особых категорий (религия, политика, здоровье) без согласия и без правовой основы. По законодательству ЕС такие данные не просто регулируются — их обработка запрещена без явного согласия.</p><p>Fairlinked e.V. собирает доказательную базу и средства для судебного разбирательства. На момент публикации Microsoft и LinkedIn не прокомментировали расследование.</p><h2>Выводы</h2><p>Расследование BrowserGate — одно из крупнейших обвинений в корпоративном шпионаже в истории веба. Если данные подтвердятся, LinkedIn и Microsoft могут столкнуться с серьёзными штрафами по GDPR и Digital Markets Act.</p><p><a href="https://browsergate.eu/">Полное расследование</a> и доказательная база доступны на сайте BrowserGate.</p>]]></content:encoded>
    </item>
    <item>
      <title>ASPA — как новый стандарт проверяет путь интернет-трафика и защищает от утечек маршрутов</title>
      <link>https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi</link>
      <comments>https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi</guid>
      <description><![CDATA[<p>Как ASPA дополняет RPKI/ROA, проверяя не только пункт назначения, но и весь путь трафика. Перевод статьи Cloudflare о новом стандарте безопасности BGP.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi">ASPA — как новый стандарт проверяет путь интернет-трафика и защищает от утечек маршрутов</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[смарт-контракты]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 12:37:12 GMT</pubDate>
      <content:encoded><![CDATA[<p>Это перевод с адаптацией <a href="https://blog.cloudflare.com/aspa-secure-internet/">статьи</a> Mingwei Zhang и Bryton Herdes из блога <a href="https://blog.cloudflare.com/">Cloudflare</a>.</p><p>BGP (Border Gateway Protocol) — протокол, по которому автономные системы (AS) обмениваются информацией о маршрутах. Автономная система — это сеть под управлением одного оператора: провайдера, облачной платформы, крупной компании. Когда вы открываете сайт, трафик проходит через цепочку таких AS. Но иногда он уходит не туда — из-за ошибок конфигурации или злонамеренных действий. Такие инциденты называются утечками маршрутов (route leaks). Новый криптографический стандарт ASPA (Autonomous System Provider Authorization) призван решить эту проблему — он проверяет не только пункт назначения, но и весь путь трафика.</p><ul><li>ASPA — новый стандарт криптографической проверки маршрутов BGP, дополняющий существующий RPKI/ROA</li><li>ROA проверяет пункт назначения трафика, ASPA проверяет путь — цепочку сетей, через которые он проходит</li><li>ASPA обнаруживает утечки маршрутов, проверяя, что трафик движется по «горной» модели: вверх к провайдеру, через пиринг, вниз к получателю</li><li>Создать ASPA-запись можно за пару кликов в RIPE или ARIN</li><li>Cloudflare Radar теперь отслеживает глобальное внедрение ASPA в реальном времени</li></ul><h2>Как сейчас защищён BGP: RPKI и ROA</h2><p>Сегодня сети используют инфраструктуру <a href="https://blog.cloudflare.com/rpki/">RPKI</a> (Resource Public Key Infrastructure), внедрение которой значительно выросло за последние годы. В рамках RPKI сети публикуют криптографические записи — ROA (Route Origin Authorizations). ROA — это верифицируемое цифровое удостоверение, подтверждающее, что конкретная автономная система (AS) авторизована анонсировать определённые IP-адреса. Это решает проблему origin hijacks — когда одна сеть выдаёт себя за другую.</p><p>Но ROA проверяет только пункт назначения. А что насчёт пути?</p><h2>Что такое ASPA и как он работает</h2><p>ASPA (Autonomous System Provider Authorization) надстраивается над RPKI. Если ROA проверяет <b>куда</b> идёт трафик, то ASPA проверяет <b>как</b> он туда добирается.</p><p>Когда данные путешествуют по интернету, каждая сеть на пути записывается в лог — AS_PATH. ASPA позволяет сетям официально публиковать список авторизованных апстрим-провайдеров в системе RPKI. Любая принимающая сеть может посмотреть на AS_PATH, проверить ASPA-записи и убедиться, что трафик прошёл только через одобренную цепочку сетей.</p><h3>Модель «горы»: как устроена здоровая маршрутизация</h3><p>В нормальной топологии (valley-free routing) трафик движется по «горной» модели:</p><ol><li><b>Подъём (Up-Ramp)</b> — трафик идёт от клиента вверх через всё более крупных провайдеров (ISP)</li><li><b>Вершина (Apex)</b> — на уровне магистрали трафик может пересечь один пиринговый линк</li><li><b>Спуск (Down-Ramp)</b> — трафик спускается через провайдеров к получателю</li></ol><p>Один из типов утечки — «долина» в этой модели. Она происходит, когда трафик спускается к клиенту и неожиданно пытается снова подняться к другому провайдеру. Клиентские сети не предназначены для транзита трафика между крупными провайдерами.</p><h3>Как ASPA валидирует маршруты</h3><p>ASPA проверяет цепочку отношений с обоих концов маршрута:</p><ol><li><b>Проверка подъёма</b> — начинаем от источника и двигаемся вперёд. На каждом хопе спрашиваем: «Авторизовала ли эта сеть следующую как своего провайдера?»</li><li><b>Проверка спуска</b> — то же самое, но в обратном направлении от получателя BGP-обновления</li></ol><p>Если «подъём» и «спуск» встречаются или пересекаются на вершине — маршрут <b>валидный</b>. Форма горы сохранена.</p><p>Если пути не сходятся и в середине есть разрыв — ASPA отмечает маршрут как проблемный. Этот разрыв и есть «долина», то есть утечка.</p><h3>Пример: обнаружение утечки маршрута</h3><p>Допустим, сеть AS65539 получает подозрительный маршрут от клиента AS65538. Клиент пытается отправить трафик, полученный от одного провайдера (AS65537), «вверх» к другому провайдеру (AS65539) — действуя как мост между провайдерами. Это классическая утечка маршрута.</p><p>Процесс валидации ASPA:</p><ol><li>Проверяем подъём: источник (AS65536) авторизует своего провайдера — проверка пройдена</li><li>Проверяем спуск: начинаем от получателя и смотрим назад — видим клиента (AS65538)</li><li>Несовпадение: подъём заканчивается на AS65537, спуск — на AS65538. Пути не соединяются</li></ol><p>Результат: маршрут отмечен как <b>ASPA Invalid</b>. Без подписанных ASPA-объектов в RPKI невозможно определить, какие сети авторизованы анонсировать префиксы горизонтально (пирам) или вверх (провайдерам).</p><h2>ASPA против forged-origin hijacks</h2><p>ASPA эффективно защищает от forged-origin hijacks — атак, при которых злоумышленник обходит проверку ROV: он анонсирует реальный IP-префикс с правильным origin AS, но вставляет себя в AS_PATH как промежуточный хоп. ROV это не замечает, так как проверяет только origin. Источник формально правильный, но связь между атакующим и жертвой — сфабрикована.</p><p>ASPA разоблачает это: сеть-жертва криптографически объявляет своих реальных провайдеров, и поскольку атакующий не входит в этот список, маршрут отклоняется.</p><p><b>Ограничение:</b> ASPA не защищает от всех случаев. Провайдер может подделать пиринговый линк с другой AS, чтобы привлечь трафик клиента коротким AS_PATH, даже если такого пирингового линка в реальности не существует. ASPA работает только с информацией о провайдерах и ничего не знает о пиринговых отношениях.</p><h2>Как создать ASPA-запись: пара кликов</h2><p>Создание ASPA-объекта для вашей сети стало простым в реестрах <a href="https://www.ripe.net/">RIPE</a> и <a href="https://www.arin.net/">ARIN</a>. Всё, что нужно — ваш номер AS и номера AS ваших провайдеров, у которых вы покупаете транзит. В обратном направлении это сети, которым вы разрешаете присылать полную таблицу маршрутизации — карту достижимости остального интернета.</p><p>Пример Cloudflare: для AS203898 (офис в Лондоне) с тремя интернет-провайдерами (AS8220, AS2860, AS1273) процесс занимает три шага:</p><ol><li>Войти в RPKI-дашборд RIPE и перейти в раздел ASPA</li><li>Нажать «Create ASPA» для нужного AS</li><li>Указать список провайдеров</li></ol><p>Через короткое время ASPA-запись появляется в глобальной RPKI-экосистеме.</p><p>Отдельный случай — запись с <b>AS0</b> в качестве провайдера. Это означает, что у сети нет апстрим-провайдеров. По определению, каждая транзитно-свободная сеть Tier-1 в будущем должна будет подписать ASPA только с «AS0» — если у неё действительно только пиринговые и клиентские отношения.</p><h2>Мониторинг ASPA в Cloudflare Radar</h2><p><a href="https://radar.cloudflare.com/">Cloudflare Radar</a> добавил новые возможности мониторинга внедрения ASPA:</p><ul><li>Графики роста внедрения ASPA по пяти региональным реестрам (RIR)</li><li>Интеграция ASPA-данных в страницы маршрутизации по странам и ASN</li><li>Для каждой AS — список провайдеров из ASPA-объекта, проверка BGP-апстримов и история изменений</li></ul><h2>Что нужно для полного внедрения ASPA</h2><p>ASPA — это криптографический фундамент для валидации путей. Но, как показал опыт RPKI/ROA, внедрение займёт время. Необходимы обновления:</p><ul><li>RPKI Relying Party (RP) — программы проверки криптографических записей</li><li>RTR (RPKI-to-Router protocol) — протокол передачи данных маршрутизаторам</li><li>BGP-реализации на маршрутизаторах — для валидации путей с использованием ASPA</li></ul><p>Помимо создания ASPA-записей, операторам рекомендуется настроить <b>BGP roles</b> (<a href="https://www.rfc-editor.org/rfc/rfc9234">RFC 9234</a>). BGP roles привязывают предполагаемые отношения между AS к конкретным BGP-сессиям, помогая ASPA определить, какой алгоритм валидации применять — для апстрима или даунстрима. Уточните у своих вендоров оборудования, поддерживают ли они BGP roles и атрибут OTC (Only-to-Customer).</p><blockquote>Управление ASPA-записями не отличается от управления ROA. В будущем, когда сети начнут активно блокировать невалидные пути, пропуск легитимного провайдера может привести к потере трафика. Но это тот же риск, который операторы уже научились контролировать.</blockquote><h2>Выводы</h2><p>ASPA — следующий логичный шаг в безопасности интернет-маршрутизации после RPKI/ROA. Если ROA закрепил за каждой AS право анонсировать свои IP-адреса, то ASPA закрепляет право на транзит — описывает авторизованный путь трафика.</p><p>Для операторов сетей: <a href="https://radar.cloudflare.com/">проверьте в Cloudflare Radar</a>, есть ли у вашей AS ASPA-запись, и создайте её в RIPE или ARIN. Чем больше сетей подпишут ASPA, тем быстрее стандарт начнёт реально блокировать утечки маршрутов.</p>]]></content:encoded>
    </item>
    <item>
      <title>Переосмысление пулл-реквестов: почему code review должен учить, а не только ловить баги</title>
      <link>https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--</link>
      <comments>https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--</guid>
      <description><![CDATA[<p>Как стековые PR, приоритет файлов в диффе и единая страница ревью сокращают comprehension debt. Перевод статьи создателя Lubeno о будущем code review.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--">Переосмысление пулл-реквестов: почему code review должен учить, а не только ловить баги</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Организация разработки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 12:28:46 GMT</pubDate>
      <content:encoded><![CDATA[<p>Это перевод с адаптацией <a href="https://lubeno.dev/blog/reinventing-the-pull-request">статьи</a> Bernard Kolobara, автора платформы <a href="https://lubeno.dev">Lubeno</a>.</p><p>Пулл-реквесты задумывались как инструмент для совместной работы над кодом. На практике они превратились в бюрократическую процедуру: гигантские диффы, комментарии в разных вкладках, коллапсированные «outdated»-ветки обсуждений. Bernard Kolobara считает, что проблема не в самой идее code review, а в инструментах — и предлагает конкретные решения.</p><ul><li>Comprehension debt (долг понимания) — главная проблема, которую должен решать code review, а не только ловля багов</li><li>Стековые пулл-реквесты: разбиение изменений на мелкие самодостаточные коммиты, которые ревьюятся независимо</li><li>Приоритет файлов: тесты и зависимости показываются первыми в диффе через .gitattributes</li><li>Всё на одной странице: код и обсуждение вместе, без вкладок</li><li>ИИ не убил code review — он обнажил хрупкость инструментов, которые не справляются с растущим объёмом кода</li></ul><h2>Comprehension debt: долг понимания кода</h2><p>Addy Osmani <a href="https://addyosmani.com/blog/comprehension-debt/">описал</a> comprehension debt как разрыв между объёмом кода в проекте и тем, сколько из этого кода команда реально понимает. Чем больше разрыв — тем медленнее работа. Проектировать систему, которую полностью понимаешь, проще, чем ту, которую «примерно знаешь». С появлением ИИ-агентов в рабочих процессах этот разрыв значительно вырос.</p><p>Paul Graham в эссе <a href="https://paulgraham.com/greatwork.html">о великой работе</a> пишет, что лучшие идеи приходят вне клавиатуры — на прогулке, в душе, перед сном. Но для этого «фонового процессинга» нужно, чтобы контекст проекта уже был в голове. Сначала нужна осознанная работа с кодом.</p><p>Code review — идеальный момент для сокращения этого разрыва. Каждый ревью — возможность узнать, как кодовая база развивается, каковы её границы и ограничения. Не обязательно проверять каждую строку дифа — достаточно понять ключевые части, чтобы обновить ментальную модель. Ловля багов — лишь <a href="https://www.davidpoll.com/2026/02/code-review-is-not-about-catching-bugs">одна часть</a> ценности ревью.</p><h2>Как сократить разрыв: конкретные решения</h2><h3>Стековые пулл-реквесты</h3><p>Разбить большой PR на маленькие — самый эффективный способ помочь ревьюеру. В теории для этого подходят коммиты: каждый — самодостаточная единица, <a href="https://youtu.be/GOrKfCs-mr0?si=SWndwJF0IWOF-SG7&amp;t=102">рассказывающая историю</a>. На практике это не работает из-за Git.</p><p>Git заточен под append-only workflow. Вернуться в старый коммит и отредактировать его — мучительно. Даже если вы аккуратно структурировали историю, рано или поздно появляется серия коммитов «fix», «actual fix», «ok now really fix». Когда смотришь на отдельный коммит, не видишь полной картины — правки могут быть размазаны по нескольким коммитам дальше по истории.</p><p>Bernard и его коллега Luísa решают эту проблему с помощью <a href="https://docs.jj-vcs.dev/latest/">Jujutsu</a> — VCS, которая позволяет прыгнуть в любой коммит и отредактировать его на месте, а затем автоматически пропагирует изменения через всю историю. Это позволяет «вылепить» идеальную историю коммитов.</p><p>В Lubeno стековые PR детектятся автоматически. Каждый PR показывается как дифф относительно родительского PR — ревью и одобрение идут независимо. Автор не ждёт, пока предыдущий PR смёржат, и может продолжать работу.</p><h3>Приоритет файлов в диффе</h3><p>При ревью автор первым делом смотрит тесты: были ли изменены существующие, тестируют ли новые что-то полезное. Затем — зависимости: добавляется ли новая и зачем. Но все платформы для code review показывают файлы в алфавитном порядке — важные изменения легко пропустить в большом диффе.</p><p>Lubeno использует кастомный атрибут priority в .gitattributes (это не стандартный атрибут Git, а расширение Lubeno):</p><p>Файлы с высоким приоритетом показываются первыми на странице PR. Простое решение, но оно гарантирует, что самые важные изменения вы увидите сразу.</p><h3>Всё на одной странице</h3><p>Почти все платформы для code review разносят комментарии, коммиты и код по разным вкладкам. Автор признаётся: «Я нажимал на вкладку Commits только по ошибке — ни разу намеренно». Обсуждение тесно связано с кодом, но чтобы следить за ним, приходится постоянно скроллить наверх, переключать вкладки и искать нужный фрагмент.</p><p>В Lubeno нет вкладок на странице PR. Код и обсуждение живут в одном месте.</p><h2>Эволюция кода в рамках PR</h2><p>PR — не статичная сущность. Это место для обсуждения и итераций. Знакомая ситуация: вы оставили комментарий, вернулись — и обнаружили несколько новых коммитов, а все ваши комментарии свёрнуты как «outdated». Непонятно, учтены ли ваши замечания, что изменилось с момента вашего последнего просмотра.</p><p>Lubeno отслеживает комментарии к коду и наложение interdiff (разницу между версиями файла в рамках PR): если код был изменён более поздним коммитом (или force push), разница видна прямо в контексте комментария. Не нужно переключаться между вкладками, чтобы понять, что произошло.</p><h2>Будущее пулл-реквестов</h2><p>Некоторые <a href="https://boristane.com/blog/the-software-development-lifecycle-is-dead/">называют</a> PR «реликтом прошлого» и призывают от них отказаться. Автор не согласен: процесс ревью кода сегодня ценнее, чем когда-либо. ИИ не убил code review — он обнажил хрупкость инструментов. Больше строк кода просто сделали их непригодными.</p><p>Code review находится в идеальной точке жизненного цикла: после всей творческой работы и прямо перед продакшном. Это последний шанс разобраться, что именно поедет к пользователям. Если вы хотите создавать продукт, который радует пользователей, вам нужно понимать, что происходит в коде.</p><h2>Выводы</h2><p>Статья Bernard Kolobara — не абстрактные размышления, а описание конкретных решений, реализованных в <a href="https://lubeno.dev">Lubeno</a>. Даже если вы не планируете переходить с GitHub — идеи стековых PR, приоритета файлов и unified-страницы ревью стоит примерить к своему workflow.</p><p>Ключевой тезис: code review — не бюрократия, а инструмент обучения. Каждый ревью должен делать команду чуть умнее, а не просто ставить галочку.</p>]]></content:encoded>
    </item>
    <item>
      <title>Python: полный путеводитель для разработчика</title>
      <link>https://tproger.ru/articles/python--polnyj-putevoditel-dlya-razrabotchika</link>
      <comments>https://tproger.ru/articles/python--polnyj-putevoditel-dlya-razrabotchika?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Картофельный Повелитель]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/python--polnyj-putevoditel-dlya-razrabotchika</guid>
      <description><![CDATA[<p>Структурированный гайд по Python: синтаксис, ООП, Django/FastAPI, Data Science, asyncio и GIL. Примеры кода и ссылки на углублённые материалы.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/python--polnyj-putevoditel-dlya-razrabotchika">Python: полный путеводитель для разработчика</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[Data Science]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 11:17:39 GMT</pubDate>
      <content:encoded><![CDATA[<p>Python — высокоуровневый интерпретируемый язык программирования общего назначения, который уверенно входит в тройку самых популярных языков программирования в мире. По данным индекса <a href="https://www.tiobe.com/tiobe-index/">TIOBE</a> на начало 2026 года, он стабильно удерживает первое место, а <a href="https://survey.stackoverflow.co/2024/">Stack Overflow Developer Survey</a> подтверждает: Python остаётся одним из самых желанных языков для изучения. Причина — универсальность: веб-приложения, нейросети, автоматизация, анализ данных, боты и управление инфраструктурой. Чистый синтаксис, читаемый код и гигантская экосистема библиотек позволяют писать рабочие программы уже после нескольких часов знакомства с языком.</p><p>В октябре 2025 года вышел Python 3.14 с экспериментальным JIT-компилятором и поддержкой шаблонных T-строк — язык продолжает ускоряться, не жертвуя простотой. Экосистема тоже не стоит на месте: FastAPI стал стандартом для высокопроизводительных API, а инструменты вроде Ruff и uv радикально ускорили рабочий процесс разработчика. Python Package Index (<a href="https://pypi.org/">PyPI</a>) насчитывает более 600 000 пакетов — для любой задачи, скорее всего, уже существует готовое решение.</p><p>Этот путеводитель — не энциклопедия и не учебник. Это навигационный хаб: мы кратко разберём каждую важную область Python и дадим ссылки на подробные материалы Tproger, где каждая тема раскрыта в деталях. Неважно, только начинаете вы знакомство с языком или уже пишете на нём продакшен-код — здесь вы найдёте структурированную карту для дальнейшего роста. Мы охватим основы синтаксиса, продвинутые концепции, три главных веб-фреймворка, Data Science, последние нововведения в Python 3.14 и карьерные перспективы.</p><p>— Python — язык №1 по TIOBE 2026, более 600 000 пакетов в PyPI</p><p>— Основы языка: динамическая типизация, duck typing, встроенные коллекции (list, tuple, dict, set и другие)</p><p>— Три главных веб-фреймворка: Django (full-stack), Flask (микро), FastAPI (async API)</p><p>— Python 3.14: экспериментальный JIT-компилятор и шаблонные T-строки</p><p>— Медианная зарплата middle Python-разработчика: 250 000—350 000 руб./мес.</p><p>— Функции: замыкания, LEGB, *args/**kwargs, лямбды</p><p>— ООП: классы, наследование, @property, магические методы</p><p>— GIL, threading, asyncio и multiprocessing — когда что использовать</p><p>— Тестирование с pytest, работа с файлами через pathlib</p><h2>Основы языка: с чего начинается Python</h2><p>Python — язык с динамической типизацией и строгим контролем отступов. Если в C++ или Java фигурные скобки определяют блоки кода, то в Python эту роль играют пробелы. Поначалу это непривычно, но на практике делает код единообразным и читаемым — у вас просто нет возможности написать нечитаемую «лапшу». Философия Python описана в «Дзен Python» (<a href="https://peps.python.org/pep-0020/">PEP 20</a>): «Красивое лучше уродливого», «Явное лучше неявного», «Простое лучше сложного». Эти принципы пронизывают весь язык и его стандартную библиотеку.</p><p>Базовые типы данных в Python — это числа (int, float, complex), строки (str), булевы значения (bool), а также коллекции: списки (list), кортежи (tuple), множества (set) и словари (dict). Каждый тип имеет свои особенности. Например, целые числа в Python не ограничены размером: можно спокойно работать с числами в тысячи разрядов без переполнения — попробуйте сделать это в C или Java. Строки неизменяемы, а словари с Python 3.7 гарантированно сохраняют порядок вставки. Множества предоставляют проверку принадлежности элемента за O(1), а операции объединения, пересечения и разности выполняются за линейное время, что делает их незаменимыми для задач на поиск уникальных элементов.</p><p>Одна из ключевых концепций — duck typing: «если объект ходит как утка и крякает как утка, то это утка». Python не проверяет тип объекта заранее — он проверяет, поддерживает ли объект нужную операцию. Это даёт гибкость, но требует дисциплины. Современный Python активно использует аннотации типов (type hints), которые помогают IDE и линтерам находить ошибки ещё до запуска кода. Начиная с Python 3.10 появился оператор match/case (паттерн-матчинг), а в 3.12 — улучшенные дженерики и type aliases, которые делают типизацию ещё удобнее.</p><p>Переменные в Python — это не ячейки памяти, а метки (имена), привязанные к объектам. Понимание этого механизма — ключ к предсказуемой работе с мутабельными типами вроде списков и словарей. Когда вы пишете a = b для списка, вы не копируете данные — обе переменные указывают на один и тот же объект в памяти. Отсюда классические ловушки с изменяемыми аргументами по умолчанию и «неожиданным» изменением данных. Для создания независимой копии нужно использовать срез [:], метод copy() или модуль copy для глубокого копирования.</p><p>Управляющие конструкции в Python минималистичны и выразительны. Условия записываются через if/elif/else, циклы — через for и while. Конструкция for в Python ближе к foreach из других языков: она итерирует по элементам коллекции, а не по индексам. Функция range() генерирует последовательности чисел для случаев, когда нужен числовой цикл. Важно освоить и обработку исключений (try/except/finally) — Python использует исключения не только для ошибок, но и как механизм управления потоком, например StopIteration для завершения итерации.</p><p>Подробнее о типах данных и их поведении — в <a href="https://tproger.ru/translations/python-data-types">нашем гайде по основным типам данных</a>. А если хотите системно пройти все базовые концепции от установки до первого проекта — загляните в <a href="https://tproger.ru/articles/podrobnoe-opisanie-jazyka-python-dlja-nachinajushhih">подробное описание языка для начинающих</a>.</p><h2>Функции в Python</h2><p>Функции — основной инструмент структурирования кода в Python. Ключевое слово def создаёт функцию, return возвращает результат. Python поддерживает позиционные и именованные аргументы, значения по умолчанию, а также распаковку через *args (кортеж позиционных) и **kwargs (словарь именованных). Это позволяет создавать гибкие интерфейсы: от простых утилит до сложных API-обёрток.</p><p>Анонимные функции lambda удобны для коротких выражений — например, в качестве ключа сортировки: sorted(users, key=lambda u: u.age). Однако злоупотреблять ими не стоит: если лямбда не помещается в одну строку, лучше написать обычную функцию с понятным именем.</p><p>Python использует правило LEGB для поиска переменных: Local → Enclosing → Global → Built-in. Это объясняет, почему переменная внутри функции «затеняет» глобальную, и почему для изменения глобальной переменной нужно объявление global. Замыкания (closures) — функции, захватывающие переменные из объемлющей области видимости — лежат в основе декораторов, фабричных функций и callback-паттернов.</p><p>Функции в Python — объекты первого класса: их можно передавать как аргументы, возвращать из других функций и сохранять в структурах данных. Это фундамент для функционального стиля программирования, который активно используется вместе с map(), filter() и functools.</p><h2>ООП в Python</h2><p>Python — мультипарадигменный язык, но ООП в нём реализовано глубоко и последовательно. Классы создаются ключевым словом class, конструктор определяется методом __init__, а первый параметр каждого метода — self, ссылка на текущий экземпляр. В отличие от Java или C#, где this подразумевается неявно, Python требует явного указания — это осознанный выбор в пользу читаемости.</p><p>Python поддерживает множественное наследование через механизм MRO (Method Resolution Order) — алгоритм C3-линеаризации определяет порядок обхода родительских классов. Полиморфизм реализуется через duck typing: нет необходимости в интерфейсах — достаточно, чтобы объект имел нужные методы. Для формальных контрактов есть модуль abc с абстрактными базовыми классами и декоратором @abstractmethod.</p><p>Инкапсуляция в Python — скорее соглашение, чем принуждение. Префикс _ обозначает «приватный» атрибут, __ — активирует механизм name mangling, но ни то ни другое не запрещает доступ. Для контролируемого доступа к атрибутам используют декоратор @property, который превращает метод в вычисляемое свойство с геттером, сеттером и делетером.</p><p>Магические методы (dunder-методы) — мощный механизм, позволяющий объектам вести себя как встроенные типы. __str__ и __repr__ управляют строковым представлением, __eq__ и __hash__ — сравнением, __len__ и __getitem__ — доступом к элементам. Подробный разбор синтаксиса и концепций Python — в <a href="https://tproger.ru/articles/podrobnoe-opisanie-jazyka-python-dlja-nachinajushhih">нашем подробном описании языка для начинающих</a>.</p><h2>Модули и пакеты Python</h2><p>Модульная система Python проста: любой .py-файл — это модуль, а директория с __init__.py — пакет. Импорт осуществляется через import и from ... import. Python ищет модули по путям из sys.path, куда автоматически входят текущая директория, стандартная библиотека и директория site-packages с установленными пакетами.</p><p>Для управления зависимостями экосистема предлагает несколько инструментов. Классический pip + venv решает базовые задачи: создание изолированного окружения и установка пакетов из PyPI. Poetry добавляет управление зависимостями через pyproject.toml, lock-файлы и публикацию пакетов. Новый uv — написанный на Rust менеджер пакетов — работает в 10—100 раз быстрее pip и активно набирает популярность.</p><p>Стандартная библиотека Python (batteries included) — одна из самых богатых: от работы с сетью (http, socket) до сериализации (json, pickle), регулярных выражений (re) и параллелизма (threading, multiprocessing). Полный список из более чем 200 модулей доступен в <a href="https://tproger.ru/translations/10-python-libraries-you-might-not-know">нашей подборке полезных Python-библиотек</a>.</p><h2>Практика: задачи для начинающих</h2><p>Главная ошибка при изучении программирования — читать теорию неделями, не написав ни строчки кода. Python хорош тем, что позволяет начать практиковаться с первого дня: интерактивный интерпретатор (REPL), быстрая обратная связь и понятные сообщения об ошибках снижают барьер входа до минимума. Откройте терминал, напишите python3 — и вы уже можете экспериментировать.</p><p>Начинайте с простых задач: обработка строк, работа со списками, базовые циклы и условия. Затем переходите к задачам на функции, рекурсию и работу с файлами. Важно не просто решать задачу, а разбирать чужие решения — так вы быстрее освоите идиоматический Python. Один грамотно решённый пример научит вас большему, чем десять страниц документации. Обращайте внимание на то, как опытные разработчики используют встроенные функции (enumerate, zip, map), срезы списков и словарные включения — это и есть «питонический» стиль.</p><p>Хорошая практика — вести собственный файл с решениями и заметками. Возвращаясь к задачам через неделю, вы увидите, как вырос ваш уровень. Платформы вроде LeetCode, Codewars и HackerRank предлагают задачи с автоматической проверкой, но начинать лучше с задач, адаптированных под русскоязычную аудиторию. Ещё один совет: не гонитесь за количеством. Пять задач, решённых вдумчиво с разбором альтернативных подходов, ценнее пятидесяти, решённых механически копированием паттернов.</p><p>Мы собрали <a href="https://tproger.ru/problems/python-3-exercises-for-beginners-geekbrains">подборку задач для начинающих</a> — от элементарных до задач средней сложности. Каждая задача тренирует конкретный навык: работу с коллекциями, строковыми операциями, логикой ветвления. Рекомендуем решать их последовательно — сложность нарастает постепенно, и к концу подборки вы будете уверенно владеть основами языка.</p><h2>Продвинутые концепции Python</h2><p>Когда основы освоены, приходит время познакомиться с инструментами, которые отличают код новичка от кода опытного разработчика. В Python таких инструментов много, но есть пять ключевых концепций, без которых сложно писать по-настоящему качественный код: декораторы, генераторы, comprehensions, контекст-менеджеры и механизм *args/**kwargs. Именно владение этими инструментами отличает junior-разработчика от middle — и именно их чаще всего спрашивают на собеседованиях.</p><h3>Декораторы</h3><p>Декоратор — это функция, которая принимает другую функцию и возвращает её модифицированную версию. Звучит абстрактно, но на практике декораторы встречаются повсеместно: @property, @staticmethod, @login_required в Django, @app.route() во Flask. Они позволяют добавлять поведение без изменения исходного кода функции — логирование, кэширование, проверку прав доступа, валидацию аргументов, замер времени выполнения.</p><p>Под капотом декоратор — это обычный паттерн: функция, принимающая функцию и возвращающая функцию. Но синтаксический сахар с символом @ делает код лаконичным и выразительным. Декораторы можно параметризовать, складывать стопкой (применять несколько к одной функции) и даже применять к целым классам. Стандартная библиотека Python включает полезные декораторы: @functools.lru_cache для кэширования результатов, @functools.wraps для сохранения метаданных обёрнутой функции.</p><p>Декораторы — одна из тех тем, которые кажутся сложными ровно до момента, пока не разберёшься. Подробный разбор с примерами — в статье <a href="https://tproger.ru/translations/demystifying-decorators-in-python">«Декораторы в Python: понять и полюбить»</a>.</p><h3>Генераторы и comprehensions</h3><p>Генераторы — это функции с ключевым словом yield, которые возвращают данные лениво, по одному элементу за раз. Вместо того чтобы создавать в памяти список из миллиона элементов, генератор выдаёт их по запросу. Это критически важно при обработке больших файлов, потоков данных и результатов SQL-запросов. Генератор занимает фиксированный объём памяти независимо от количества элементов — хоть миллион, хоть миллиард.</p><p>Comprehensions (списковые, словарные и множественные включения) — это питонический способ создания коллекций в одну строку. Вместо цикла из трёх строк вы пишете выразительную конструкцию: [x ** 2 for x in range(10) if x % 2 == 0]. Они быстрее эквивалентных циклов (Python оптимизирует их на уровне байткода) и читаются проще — если не злоупотреблять вложенностью. Словарные включения {k: v for k, v in pairs} и множественные {x for x in items} работают по тому же принципу.</p><h3>Контекст-менеджеры и *args/**kwargs</h3><p>Конструкция with в Python — это контекст-менеджер, который гарантирует корректное освобождение ресурсов: закрытие файлов, соединений с базой, снятие блокировок. Вместо try/finally вы пишете with open('file.txt') as f: — и ресурс освобождается автоматически, даже если произошла ошибка. Можно создавать собственные контекст-менеджеры через методы __enter__/__exit__ или декоратор @contextmanager из модуля contextlib — это проще, чем кажется.</p><p>*args и **kwargs позволяют создавать функции с переменным числом аргументов. Это основа для написания гибких API, декораторов и обёрток. Понимание того, как Python распаковывает аргументы, открывает путь к элегантным решениям: передача параметров из словаря в функцию одной строкой, объединение конфигураций, создание универсальных обёрток. В комбинации с аннотациями типов (ParamSpec, Concatenate) этот механизм стал ещё мощнее в последних версиях Python.</p><p>Отдельного внимания заслуживает работа с памятью. Python скрывает от разработчика ручное управление памятью, но понимание того, сколько весят разные типы данных и как работает сборщик мусора, помогает писать эффективный код. Например, пустой список в Python занимает 56 байт, а каждый элемент добавляет 8 байт на указатель плюс размер самого объекта. Для числовых задач это означает, что NumPy-массив может быть в 10 раз компактнее обычного списка. Детальный разбор — в статье о <a href="https://tproger.ru/articles/raspredelenie-pamjati-v-python-skolko-i-v-kakih-sluchajah-zanimajut-tipy-dannyh">распределении памяти в Python</a>.</p><h3>Dataclasses и NamedTuple</h3><p>Модуль dataclasses (Python 3.7+) решает классическую проблему: написание классов, которые в основном хранят данные. Декоратор @dataclass автоматически генерирует __init__, __repr__, __eq__ и другие методы. С параметром frozen=True класс становится неизменяемым — удобно для конфигураций и DTO.</p><p>NamedTuple — ещё более лёгкая альтернатива: именованный кортеж занимает меньше памяти, чем dataclass, и автоматически поддерживает распаковку и итерацию. Выбор между ними прост: нужна изменяемость или наследование — dataclass, нужна компактность и совместимость с кортежами — NamedTuple.</p><h2>Многопоточность, асинхронность и GIL</h2><p>GIL (Global Interpreter Lock) — глобальная блокировка интерпретатора CPython, которая гарантирует, что в каждый момент времени только один поток выполняет байткод Python. Это упрощает реализацию интерпретатора и работу с памятью, но ограничивает параллелизм CPU-задач. Важно: GIL не мешает I/O-параллелизму — потоки освобождают блокировку при ожидании сети, диска или sleep.</p><p>Модуль threading подходит для I/O-bound задач: параллельные HTTP-запросы, чтение файлов, работа с базами данных. Для CPU-bound вычислений (обработка изображений, математические расчёты) используйте multiprocessing — он создаёт отдельные процессы, каждый со своим GIL. Пул concurrent.futures.ProcessPoolExecutor упрощает распределение задач по ядрам.</p><p>Модуль asyncio — стандарт для асинхронного программирования в Python. Конструкции async def и await позволяют писать неблокирующий код, который выглядит почти как синхронный. Один поток обрабатывает тысячи соединений — именно поэтому FastAPI и другие ASGI-фреймворки работают быстрее классических WSGI-аналогов.</p><p>Когда что использовать? threading — для I/O-операций с умеренной нагрузкой. asyncio — для высоконагруженных I/O-сценариев (веб-серверы, парсеры). multiprocessing — для CPU-bound задач. На практике они часто комбинируются: например, asyncio для сетевого ввода-вывода и ProcessPool для тяжёлых вычислений внутри одного приложения.</p><p>Важная новость: <a href="https://peps.python.org/pep-0703/">PEP 703</a> предлагает сделать GIL опциональным (free-threaded Python). Экспериментальная сборка без GIL уже доступна в Python 3.13+ через специальную сборку python3.14t (free-threaded build). В Python 3.14 этот режим стал официально поддерживаемым (<a href="https://peps.python.org/pep-0779/">PEP 779</a>). Если эксперимент окажется успешным, в будущих версиях Python сможет полноценно использовать все ядра процессора без обходных путей через multiprocessing.</p><h2>Тестирование в Python</h2><p>Тестирование — не роскошь, а базовая гигиена разработки. В Python стандартом де-факто является pytest — фреймворк, который сочетает простоту написания тестов с мощной системой расширений. Обычные функции с assert — это уже тесты. Не нужны классы, наследование от TestCase и специальные методы.</p><p>Фикстуры (@pytest.fixture) управляют подготовкой и очисткой тестового окружения: подключение к базе данных, создание тестового клиента, временные файлы. Параметризация (@pytest.mark.parametrize) позволяет прогнать один тест с десятками наборов входных данных без дублирования кода.</p><p>Для изоляции внешних зависимостей используйте unittest.mock — встроенный модуль, который позволяет подменять HTTP-запросы, обращения к базе данных и вызовы внешних сервисов. В связке с pytest это покрывает 95% потребностей в тестировании. TDD (Test-Driven Development) — подход, при котором тест пишется раньше кода. Его необязательно практиковать всегда, но для сложной бизнес-логики он существенно снижает количество регрессий.</p><h2>Работа с файлами и данными</h2><p>Python предоставляет удобные инструменты для работы с файлами любых форматов. Конструкция with open(...) гарантирует корректное закрытие файла даже при ошибке. Модуль pathlib (Python 3.4+) — современная замена os.path: объектно-ориентированные пути, кроссплатформенная совместимость и цепочки вызовов.</p><p>Для структурированных данных стандартная библиотека предлагает модули json, csv и configparser. Для YAML понадобится сторонний пакет PyYAML. Работа с Excel-файлами — через openpyxl или pandas. Для больших объёмов данных используйте потоковое чтение: csv.reader или json.JSONDecoder().raw_decode() вместо загрузки всего файла в память.</p><p>Для работы с распределением памяти и внутренним устройством типов данных Python — рекомендуем нашу <a href="https://tproger.ru/articles/raspredelenie-pamjati-v-python-skolko-i-v-kakih-sluchajah-zanimajut-tipy-dannyh">статью о распределении памяти в Python</a>: сколько и в каких случаях занимают типы данных.</p><h2>Веб-разработка на Python</h2><p>Python — один из ключевых языков для серверной веб-разработки. Три фреймворка покрывают практически все сценарии: Django — для полнофункциональных приложений, Flask — для микросервисов и лёгких проектов, FastAPI — для высокопроизводительных API. Каждый из них занимает свою нишу, и выбор зависит от масштаба проекта, требований к производительности и опыта команды. Разберём сильные и слабые стороны каждого, чтобы вы могли сделать осознанный выбор.</p><h3>Django: всё включено</h3><p>Django — это «батарейки в комплекте». ORM, админ-панель, система аутентификации, шаблонизатор, миграции базы данных, защита от CSRF и XSS, формы с валидацией, кэширование, интернационализация — всё работает из коробки и не требует сторонних зависимостей. Это делает Django идеальным выбором для крупных проектов: интернет-магазинов, SaaS-платформ, CRM-систем, внутренних корпоративных порталов. Instagram, Mozilla, Disqus, Pinterest — все они используют Django в продакшене.</p><p>Главное преимущество Django — зрелость. Фреймворку больше 20 лет, он имеет огромное сообщество, тысячи готовых пакетов (django-rest-framework, django-allauth, celery) и предсказуемый цикл релизов. Django ORM позволяет работать с базой данных через Python-объекты, не написав ни строчки SQL, а система миграций автоматически отслеживает изменения в моделях. Обратная сторона — Django навязывает свою архитектуру. Если вам нужен только REST API без шаблонов и админки, значительная часть фреймворка будет «мёртвым грузом».</p><h3>Flask: минималистичный и гибкий</h3><p>Flask — противоположность Django. Микрофреймворк даёт маршрутизацию, обработку запросов и систему расширений — остальное вы выбираете сами. Нужна ORM? Подключите SQLAlchemy. Нужна авторизация? Flask-Login. Хотите WebSocket? Flask-SocketIO. Такой подход идеален для микросервисов, прототипов и проектов, где полный контроль над стеком важнее скорости старта. Flask часто выбирают для внутренних сервисов, API-шлюзов и проектов, которые начинаются маленькими, но могут вырасти.</p><p>Flask отлично сочетается с фронтенд-фреймворками. Например, в статье <a href="https://tproger.ru/translations/developing-app-with-flask-and-vue-js">«Пишем одностраничное приложение с Flask и Vue.js»</a> мы показываем, как построить SPA с Flask-бэкендом — от настройки проекта до деплоя. Это типичный современный стек: Python на сервере, JavaScript-фреймворк на клиенте.</p><h3>FastAPI: скорость и типизация</h3><p>FastAPI — самый молодой из тройки, но уже ставший стандартом для создания API. Он построен на Starlette (ASGI) и Pydantic, поддерживает async/await из коробки и автоматически генерирует документацию OpenAPI (Swagger UI и ReDoc) прямо из аннотаций типов в коде. FastAPI — один из самых быстрых Python-фреймворков благодаря Starlette и uvicorn. Валидация данных через Pydantic-модели ловит ошибки ещё до обработки запроса, а type hints превращаются в живую документацию API. Dependency injection встроен в ядро фреймворка, что упрощает тестирование и переиспользование кода.</p><p>Но скорость — не всё. FastAPI требует понимания асинхронного программирования, а экосистема пока уступает Django и Flask по количеству готовых решений. Для простого CRUD-приложения с админкой Django справится быстрее; для прототипа с нестандартной архитектурой Flask даст больше свободы. О подводных камнях и ситуациях, когда FastAPI — не лучший выбор, мы подробно рассказываем в статье <a href="https://tproger.ru/articles/pochemu-ne-stoit-vybirat-fastapi-samyj-bystryj-frejmvork-na-python">«Почему не стоит выбирать FastAPI»</a> — честный разбор, который поможет принять взвешенное решение.</p><h3>Какой фреймворк выбрать</h3><ul><li>Полноценное веб-приложение с админкой и авторизацией — Django</li><li>Микросервис или прототип с полным контролем над стеком — Flask</li><li>Высокопроизводительный REST/GraphQL API с автодокументацией — FastAPI</li><li>Не уверены — начните с Django: у него самый пологий путь от нуля до продакшена</li></ul><p>На практике многие команды используют несколько фреймворков одновременно: Django для основного приложения, FastAPI для высоконагруженных микросервисов, Flask для внутренних инструментов. Python позволяет комбинировать. Общий навык для всех трёх фреймворков — понимание HTTP-протокола, REST-архитектуры, работы с базами данных и основ безопасности (CORS, CSRF, XSS, SQL-инъекции). Освоив эти концепции на одном фреймворке, вы легко перейдёте на другой.</p><h2>Python для Data Science</h2><p>Если веб-разработка — давняя территория Python, то Data Science — его новая сверхдержава. По данным <a href="https://www.jetbrains.com/lp/devecosystem-2024/python/">JetBrains Developer Ecosystem Survey</a>, Python — самый изучаемый язык программирования и основной инструмент дата-аналитиков и дата-инженеров. R, Julia, Scala — у каждого есть свои преимущества, но ни один не предлагает такую же широту экосистемы. Причина — уникальный набор библиотек, который покрывает весь pipeline работы с данными: от загрузки и очистки до визуализации и развёртывания моделей в продакшен.</p><p>NumPy — фундамент всего стека. Библиотека предоставляет многомерные массивы и математические операции, работающие на порядки быстрее чистого Python — за счёт реализации на C. Умножение матрицы 1000x1000 в NumPy выполняется за миллисекунды, в то время как наивная реализация на чистом Python займёт минуты. Pandas строится поверх NumPy и предлагает удобные таблицы (DataFrame), позволяя загружать, фильтровать, группировать и агрегировать данные в несколько строк кода. Данные из CSV, Excel, SQL, JSON — Pandas читает практически всё.</p><p>Для машинного обучения стандартом остаётся scikit-learn — библиотека с десятками алгоритмов классификации, регрессии и кластеризации. Её главная сила — единый интерфейс: fit(), predict(), score() работают одинаково для любого алгоритма, будь то случайный лес, SVM или градиентный бустинг. Это позволяет быстро сравнивать модели, менять алгоритмы одной строкой и строить пайплайны предобработки данных.</p><p>Для глубокого обучения Python предлагает PyTorch и TensorFlow — два гиганта, на которых построены GPT, Stable Diffusion и другие модели, изменившие индустрию. PyTorch доминирует в исследованиях благодаря динамическим вычислительным графам, а TensorFlow остаётся популярным в продакшене благодаря TensorFlow Serving и TFLite. Визуализация данных — matplotlib для статичных графиков, seaborn для статистических визуализаций и plotly для интерактивных дашбордов. Jupyter Notebook объединяет всё это в единую среду, где код, графики и текст живут рядом.</p><p>Разобраться в ключевых библиотеках поможет наш <a href="https://tproger.ru/translations/top-10-python-bibliotek-dlja-data-science">топ-10 Python-библиотек для Data Science</a>. А если хотите расширить инструментарий за пределы стандартного набора — загляните в подборку <a href="https://tproger.ru/translations/10-python-libraries-you-might-not-know">10 полезных библиотек, о которых вы могли не слышать</a>: там есть настоящие жемчужины для отладки, профилирования и работы с данными.</p><p>Для управления окружениями в Data Science часто используют conda (Anaconda/Miniconda) — он умеет устанавливать не только Python-пакеты, но и системные зависимости вроде CUDA для GPU-вычислений.</p><h2>Практические инструменты Python</h2><p>Помимо веб-разработки и Data Science, Python — незаменимый инструмент для повседневных задач: интеграция с внешними сервисами, извлечение данных из веб-страниц и обработка текста.</p><h3>Работа с API</h3><p>Библиотека requests — стандарт для синхронных HTTP-запросов: лаконичный API, автоматическая сериализация JSON и управление сессиями. Для асинхронных задач и HTTP/2 используйте httpx — он совместим с requests по интерфейсу, но поддерживает async/await.</p><h3>Веб-скрапинг</h3><p>Для извлечения данных из HTML-страниц Python предлагает несколько уровней инструментов. BeautifulSoup — простой парсер для статических страниц: выборка по CSS-селекторам и тегам. Scrapy — полноценный фреймворк для масштабного скрапинга с очередями, ротацией прокси и экспортом данных. Selenium и Playwright — для страниц, где контент рендерится JavaScript'ом.</p><h3>Регулярные выражения</h3><p>Модуль re — мощный инструмент для поиска и трансформации текста по шаблонам. Основные функции: re.findall() для извлечения всех совпадений, re.sub() для замены и re.compile() для предкомпиляции часто используемых паттернов.</p><p>Совет: для сложных паттернов используйте сырые строки (r"...") — они избавляют от двойного экранирования обратных слэшей. А для задач, выходящих за рамки регулярных выражений (парсинг HTML, XML), всегда предпочитайте специализированные парсеры.</p><h2>Что нового в Python 3.14</h2><p>Python 3.14 (<a href="https://docs.python.org/3/whatsnew/3.14.html">что нового</a>) (да, «пи»-релиз — разработчики не упустили возможность пошутить), выпущенный в октябре 2025 года, стал одним из самых значительных релизов за последние годы. Главные нововведения направлены на производительность — область, где Python традиционно уступал компилируемым языкам. Но 3.14 меняет правила игры.</p><p>Экспериментальный JIT-компилятор (<a href="https://peps.python.org/pep-0744/">PEP 744</a>) — пожалуй, главная новость. Он компилирует часто выполняемые участки кода (так называемые «горячие пути») в машинные инструкции прямо во время работы программы. На реальных приложениях это даёт эффект варьируется: от замедления на 10% до ускорения на 20% в зависимости от нагрузки — на некоторых задачах JIT пока замедляет код без каких-либо изменений в коде. JIT пока отключён по умолчанию (в официальных сборках для macOS и Windows JIT уже включён в бинарники — активируется переменной окружения PYTHON_JIT=1), но уже работает стабильно на большинстве платформ. Это первый шаг к тому, чтобы Python перестал считаться «медленным языком».</p><p>Внутренняя архитектура интерпретатора переработана: новый tail-call диспетчер опкодов (на уровне C, не Python-функций) даёт прирост 3—5% на стандартном benchmark suite. Важно: это не оптимизация хвостовой рекурсии в Python-коде — RecursionError при превышении глубины стека по-прежнему возможен.</p><p>T-строки (<a href="https://peps.python.org/pep-0750/">PEP 750</a>) — новый синтаксис шаблонных строк с префиксом t"...". В отличие от f-строк, T-строки не выполняют подстановку сразу, а возвращают объект Template, который можно обработать — экранировать специальные символы, валидировать параметры, преобразовать значения. Это отличное решение для безопасной генерации HTML и SQL без риска инъекций.</p><p>Среди других улучшений — ускоренные операции со словарями (до 40% быстрее в некоторых сценариях), оптимизированная работа сборщика мусора и улучшенные сообщения об ошибках, которые теперь подсказывают возможные причины проблемы. Обновлён синтаксис обработки исключений (<a href="https://peps.python.org/pep-0758/">PEP 758</a>): теперь можно писать except ValueError, TypeError: без скобок (без as — с as по-прежнему нужны скобки: except (ValueError, TypeError) as e:). Также завершён переход на отложенное вычисление аннотаций типов (<a href="https://peps.python.org/pep-0649/">PEP 649</a>/749) — аннотации больше не вычисляются при импорте модуля, что ускоряет запуск. Python продолжает развиваться, сохраняя обратную совместимость и фокус на удобстве разработчика.</p><h2>Куда двигаться дальше</h2><p>Python открывает множество карьерных путей, и выбор зависит от ваших интересов и склонностей. Вот основные направления, в каждом из которых Python — ключевой или один из основных инструментов:</p><ol><li><b>Backend-разработчик</b> — Django, Flask или FastAPI, базы данных (PostgreSQL, Redis), REST API, очереди задач (Celery), контейнеризация (Docker, Kubernetes)</li><li><b>Data Scientist / ML-инженер</b> — pandas, scikit-learn, PyTorch, работа с данными, статистика, построение и деплой моделей</li><li><b>DevOps / SRE</b> — автоматизация инфраструктуры (Ansible, Terraform), скрипты мониторинга, CI/CD пайплайны, облачные провайдеры (AWS, GCP)</li><li><b>ИИ-инженер</b> — LLM, промпт-инжиниринг, RAG-системы, fine-tuning, LangChain, работа с API нейросетей (OpenAI, Anthropic, Mistral)</li><li><b>Автоматизатор / QA-инженер</b> — Selenium, Playwright, pytest, автоматизация тестирования, нагрузочное тестирование (Locust)</li></ol><p>Независимо от выбранного направления, есть навыки, которые пригодятся везде: Git для контроля версий, SQL для работы с базами данных, Docker для контейнеризации, Linux для понимания серверной среды. Python-разработчик в 2026 году — это не просто человек, который знает синтаксис языка, а специалист, владеющий инструментарием вокруг него. Также стоит освоить виртуальные окружения (venv, poetry, uv), линтеры (ruff, mypy) и основы CI/CD — это ожидается от любого профессионального разработчика. Для управления версиями Python-проектов пригодится наш <a href="https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor">путеводитель по Git</a>.</p><p>Рынок труда подтверждает спрос: по данным <a href="https://hh.ru/">hh.ru</a>, количество вакансий с Python стабильно растёт на 15—20% в год, а медианная зарплата Python-разработчика уровня middle составляет 250 000—350 000 рублей в месяц. Специалисты на стыке Python и Data Science / ML зарабатывают ещё больше. Язык востребован не только в IT-компаниях: банки, телеком, ритейл, промышленность — Python нужен везде, где есть данные и автоматизация.</p><p>Отдельно стоит упомянуть растущий спрос на ИИ-инженеров. С развитием больших языковых моделей Python стал основным языком для интеграции ИИ в продукты: построение RAG-систем, создание агентов, fine-tuning моделей — всё это делается на Python. Библиотеки LangChain, LlamaIndex, Hugging Face Transformers формируют новую экосистему, которая растёт быстрее любого другого направления в IT.</p><p>Если вы в начале пути — начните со структурированной <a href="https://tproger.ru/articles/python-roadmap-2023-ljn8jvxfj">дорожной карты изучения Python</a>. Она поможет не потеряться в обилии материалов и выстроить последовательный план обучения от основ до профессионального уровня. А затем возвращайтесь к этому путеводителю — здесь вы всегда найдёте ссылки на углублённые материалы по каждой теме. Мы регулярно обновляем наши гайды, чтобы они оставались актуальными — так что добавляйте страницу в закладки.</p>]]></content:encoded>
    </item>
    <item>
      <title>Cloudflare запустила EmDash — open-source CMS на TypeScript, которая решает главную проблему WordPress</title>
      <link>https://tproger.ru/news/cloudflare-zapustila-emdash---open-source-cms-na-typescript--kot</link>
      <comments>https://tproger.ru/news/cloudflare-zapustila-emdash---open-source-cms-na-typescript--kot?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/cloudflare-zapustila-emdash---open-source-cms-na-typescript--kot</guid>
      <description><![CDATA[<p>Cloudflare выпустила EmDash — open-source CMS на TypeScript с песочницей для плагинов, MCP-сервером для ИИ-агентов и миграцией с WordPress. Разбираем архитектуру.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/cloudflare-zapustila-emdash---open-source-cms-na-typescript--kot">Cloudflare запустила EmDash — open-source CMS на TypeScript, которая решает главную проблему WordPress</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[WordPress]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[CMS]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 10:18:14 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы хоть раз обновляли WordPress-плагин и молились, чтобы сайт не упал — Cloudflare сделала кое-что для вас.</p><p><a href="https://blog.cloudflare.com/emdash-wordpress/">EmDash</a> — это новая open-source CMS (система управления контентом) на TypeScript от Cloudflare, которую компания <a href="https://blog.cloudflare.com/emdash-wordpress/">называет</a> «духовным наследником WordPress». Главная идея: плагины работают в изолированных песочницах и не могут навредить сайту, даже если содержат уязвимости.</p><ul><li>Cloudflare выпустила EmDash v0.1.0 — open-source CMS на TypeScript с MIT-лицензией</li><li>Каждый плагин запускается в изолированной песочнице (Dynamic Workers) и декларирует нужные разрешения в манифесте</li><li>96% уязвимостей WordPress-сайтов приходится на плагины — EmDash решает эту проблему архитектурно</li><li>Под капотом — Astro, serverless-архитектура, Portable Text вместо HTML, встроенный MCP-сервер для ИИ-агентов</li><li>Проект создан за 2 месяца с помощью ИИ-агентов, доступен на GitHub (3200+ звёзд за сутки)</li></ul><p>WordPress исполнится 23 года в этом году (основан в 2003 году). Платформа <a href="https://w3techs.com/technologies/details/cm-wordpress">обслуживает</a> более 40% всех сайтов в интернете, но её архитектура родом из эпохи, когда AWS EC2 ещё не существовал. Плагинная система WordPress — главное преимущество и главная боль одновременно.</p><h2>Почему безопасность плагинов WordPress — нерешаемая проблема</h2><p>В WordPress плагин — это PHP-скрипт, который встраивается напрямую в ядро и получает полный доступ к базе данных и файловой системе. Нет изоляции, нет ограничений. Установить плагин — значит полностью ему довериться.</p><p>Статистика <a href="https://www.wordfence.com/">Wordfence</a> и других ИБ-компаний неутешительна:</p><ul><li><b>96% уязвимостей</b> WordPress-сайтов происходят из плагинов</li><li>В 2025 году нашли больше критических уязвимостей в экосистеме WordPress, чем за два предыдущих года вместе</li><li>Очередь ревью в маркетплейсе WordPress.org — <b>800+ плагинов</b>, ожидание — минимум 2 недели</li></ul><p>WordPress не может решить эту проблему, не переписав архитектуру с нуля. Cloudflare решила это сделать.</p><h2>Как EmDash изолирует плагины</h2><p>В EmDash каждый плагин запускается в собственном изолированном воркере (<a href="https://developers.cloudflare.com/workers/">Dynamic Worker</a> — легковесная v8-песочница, запускающаяся за миллисекунды). Вместо полного доступа ко всему, плагин <b>декларирует</b> в манифесте, какие возможности ему нужны:</p><p>Этот плагин запрашивает ровно два разрешения: чтение контента и отправку email. <b>Ничего другого он сделать не может</b> — ни обратиться к внешнему серверу, ни прочитать файловую систему, ни получить доступ к базе данных напрямую.</p><p>Модель напоминает OAuth: при установке плагина вы видите, какие именно разрешения он запрашивает, и принимаете осознанное решение. Администратор может задать политики — какие capabilities допустимы для каких ролей.</p><h2>Архитектура и стек</h2><p>EmDash построен на современном стеке:</p><ul><li><b>TypeScript</b> — весь код, включая плагины и темы</li><li><b>Astro</b> — фреймворк для контентных сайтов, рендеринг тем</li><li><b>Portable Text</b> — структурированный JSON вместо HTML, контент не привязан к DOM</li><li><b>Serverless</b> — масштабируется до нуля, работает на Cloudflare Workers или любом Node.js-сервере</li><li><b>Passkeys</b> — аутентификация без паролей по умолчанию (WebAuthn)</li><li><b>MIT-лицензия</b> — без ограничений GPL, плагины могут иметь любую лицензию</li></ul><h3>Хранение и совместимость</h3><p>На Cloudflare EmDash использует D1 (база данных), R2 (файлы), Workers (вычисления). Но абстракции портируемы: можно запустить на SQLite, PostgreSQL, AWS S3 или локальном файловом хранилище. Команда для развёртывания:</p><h2>ИИ-нативная CMS: MCP, CLI, Agent Skills</h2><p>EmDash <a href="https://github.com/emdash-cms/emdash">спроектирован</a> для работы с ИИ-агентами:</p><ul><li><b>Встроенный MCP-сервер</b> — Claude, ChatGPT и другие ИИ-инструменты могут управлять сайтом напрямую через Model Context Protocol</li><li><b>Agent Skills</b> — файлы-инструкции для ИИ-агентов: как писать плагины, портировать темы с WordPress, работать со схемами контента</li><li><b>CLI</b> — программное управление контентом, медиа, схемами</li></ul><p>По сути, рутинную работу — миграцию контента, создание плагинов, адаптацию тем — можно поручить ИИ-агенту, и EmDash даст ему весь необходимый контекст.</p><h2>Встроенная монетизация через x402</h2><p>Каждый сайт на EmDash поддерживает стандарт <a href="https://x402.org">x402</a> — нативные интернет-платежи. Клиент (например, ИИ-агент) отправляет HTTP-запрос, получает ответ 402 Payment Required и оплачивает доступ к контенту на лету. Настроить монетизацию можно без единой строчки кода — указать, какой контент платный, и привязать кошелёк.</p><h2>Миграция с WordPress</h2><p>EmDash поддерживает импорт существующих WordPress-сайтов:</p><ol><li>Экспорт WXR-файла (WordPress eXtended RSS) из WordPress-админки</li><li>Или установка плагина EmDash Exporter, который создаёт защищённый endpoint для миграции</li><li>Автоматический перенос постов, страниц, медиафайлов и таксономий</li></ol><p>Кастомные типы контента (которые в WordPress требуют Advanced Custom Fields) в EmDash задаются через визуальный конструктор схем в админке.</p><h2>Что стоит учесть</h2><p>EmDash находится в статусе <b>бета-превью (v0.1.0)</b>. Несколько моментов:</p><ul><li>Проект молодой — 62 коммита, 4 контрибьютора, 34 релиза</li><li>Песочница для плагинов через Dynamic Workers требует платного аккаунта Cloudflare (от $5/мес), но EmDash запускается и без неё — плагины будут работать в safe mode без изоляции</li><li>Экосистема плагинов и тем ещё не сформировалась — на старте доступны формы, встраивания, SEO, аудит-лог</li><li>Привязка к инфраструктуре Cloudflare — можно запустить на Node.js, но максимальную производительность даёт именно Cloudflare</li></ul><h2>Выводы</h2><blockquote>WordPress — триумф open source, который дал возможность публиковаться миллионам. Но экосистеме нужен вариант, который даёт ту же свободу и доступность, решая при этом проблемы, которые WordPress не может решить.</blockquote><p>EmDash — амбициозная заявка Cloudflare на рынок CMS. За 24 часа после анонса проект набрал более 3200 звёзд на <a href="https://github.com/emdash-cms/emdash">GitHub</a> и 600+ баллов на Hacker News. Продакшн-готовности пока нет — это бета. Но идея изолированных плагинов с декларативными разрешениями решает реальную проблему, которая мучает WordPress-экосистему десятилетиями.</p><p>Попробовать EmDash можно в <a href="https://emdash.dev/playground">онлайн-песочнице</a> или развернуть локально через CLI.</p>]]></content:encoded>
    </item>
    <item>
      <title>Разработчик построил DOOM на чистом CSS — можно поиграть прямо в браузере</title>
      <link>https://tproger.ru/news/razrabotchik-postroil-doom-na-chistom-css---rendering-bez-edinoj-s</link>
      <comments>https://tproger.ru/news/razrabotchik-postroil-doom-na-chistom-css---rendering-bez-edinoj-s?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/razrabotchik-postroil-doom-na-chistom-css---rendering-bez-edinoj-s</guid>
      <description><![CDATA[<p>Разработчик построил DOOM целиком на CSS transforms: стены через hypot(), углы через atan2(), анимации на transitions. Логика на JS, графика — чистый CSS.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/razrabotchik-postroil-doom-na-chistom-css---rendering-bez-edinoj-s">Разработчик построил DOOM на чистом CSS — можно поиграть прямо в браузере</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 29 Mar 2026 05:33:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>Веб-разработчик Нильс Ленхер (Niels Leenheer) построил полноценный DOOM на чистом CSS. Каждая стена, пол, бочка и имп — это &lt;div&gt;, позиционированный в 3D-пространстве через CSS transforms. Игровая логика работает на JavaScript, но <b>весь рендеринг — исключительно CSS</b>.</p><p><b>Поиграть прямо в браузере:</b> <a href="https://cssdoom.wtf/">cssdoom.wtf</a> — полноценный первый уровень DOOM, целиком на CSS. Chrome или Safari, WASD + мышь.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-29/89e75765-8bbd-4917-a64f-221772d95ffb.webp" alt="CSS DOOM — DOOM работающий на чистом CSS в браузере" /><figcaption>DOOM на CSS — все стены, полы и спрайты отрисованы через CSS transforms</figcaption></figure><p>Ленхер — автор нескольких экспериментальных проектов, включая DOOM на осциллографе 1980-х годов. Новый проект использует координаты из оригинального WAD-файла (формат хранения данных карт DOOM) 1993 года и современные CSS-функции: @property, shape() и clip-path (свойство CSS для обрезки элемента по произвольному контуру) с правилом evenodd (правило заливки SVG-путей: закрашиваются области, ограниченные нечётным числом линий). <a href="https://nielsleenheer.com/articles/2026/css-is-doomed/">Исходная статья</a> набрала 306 очков и 67 комментариев на <a href="https://news.ycombinator.com/item?id=47557960">Hacker News</a>, а код <a href="https://github.com/NielsLeenheer/cssDOOM">опубликован на GitHub</a>.</p><p>— CSS умеет считать тригонометрию: ширина стены через hypot(), угол через atan2()</p><p>— Камеры в CSS нет — двигается весь мир вокруг игрока через translate3d с инвертированными координатами</p><p>— Двери, лифты и снаряды анимируются через CSS transitions и CSS animations без JS animation loop</p><p>— Освещение секторов работает через filter: brightness(), наследуемый по каскаду</p><p>— @property регистрирует custom properties как числа, что позволяет анимировать их плавно</p><h2>Как это работает — CSS как 3D-движок</h2><p>Сцена строится из нескольких тысяч &lt;div&gt;-элементов. Каждый получает сырые координаты из оригинального WAD-файла DOOM в виде CSS custom properties: две пары x/y-координат, высоту пола и потолка. CSS сам вычисляет всё остальное.</p><h3>Тригонометрия в CSS</h3><p>Ширина стены — это расстояние между двумя точками, которое вычисляется по теореме Пифагора через функцию hypot(). Угол поворота — это арктангенс, вычисляемый через atan2(). Обе функции добавлены в CSS специально для подобных расчётов.</p><p>JavaScript передаёт сырые данные DOOM. CSS считает тригонометрию. Это разделение — ключевой архитектурный принцип проекта.</p><h3>Движение мира вместо камеры</h3><p>В CSS нет понятия камеры. Вместо этого используется классический трюк: перемещается весь мир в направлении, противоположном движению игрока. JavaScript задаёт всего четыре custom property — --player-x, --player-y, --player-z и --player-angle. CSS делает остальное:</p><p>Обратите внимание на инвертированные знаки: если игрок шагает вперёд — мир сдвигается назад. Если игрок поднимается по лестнице — лестница опускается вниз.</p><h2>Полы, текстуры и клипы</h2><p>DOM-элементы по умолчанию вертикальны — существуют в плоскости x/y. Чтобы превратить &lt;div&gt; в пол, достаточно rotateX(90deg) — элемент «ложится» горизонтально.</p><h3>Сложные формы через clip-path</h3><p>Секторы DOOM — это произвольные многоугольники: L-образные комнаты, неправильные формы, закруглённые коридоры. Для них используется clip-path с polygon(). Для секторов с отверстиями (колонны, платформы, окна) — clip-path с path() и правилом заливки evenodd.</p><p>Однако polygon() работает с процентами, а path() требует координат в пространстве CSS — что нарушает чистоту разделения. Решение нашлось в новой функции shape(), которая поддерживает проценты и evenodd одновременно.</p><h3>Выравнивание текстур</h3><p>Два соседних сектора с одинаковой текстурой пола должны бесшовно стыковаться. Поскольку background-image повторяется бесконечно, достаточно выровнять начало паттерна по мировым координатам:</p><p>Каждый сектор ссылается на одну и ту же текстурную сетку — независимо от того, где расположен его &lt;div&gt;. В результате переход между секторами выглядит бесшовным.</p><h2>Анимации — двери, снаряды, спрайты</h2><p>Прежде чем перейти к деталям — важный термин: <b>billboarding</b>. Это техника, при которой 2D-спрайт всегда повёрнут лицом к камере, независимо от положения игрока. В DOOM все враги, бочки и снаряды — billboarded-элементы.</p><h3>Двери и лифты на CSS transitions</h3><p>Открытие двери в DOOM — это поднятие потолка сектора. В CSS все элементы двери группируются в контейнер, а анимация запускается переключением атрибута data-state:</p><p>Никакого JS animation loop — достаточно установить атрибут состояния на элементе. CSS transitions берут анимацию на себя.</p><p>С лифтами всё сложнее: игрок едет вместе с платформой, поэтому --player-z должен обновляться синхронно с CSS transition. Но --player-z управляется из JavaScript. Поэтому для лифтов JS вынужден использовать функцию cubic ease-in-out (t² * (3 - 2t)), чтобы оставаться в синхронизации с CSS-анимацией — это признанное ограничение текущей архитектуры.</p><h3>Снаряды на CSS animations</h3><p>Ракеты и файерболы импов — это billboarded &lt;div&gt;. При создании снаряда JavaScript вычисляет конечную точку и длительность полёта, а CSS анимирует перемещение от точки A к точке B:</p><p>Благодаря разделению translate и rotate как отдельных CSS-свойств анимация управляет только позицией, а rotate реагирует на --player-angle — файербол продолжает смотреть на камеру при движении игрока.</p><p>Параллельно с CSS-анимацией игровой цикл на JavaScript рассчитывает позицию снаряда тем же линейным методом — для обнаружения столкновений (collision detection). Когда снаряд попадает в стену, пол, игрока или врага, JS удаляет элемент посреди полёта и порождает взрыв.</p><h3>Спрайты с billboarding и mirroring</h3><p>Враги в DOOM — 2D-спрайты, которые всегда повёрнуты к камере (billboarding). Оригинальная игра хранит 5 уникальных наборов кадров из 8 ракурсов — ракурсы 6-8 это зеркальные отражения 2-4. CSS воспроизводит это через scaleX(-1):</p><p>Анимация ходьбы — это spritesheet (набор кадров анимации в одном изображении) со сдвигом background-position-x через steps(). При атаке или смерти JavaScript меняет data-state, и CSS переключается на другой фрагмент spritesheet.</p><p>Одна из проблем: изначально все враги маршировали идеально в ногу — левая нога каждого зомби касалась земли в один и тот же момент. Решение — случайный animation-delay, задаваемый из JavaScript. Когда в браузерах появится CSS-функция random(), этот параметр можно будет перенести целиком в CSS.</p><h2>Освещение и @property</h2><p>DOOM хранит уровень освещённости для каждого сектора. В CSS это реализовано через custom property --light на контейнере сектора:</p><p>Каскад CSS идеально подходит для этого: все стены, полы и спрайты в тёмном секторе автоматически затемняются — без необходимости устанавливать яркость на каждом элементе отдельно. Мерцающие лампы — это @keyframes-анимации переменной --light.</p><p>Но анимировать custom properties можно только если они зарегистрированы через @property. Без этого браузер воспринимает их как строки:</p><p>Эта регистрация позволяет плавно анимировать --player-z — например, при падении игрока с уступа CSS сам создаёт плавный переход.</p><h2>Что делает JavaScript, а что CSS</h2><p>Автор чётко разделил ответственности:</p><ul><li><b>JavaScript</b> — игровой цикл, состояние игры, коллизии, порождение и удаление DOM-элементов, установка custom properties и data-атрибутов</li><li><b>CSS</b> — все 3D-трансформации, вычисление геометрии (тригонометрия), анимации дверей и снарядов, освещение, CSS рендеринг спрайтов</li></ul><p>По словам Ленхера, game loop на JavaScript — наименее интересная часть проекта. Исходный код DOOM на C доступен публично уже много лет, поэтому для портирования он <a href="https://nielsleenheer.com/articles/2026/css-is-doomed/">использовал Claude</a>, чтобы сосредоточиться на CSS-рендеринге.</p><h2>Выводы</h2><blockquote>Я хотел найти границы того, на что способен браузер. Увидеть, насколько мощным стал современный CSS. И потому что это DOOM. На CSS. Вам правда нужна ещё какая-то причина?</blockquote><p>Проект демонстрирует, как далеко продвинулся CSS за 30 лет. Функции вроде hypot(), atan2() и @property превращают каскадные таблицы стилей в полноценный инструмент для 3D-вычислений. Разделение на JS game loop и CSS-рендеринг оказалось не только возможным, но и элегантным.</p><p>Исходный код: <a href="https://github.com/NielsLeenheer/cssDOOM">GitHub</a>. Подробный разбор: <a href="https://nielsleenheer.com/articles/2026/css-is-doomed/">CSS is DOOMed</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое REST API простыми словами: принципы, методы и примеры</title>
      <link>https://tproger.ru/articles/chto-takoe-rest-api-prostymi-slovami--principy--metody-i-primery</link>
      <comments>https://tproger.ru/articles/chto-takoe-rest-api-prostymi-slovami--principy--metody-i-primery?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-takoe-rest-api-prostymi-slovami--principy--metody-i-primery</guid>
      <description><![CDATA[<p>REST API — архитектурный стиль для взаимодействия клиента и сервера через HTTP. Разбираем 6 принципов REST, методы GET, POST, PUT, DELETE и CRUD на примерах.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-takoe-rest-api-prostymi-slovami--principy--metody-i-primery">Что такое REST API простыми словами: принципы, методы и примеры</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 28 Mar 2026 15:28:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вы наверняка сталкивались с REST API, даже если не знали об этом. Каждый раз, когда мобильное приложение загружает ленту новостей, а сайт показывает прогноз погоды — за кулисами работает именно REST API. Разберёмся, как устроена эта технология и почему она стала стандартом веб-разработки.</p><p><b>REST API</b> (Representational State Transfer Application Programming Interface) — это архитектурный стиль взаимодействия между клиентом и сервером через протокол HTTP. Клиент отправляет запрос на определённый URL, а сервер возвращает данные — чаще всего в формате JSON. REST не является протоколом или стандартом: это набор архитектурных принципов, которым следует разработчик при проектировании API.</p><p>— REST API — это архитектурный стиль, а не протокол. Он основан на 6 принципах, предложенных Роем Филдингом в 2000 году</p><p>— Для работы с ресурсами используются HTTP-методы: GET (чтение), POST (создание), PUT (обновление), DELETE (удаление)</p><p>— Каждый ресурс имеет уникальный URL — эндпоинт, к которому обращается клиент</p><p>— REST проще SOAP и гибче GraphQL — именно поэтому более 80% публичных API используют REST</p><p>— JSON не обязателен — REST может возвращать XML, HTML или даже обычный текст</p><h2>Что означает REST — 6 принципов архитектуры</h2><p>Термин REST ввёл Рой Филдинг в своей докторской диссертации в 2000 году. Он описал 6 архитектурных ограничений, которым должна соответствовать система, чтобы считаться RESTful.</p><ol><li><b>Клиент-сервер</b> — клиент и сервер разделены. Клиент отвечает за интерфейс, сервер — за хранение данных и бизнес-логику. Это позволяет развивать их независимо</li><li><b>Отсутствие состояния (Stateless)</b> — каждый запрос содержит всю информацию, необходимую для его обработки. Сервер не хранит контекст между запросами</li><li><b>Кэширование</b> — ответы сервера могут быть помечены как кэшируемые. Это снижает нагрузку и ускоряет работу клиента</li><li><b>Единообразный интерфейс</b> — все ресурсы доступны через стандартные HTTP-методы и имеют предсказуемые URL. Это главное отличие REST от других подходов</li><li><b>Многослойная архитектура</b> — между клиентом и сервером могут находиться промежуточные слои: балансировщики, прокси, кэш-серверы. Клиент не знает, общается ли он напрямую с сервером</li><li><b>Код по запросу (необязательно)</b> — сервер может передавать клиенту исполняемый код, например JavaScript. Этот принцип — единственный необязательный из шести</li></ol><h2>HTTP-методы — GET, POST, PUT, DELETE</h2><p>REST API использует стандартные HTTP-методы для операций над ресурсами. Каждый метод соответствует определённому действию — это называется <b>CRUD</b> (Create, Read, Update, Delete).</p><h3>GET — получение данных</h3><p>Запрашивает ресурс с сервера. Не изменяет данные — только читает.</p><p>Ответ сервера:</p><h3>POST — создание ресурса</h3><p>Создаёт новый ресурс на сервере. Данные передаются в теле запроса.</p><h3>PUT — обновление ресурса</h3><p>Полностью заменяет ресурс новыми данными. Если нужно обновить одно поле — используют PATCH.</p><h3>DELETE — удаление ресурса</h3><p>Удаляет ресурс с сервера.</p><p>Сервер обычно возвращает статус 204 No Content — данные удалены, тело ответа пустое.</p><h2>Как выглядит REST API на практике — пример CRUD</h2><p>Представим, что мы проектируем API для управления задачами (to-do list). Вот как будет выглядеть набор эндпоинтов:</p><p>Обратите внимание на структуру URL. Ресурс — это существительное во множественном числе (/tasks), а действие определяется HTTP-методом, а не URL. Именно поэтому /api/deleteTask — это плохой REST, а DELETE /api/tasks/1 — хороший.</p><p>Пример запроса на создание задачи и ответа сервера:</p><p>Сервер вернул статус 201 Created и добавил поля id и createdAt, которые генерируются автоматически.</p><h2>REST vs SOAP vs GraphQL</h2><p>REST — не единственный способ построить API. Сравним его с двумя другими популярными подходами.</p><p><b>SOAP</b> (Simple Object Access Protocol) — протокол, разработанный Microsoft в 1998 году. Использует XML для запросов и ответов, требует строгую схему (WSDL). SOAP популярен в корпоративных системах и банках, где важна формальная спецификация и встроенная безопасность (WS-Security). Но он значительно тяжелее REST: XML-конверты, обязательные заголовки, сложная настройка.</p><p><b>GraphQL</b> — язык запросов от Facebook* (2015). Клиент сам описывает, какие данные ему нужны, в одном запросе. Это решает проблему over-fetching (когда REST возвращает лишние поля) и under-fetching (когда нужно несколько запросов). Но GraphQL сложнее в реализации и отладке, а кэширование требует дополнительных усилий.</p><p><i>* Meta признана экстремистской и запрещена в России</i></p><ul><li><b>REST</b> — простой, стандартный, подходит для большинства задач. Лучший выбор, если API публичное или команда небольшая</li><li><b>SOAP</b> — для корпоративных интеграций с жёсткими требованиями к безопасности и контрактам</li><li><b>GraphQL</b> — для сложных клиентов, которым нужна гибкость в выборке данных (мобильные приложения, SPA)</li></ul><h2>Заключение</h2><p>REST API — это фундамент современной веб-разработки. Его сила — в простоте: стандартные HTTP-методы, понятные URL, предсказуемые ответы. Именно поэтому REST используют такие компании, как Google, GitHub, Stripe и тысячи других.</p><p>Если вы только начинаете работу с API — попробуйте отправить GET-запрос к любому публичному API (например, <a href="https://api.github.com/users/octocat">GitHub API</a>) через curl или Postman. Это лучший способ понять, как всё работает на практике.</p><p>Чтобы глубже разобраться во взаимодействии клиента и сервера, рекомендуем нашу статью <a href="https://tproger.ru/explain/frontend-backend-interaction">Frontend и Backend: как они взаимодействуют</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Ваш debounce вас обманывает — и вот почему</title>
      <link>https://tproger.ru/translations/vaw-debounce-vas-obmanyvaet---i-vot-pochemu</link>
      <comments>https://tproger.ru/translations/vaw-debounce-vas-obmanyvaet---i-vot-pochemu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/vaw-debounce-vas-obmanyvaet---i-vot-pochemu</guid>
      <description><![CDATA[<p>Debounce снижает частоту вызовов, но не контролирует сетевые запросы. Разбираем race conditions и ошибки, исправляем через AbortController и retry.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/vaw-debounce-vas-obmanyvaet---i-vot-pochemu">Ваш debounce вас обманывает — и вот почему</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 28 Mar 2026 14:02:07 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://www.geeksforgeeks.org/javascript/debouncing-in-javascript/">Debounce</a> — один из тех паттернов, которые фронтенд-разработчик узнаёт в самом начале карьеры и использует всю оставшуюся жизнь.</p><p>По сути debounce делает одну простую вещь: собирает серию вызовов и превращает их в один вызов после паузы. Отлично подходит для «шумных» UI-событий.</p><p>Самый типичный пример — автодополнение в поиске. Но тот же паттерн работает для обработки resize, scroll, live-валидации, фильтров и хуков аналитики.</p><p>Классическая реализация выглядит так:</p><p>Выглядит дисциплинированно. Ощущается эффективно. Быстро доезжает до прода.</p><p>И вот тут начинается обман.</p><p>Проблема не в самом debounce. Проблема в связке «debounce + fetch», когда в уравнение входит реальная сеть.</p><p>Debounce создаёт ощущение, что запросы «под контролем». Но он не контролирует жизненный цикл запроса: порядок ответов, отмену устаревших запросов, поведение при ошибках.</p><p>Именно поэтому в продакшене debounce «врёт»: UI выглядит плавно, а сетевой слой по-прежнему хрупкий.</p><p>В этой статье мы оставим debounce для того, в чём он хорош (сглаживание UI), и укрепим сетевой слой отменой запросов, повторными попытками и корректной обработкой ошибок.</p><blockquote><b>Ключевые выводы:</b><br />— Debounce — это паттерн UI, а не паттерн работы с сетью<br />— Он гарантирует только одно: «я не буду вызывать функцию слишком часто»<br />— Порядок ответов, отмена устаревших запросов и обработка ошибок — это то, что вам придётся решать отдельно<br />— AbortController отменяет устаревшие запросы на уровне сети<br />— Повторные попытки с экспоненциальной задержкой спасают от транзиентных ошибок сервера</blockquote><h2>Проблема 1 — гонка запросов (race conditions)</h2><p>На локальной машине всё летает. Но в продакшене сеть непредсказуема: запросы могут приходить с разной задержкой, и нет никакой гарантии, что ответы придут в том же порядке, в каком были отправлены.</p><p>Представьте: пользователь печатает 12345678. Debounce пропускает запросы для 1234567 и 12345678. Ответ на 1234567 задерживается на сервере и приходит <i>после</i> ответа на 12345678. UI обновляется последним пришедшим ответом — и показывает устаревшие данные.</p><p>Это классическая гонка запросов, и debounce сам по себе её не предотвращает.</p><h3>Решение — AbortController</h3><p>Нам нужно гарантировать, что обрабатывается только ответ на последний запрос, а все предыдущие — отменяются. <a href="https://developer.mozilla.org/en-US/docs/Web/API/AbortController">AbortController</a> — это браузерный API, который позволяет отменять fetch-запросы. Создаём контроллер, передаём его signal в fetch, и вызываем abort(), когда нужно отменить запрос.</p><p>Что изменилось:</p><ul><li>Перед каждым запросом мы отменяем предыдущий через abort() и создаём новый контроллер</li><li>В блоке catch проверяем, является ли ошибка AbortError — это ожидаемое поведение, а не реальный сбой</li></ul><p>Результат: в обычном потоке только последний запрос из серии нажатий доходит до конца. Предыдущие отменяются на уровне сети, а не просто игнорируются после получения ответа.</p><h2>Проблема 2 — сетевые ошибки</h2><p>Сеть непредсказуема не только по задержкам, но и по надёжности. Иногда запрос, который мог бы пройти при повторной попытке, просто падает. Причины: кратковременная перегрузка сервера, пики нагрузки, таймауты базы данных.</p><h3>fetch не бросает исключение при HTTP-ошибках</h3><p>Это одна из главных ловушек нативного fetch: он отклоняет промис только при сетевых сбоях (нет соединения). Коды 4xx и 5xx — это «успешные» ответы с точки зрения fetch. Если сервер вернёт 500, ваш код радостно вызовет response.json() и получит undefined вместо данных.</p><p>Исправляем проверкой response.ok:</p><p>Теперь 500-я ошибка выбрасывает исключение до того, как мы пытаемся разобрать тело ответа. Блок catch обработает её корректно.</p><h3>Повторные попытки с экспоненциальной задержкой</h3><p>Но простая проверка — это только начало. В реальном приложении стоит добавить автоматические повторные попытки для транзиентных ошибок. Если запрос упал из-за временной проблемы, лучше попробовать ещё раз с нарастающей задержкой, чем сразу показывать ошибку пользователю.</p><p>Писать логику повторов вручную — это циклы, счётчики попыток, тайминги, и всё это должно корректно работать с отменой. Нетривиально и неинтересно. Воспользуемся библиотекой <a href="https://github.com/nickersoft/fetchkit">@fetchkit/ffetch</a> — это тонкая обёртка над fetch, которая решает именно эту задачу.</p><p>Есть и альтернативы: <a href="https://github.com/sindresorhus/ky">ky</a>, <a href="https://github.com/axios/axios">axios</a> или собственная обёртка. ffetch выбран за совместимый с fetch API и корректную работу с AbortController при повторных попытках.</p><p>Что нам это даёт:</p><ul><li>retries: 3 — при 500-й ошибке библиотека повторяет запрос до 3 раз</li><li>shouldRetry — повторяем только при 5xx; всё остальное (сетевая ошибка, отмена) пробрасывается сразу</li><li>throwOnHttpError: true — автоматически бросает исключение на HTTP-ошибки, не нужна ручная проверка response.ok</li><li>Задержка между повторами учитывает AbortController — если abort() вызван во время ожидания, повтор немедленно прекращается</li></ul><p>Последний пункт особенно важен. Без этого отмена запроса в середине серии повторов убила бы текущий fetch, но оставила бы таймер — и следующая попытка сразу бы упала с AbortError.</p><h2>Полное решение</h2><p>Собираем всё вместе: debounce для UI-сглаживания, AbortController для отмены устаревших запросов, ffetch для повторных попыток и автоматической обработки HTTP-ошибок.</p><p>Каждый слой отвечает за своё: debounce снижает частоту вызовов, AbortController гарантирует, что обрабатывается только актуальный запрос, а ffetch добавляет устойчивость к транзиентным сбоям.</p><h2>Частые вопросы</h2><h3>Зачем AbortController, если debounce и так снижает количество запросов?</h3><p>Debounce снижает <i>частоту</i> вызовов, но не контролирует, что происходит с уже отправленными запросами. Если два запроса ушли один за другим, более ранний может вернуться позже — и перезаписать актуальные данные. AbortController отменяет устаревший запрос на уровне сети, а не просто игнорирует ответ.</p><h3>Можно ли обойтись без сторонней библиотеки для повторов?</h3><p>Да, можно написать retry-логику вручную. Но это циклы, счётчики, экспоненциальная задержка и корректная обработка отмены. В продакшен-коде проще использовать готовое решение — ffetch, ky или axios — чтобы не изобретать велосипед и не допускать ошибок в edge-кейсах.</p><h3>Работает ли этот подход с React / Vue / Angular?</h3><p>Да. AbortController и retry-логика — это чистый JavaScript, независимый от фреймворка. В React, например, AbortController часто используется в useEffect для отмены запросов при размонтировании компонента. Принцип тот же: debounce для UI, отмена и повторы для сетевого слоя.</p><h2>Выводы</h2><p>Debounce — не проблема. Проблема — считать его полным решением для управления сетевыми запросами, когда он контролирует только одно измерение: частоту вызовов.</p><p>Debounce — это паттерн UI, а не паттерн работы с сетью. Чтобы построить надёжное приложение, нужно дополнить его управлением жизненным циклом запросов:</p><ul><li>Отмена устаревших запросов через AbortController</li><li>Повторные попытки с экспоненциальной задержкой для транзиентных сбоев</li><li>Корректная обработка HTTP-ошибок (проверка response.ok или автоматический проброс через библиотеку)</li></ul><p>Тогда UI будет не только отзывчивым, но и точным — даже при непредсказуемых сетевых условиях.</p><p><i>Адаптированный перевод статьи <a href="https://blog.gaborkoos.com/posts/2026-03-28-Your-Debounce-Is-Lying-to-You/">Your Debounce Is Lying to You</a> Габора Кооша (Gabor Koos).</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Что случилось с WebAssembly — и почему вы не заметили, как он победил</title>
      <link>https://tproger.ru/translations/chto-sluchilos-s-webassembly---i-pochemu-vy-ne-zametili--kak-on-po</link>
      <comments>https://tproger.ru/translations/chto-sluchilos-s-webassembly---i-pochemu-vy-ne-zametili--kak-on-po?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/chto-sluchilos-s-webassembly---i-pochemu-vy-ne-zametili--kak-on-po</guid>
      <description><![CDATA[<p>WebAssembly не заменил JavaScript — и не должен был. Figma, Cloudflare, Godot, Squoosh уже используют Wasm. Разбираем, как Wasm стал мостом между языками.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/chto-sluchilos-s-webassembly---i-pochemu-vy-ne-zametili--kak-on-po">Что случилось с WebAssembly — и почему вы не заметили, как он победил</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[WebAssembly]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 27 Mar 2026 16:15:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>В каждом обсуждении WebAssembly найдётся комментарий в стиле «а что с ним стало?». Его рекламировали как революцию. Мы не видим сайтов, полностью написанных на Wasm. Он провалился? Это новый JVM-апплет?</p><p>Нет. WebAssembly победил — просто не так, как все ожидали.</p><p><b>Главное:</b> WebAssembly не заменил JavaScript в браузере — и не должен был. Его главная роль — мост между языками. Figma, Godot, Squoosh, Cloudflare Workers, Zellij — все они используют Wasm, но вы этого не замечаете — и это нормально.</p><h2>Где Wasm уже работает</h2><ul><li><b>Figma</b> — конвертирует C++ кодовую базу в браузерное приложение + запускает пользовательские плагины в песочнице через QuickJS+Wasm</li><li><b>Godot</b> — сборка игр для веба</li><li><b>Squoosh.app</b> — использует C/C++ библиотеки сжатия изображений прямо в браузере</li><li><b>Stackblitz</b> — веб-контейнеры на Wasm</li><li><b>Ruffle</b> — эмулятор Flash в браузере</li><li><b>Cloudflare Workers</b> — запуск недоверенного кода через V8 isolates</li><li><b>Zellij, Envoy, Lapce</b> — экосистема плагинов на Wasm</li></ul><h2>Что такое WebAssembly на самом деле</h2><p>WebAssembly — это <b>язык</b>. Более точно — байткод, похожий на JVM bytecode, но с меньшим API, более строгими гарантиями безопасности и без мнений о том, как управлять памятью.</p><p>Он достаточно низкоуровневый, чтобы чисто компилироваться под большинство архитектур без значительных потерь скорости. При этом Wasm-программа не может ничего без явного разрешения хоста — ни читать файлы, ни ходить в сеть. Всё внешнее — через импорты.</p><h2>Цель компиляции, не язык разработки</h2><p>В Wasm компилируются десятки языков: <b>Rust, C, Zig, Go, Kotlin, Java, C#</b>. Даже интерпретируемые языки работают — их рантаймы компилируются в Wasm (<b>Python</b> через Pyodide, <b>PHP, Ruby</b>). Есть и языки, которые компилируются исключительно в Wasm: <b>AssemblyScript, Grain, MoonBit</b>.</p><p>Ваш браузер уже умеет запускать Wasm. Но есть и автономные рантаймы: <b>Wasmtime</b>, <b>WasmEdge</b>, <b>Wasmer</b> — аналоги JVM, но для Wasm.</p><h2>Безопасность — главное преимущество</h2><p>Всё внешнее взаимодействие — явные импорты от хоста. Это даёт <b>изоляцию на уровне процесса внутри одного процесса</b>. Cloudflare запускает недоверенный код через V8 isolates — старт <b>в 100 раз быстрее</b>, чем отдельный процесс. Fermyon заявляет о старте менее чем за миллисекунду.</p><h2>Мост между языками — главная роль</h2><p>Самое распространённое применение — <b>мост между языками</b>. В большинстве случаев Wasm прозрачен для вас — какая-то библиотека просто использует его в дереве зависимостей. Это обработка изображений, OCR, физические движки, рендеринг, базы данных, парсеры.</p><h2>Ограничения</h2><ul><li>В браузере Wasm работает через тот же пайплайн, что и JS — потолок на производительность</li><li>Пересечение границы хост-программы стоит дорого — пост-мортем Zaplib показал, что постепенная миграция может не дать выигрыша</li><li>Нет нативного строкового типа — системные API приходится пересоздавать, WASI помогает частично</li><li>Самые компактные бинарники даёт Zig, самые тяжёлые без оптимизации — Rust</li></ul><h2>Почему кажется, что ничего не произошло</h2><p>Wasm-инструменты массово используются <b>авторами библиотек</b>, а не разработчиками приложений. Внутренности непрозрачны — и это нормально. Многие ожидали, что можно будет обойтись без .js файлов вообще — это крайне маловероятно, ни один вендор браузеров не работает над этим.</p><p>Фреймворки <b>Blazor</b> (.NET) и <b>Leptos</b> (Rust) позволяют писать веб-приложения без прямого контакта с JS. Стандартизация идёт: <b>WasmGC</b> уже в Chrome, Firefox и Safari; <b>Component Model</b> развивается в Bytecode Alliance.</p><h2>FAQ</h2><h3>WebAssembly быстрее JavaScript?</h3><p>Некорректный вопрос — скорость зависит от рантайма. Но конструкции Wasm хорошо ложатся на современное железо, поэтому в вычислительных задачах Wasm часто быстрее.</p><h3>Wasm заменит JavaScript?</h3><p>Крайне маловероятно. JS остаётся языком браузера, Wasm дополняет его там, где нужны вычисления, безопасность или доступ к библиотекам из других языков.</p><h3>С чего начать?</h3><p>Попробуйте <a href="https://github.com/nicolo-ribaudo/watlings">watlings</a> — упражнения по ручному написанию WAT в стиле rustlings. А для практического применения — wasm-pack для Rust.</p><p>Источник: <a href="https://emnudge.dev/blog/what-happened-to-webassembly/">What Happened To WebAssembly</a> — EmNudge</p>]]></content:encoded>
    </item>
    <item>
      <title>Headless WordPress: архитектура с Next.js, GraphQL и Cloudflare</title>
      <link>https://tproger.ru/articles/headless-wordpress--arhitektura-s-next-js--graphql-i-cloudflare</link>
      <comments>https://tproger.ru/articles/headless-wordpress--arhitektura-s-next-js--graphql-i-cloudflare?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Александр Пехота]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/headless-wordpress--arhitektura-s-next-js--graphql-i-cloudflare</guid>
      <description><![CDATA[<p>Разбираем headless WordPress на практике: Next.js, Cloudflare Workers, GraphQL и архитектура быстрых и масштабируемых сайтов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/headless-wordpress--arhitektura-s-next-js--graphql-i-cloudflare">Headless WordPress: архитектура с Next.js, GraphQL и Cloudflare</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[WordPress]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[CMS]]></category>
      <category><![CDATA[CDN]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 26 Mar 2026 11:29:45 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Почему WordPress?</h2><p>WordPress часто не любят backend-разработчики, и у каждого на это есть свои причины. Кому-то не нравится функциональный стиль разработки, кто-то критикует form-builder и экосистему плагинов. У других WordPress как CMS и PHP как язык программирования до сих пор ассоциируются со стереотипами 10–15-летней давности - будто они устарели и уступают современным технологиям.</p><p>При этом реальность такова, что и PHP, и WordPress - отличные и современные инструменты, которые очень хорошо выполняют свои задачи. Опустим PHP - статья не об этом. Что же можно сказать про WordPress как про продукт и как CMS?</p><p>WordPress по‑прежнему остаётся самой популярной системой управления контентом. Согласно данным команды WordPress, платформа обслуживает более 43% всех веб-сайтов и занимает долю в 61% на рынке CMS. Также статистика показывает, что WordPress используется примерно на 59% сайтов, где известна CMS (это около 42% всего веба).</p><p>Данные были взяты из официального блога WordPress и сайта w3techs.com:</p><ul><li><a href="https://wordpress.com/blog/2025/04/17/wordpress-market-share/" rel="nofollow">https://wordpress.com/blog/2025/04/17/wordpress-market-share/ </a></li><li><a href="https://w3techs.com/technologies/overview/content_management" rel="nofollow">https://w3techs.com/technologies/overview/content_management</a></li><li><a href="https://w3techs.com/technologies/details/cm-wordpress" rel="nofollow">https://w3techs.com/technologies/details/cm-wordpress</a></li></ul><p>При этом, традиционный WordPress объединяет CMS, шаблоны на PHP и монолитные темы. Такая связка усложняет разработку с использованием современных JS фреймворков, а также затрудняет независимое масштабирование фронтенда и бэкенда, и оптимизацию производительности и безопасности. Жёсткая связка страниц, устаревшие PHP‑функции и не самый удобный девелоперский опыт часто заставляют команды искать альтернативы.</p><p>Headless WordPress решает эти проблемы: CMS становится админ-панелью для управления контентом, а отдельный фронтенд отвечает за UI. Такое разделение обязанностей даёт несколько преимуществ: четкое разделение ответственности, независимое масштабирование интерфейса и CMS, упрощенную локальную разработку и CI/CD. CMS превращается в API‑ориентированное хранилище, а современные фреймворки вроде Next.js берут на себя маршрутизацию и рендеринг.</p><h2>Headless WordPress с использованием WPGraphQL</h2><p>Чтобы использовать WordPress как headless‑CMS, нужен API. Также есть интересный пост про headless wordpress в их <a href="https://wordpress.com/blog/2025/03/20/headless-wordpress/" rel="nofollow">официальном блоге</a>.</p><p>В WordPress из коробки есть REST API, но для frontend и mobile приложений часто удобнее использовать GraphQL. <a href="https://wordpress.org/plugins/wp-graphql/" rel="nofollow">WPGraphQL</a> - это open source плагин, который добавляет GraphQL API в WordPress. Используя WPGraphQL, мы получаем:</p><ul><li>Гибкие запросы к таким сущностям, как посты, страницы, произвольным типам постов, таксономиям и пользователям.</li><li>Систему расширений которая позволяет расширять функционал GraphQL бекенда и таким образом поддерживать популярные плагины, тем самым позволяя возвращать дополнительные поля которые не относятся к стандартным полям Wordpress.</li><li>GraphQL API, который даёт очень удобный формат для интеграции фронтенд фреймворков таких как Next.js, Astro и SvelteKit.</li><li>Оптимизацию производительности, поскольку клиент запрашивает только нужные поля и данные делая один запрос вместо группы REST запросов + отдельный фронтенд забирает на себя часть запросов.</li></ul><p>В дополнение к доступному функционалу WPGraphQL можно добавлять дополнительные плагины-расширения, такие как <a href="https://wordpress.org/plugins/add-wpgraphql-seo/" rel="nofollow">WPGraphQL Yoast SEO</a> и <a href="https://woographql.com/" rel="nofollow">WooGraphQL</a> (WPGraphQL для WooCommerce). Таким образом добавив несколько плагинов в базовую инсталляцию CMS можно из коробки получить полностью функциональный GraphQL бекенд, который может покрыть запросы для блога, сео функционал, онлайн-магазин и тд.</p><p>Важно отметить, что изначальная идея использовать WPGraphQL пришла из статьи в блоге <a href="https://vercel.com/kb/guide/wordpress-with-vercel" rel="nofollow">Vercel</a>.</p><figure><img src="https://media.tproger.ru/user-uploads/136948/2026-03-25/838bc085-bfe5-4888-a326-6dcc00b0aaf5.webp" alt="Сравнение традиционного WordPress и headless WordPress: монолитная CMS с PHP темами против архитектуры с WPGraphQL API и Next.js фронтендом" /><figcaption>Традиционный WordPress vs Headless WordPress: разделение CMS и frontend через API (WPGraphQL + Next.js)</figcaption></figure><h2>Фронтенд на Next.js</h2><p><a href="https://nextjs.org/" rel="nofollow"> Next.js</a> - production-ready React-фреймворк, который разрабатывается компанией Vercel. Многие используют его по умолчанию для разных headless‑проектов. Наш пример headless-wordpress не исключение. Фреймворк предлагает удобную <a href="https://nextjs.org/docs/pages/building-your-application/routing" rel="nofollow">маршрутизацию</a> на базе файловой системы, где любой файл в папке pages автоматически становится маршрутом и поддерживает несколько стратегий рендеринга:</p><ul><li>Server‑side rendering (SSR) позволяет генерировать HTML при каждом запросе.</li><li>Статическая генерация (включая [Incremental Static Regeneration])</li><li>React Server Components, стратегия которая дает гибкость в балансировании производительности и кэширования.</li></ul><p>Это делает Next.js хорошей платформой для работы с GraphQL API и рендеринга страниц React‑компонентами. Если у вас нет опыта с <a href="http://nex.js">Next.js</a> и React, то это не повод не попробовать набросать POC в свободное время. Современные <a href="http://next.js">Next.js</a> и React templates + хороший AI agent помогут адаптировать UI под GraphQL для вас.</p><h2>Почему Cloudflare?</h2><p>Vercel очень часто является платформой по умолчанию для Next.js‑приложений. Более того Next.js адаптирован для запуска из коробки на серверах Vercel. При этом нужно добавить, что идея этой статьи не в том чтобы как-то компрометировать Vercel. Что же нужно знать про Cloudflare чтобы обратить внимание на этот сервис с точки зрения альтернативы для хостинга Next.js?</p><p>Согласно <a href="https://w3techs.com/technologies/details/cn-cloudflare" rel="nofollow">статистике</a>, реверс-прокси сервисы Cloudflare используются примерно на 21,9% всех сайтов в интернете, а это более 82% сайтов, где используется прокси‑сервисы в принципе. Такая распространённость говорит о масштабе, надежности и глобальном охвате сервиса. Но Cloudflare - это не только reverse-proxy. Компания разрабатывает целую группу облачных сервисов, включая такие сервисы, как Cloudflare Pages - альтернатива Github Pages, Workers - Serverless functions (по аналогии с AWS Lambda), Контейнеры, Очереди, AI сервисы, R2 Object Storage, и другие. В дополнение ко всему, компания предоставляет такие сервисы, как защита сайта (site-protection), VPN и капча (human-detection captcha). Такое разнообразие сервисов делает сервис очень распространенным.</p><h2>Лимиты бесплатного тарифа Cloudflare</h2><p>Одним из самых интересных аргументов в пользу Cloudflare можно считать их бесплатный тариф. Защита от DDoS, Universal SSL и глобальную CDN доступны бесплатно. Также бесплатный тариф включает большинство из вышеперечисленных облачных сервисов. Например, Cloudflare Workers, который можно использовать для хостинга Next.js-проектов, бесплатно даёт 100,000 запросов в день. Или R2 object storage - альтернатива S3 по умолчанию дает 10GB пространства, которое можно использовать для хранения статики или других данных. Этого более чем достаточно чтобы поэкспериментировать на выходных с новым стеком и вполне достаточно для того, чтобы бесплатно хостить ваш проект до тех пор пока у вас не пойдет серьезный трафик. Ниже приведена таблица с некоторыми из Cloudflare сервисов и что включено в бесплатный тариф.</p><figure><img src="https://media.tproger.ru/user-uploads/136948/2026-03-25/826d92c6-cecd-4d70-a2ee-78733a324a70.webp" alt="Таблица сервисов Cloudflare (Workers, KV, D1, R2 и др.) с лимитами бесплатного тарифа и их назначением" /><figcaption>Cloudflare free tier: сервисы и лимиты, достаточные для запуска headless WordPress + Next.js проекта. Взято с https://dev.to/ioniacob/which-cloudflare-services-are-free-2025-free-tier-guide-53jl.</figcaption></figure><h2>Запуск Serverless функций на edge-серверах</h2><p>Cloudflare Workers позволяют запускать серверлесс‑код по всей сети Cloudflare. Ниже приведено изображение показывающее как работает Edge CDN, когда например статика продублирована на все доступные сервера и таким образом пользователь получает ресурсы с самого близлежащего сервера.</p><figure><img src="https://media.tproger.ru/user-uploads/136948/2026-03-25/6c12d101-f282-4d1a-8d7a-b4119fabdfda.webp" alt="Схема работы CDN: пользователи обращаются к ближайшим edge-серверам, которые кешируют контент и уменьшают нагрузку на origin-сервер" /><figcaption>Как работает CDN: пользователь получает контент с ближайшего edge-сервера, снижая задержку и нагрузку на origin. Источник: https://www.cloudflare.com/learning/cdn/what-is-a-cdn/</figcaption></figure><p>Эта картинка хороша тем, что аналогично CDN статике на этих же серверах можно запускать и Workers (Lambda) функции, тем самым ускоряя вашу инфраструктуру еще больше.</p><p>Одной из интересных особенностей Workers-функций является отсутствие cold-starts. Любой cloud provider обычно подымает docker container или виртуализированное окружение в момент первого запуска программы, а это всегда задержка. Минусом Workers-функций является тот факт что их Runtime API требует чтобы код мог использовать их Web platform APIs. А это в свою очередь ограничивает выбор языка программирования: Javascript, Typescript и WebAssembly. Но благодаря такому подходу Workers используют изолированную модель запуска  и могут быть прогреты еще до момента запуска кода этого воркера. Прогрев начинается еще на этапе TLS-соединения между клиентом и серверами Cloudflare. Полный текст статьи можно почитать в их <a href="https://blog.cloudflare.com/eliminating-cold-starts-with-cloudflare-workers/" rel="nofollow">блоге</a>.</p><figure><img src="https://media.tproger.ru/user-uploads/136948/2026-03-25/4bcd2a0a-5161-46f5-984c-87f4097411dc.webp" alt="Схема работы Cloudflare Workers: прогрев (warmup) и загрузка воркера происходят во время TLS handshake до выполнения HTTP-запроса" /><figcaption>Как Cloudflare Workers устраняют cold-start: прогрев воркера происходит ещё на этапе TLS-соединения.</figcaption></figure><p>Воркеры выполняются на edge-серверах, которые находятся ближе всего к пользователям, тем самым уменьшая задержку и разгружая origin‑сервер (в нашем случае WordPress backend). По аналогии с другими cloud-провайдерами, код внутри Workers Runtime может использовать другие сервисы Cloudflare, такие как:</p><ul><li><a href="https://developers.cloudflare.com/workers/runtime-apis/cache/" rel="nofollow">Cache API</a> - позволяет читать и записывать данные в глобальный edge‑кэш через caches.default, что удобно для кэширования GraphQL‑ответов или страниц Next.js.</li><li><a href="https://developers.cloudflare.com/kv/" rel="nofollow">Workers KV</a> - распределенное key‑value‑хранилище для конфигурации и небольших наборов данных; можно хранить и получать данные глобально с низкой задержкой.</li><li><a href="https://developers.cloudflare.com/workers/configuration/cron-triggers/" rel="nofollow">Cron Triggers</a> - можно сопоставить cron‑выражение с обработчиком scheduled(), чтобы запускать периодические задачи, например, уборку кэша или обновление данных. Триггеры выполняются на малоиспользуемых машинах, максимизируя эффективность.</li></ul><p>Наличие доступа к дополнительным сервисам, таким как базы данных (D1), объектное хранилище (R2), очереди и AI даёт свободу строить более сложные и гибкие архитектуры, что очень полезно в дальнейшем на больших масштабах.</p><h2>OpenNext: мост между Next.js и Cloudflare</h2><p>Самостоятельный деплой Next.js на разные платформы непрост, поскольку среда исполнения Vercel отличается от других. Можно поднять Next.js на Node‑сервере, но его работа отличается от edge‑режима Vercel. OpenNext - это проект с открытым исходным кодом, который адаптирует Next.js для разных серверлесс‑платформ. Важно сказать что у Next.js нет нативного способа само разворачивания на других платформах, кроме Vercel; существующие отдельные адаптеры разрознены и сложны в поддержке. <a href="https://opennext.js.org/" rel="nofollow">OpenNext</a> объединяет усилия в одном адаптере, переводя выход сборки Next.js в формат, совместимый с основными облачными платформами. Проект поддерживают сообщество SST (AWS), команда Cloudflare и Netlify. Соответственно, с помощью OpenNext можно развернуть Next.js на Cloudflare Workers, сохраняя SSR, статическую генерацию и API‑маршруты.</p><p>Cloudflare‑адаптер устанавливается через @opennextjs/cloudflare. Далее следует установить<a href="https://developers.cloudflare.com/workers/wrangler/"> Wrangler</a>, настроить wrangler.toml с вашим Account ID и создать open-next.config.ts для управления кэшем и ассетами. Адаптер собирает приложение Next.js под среду Cloudflare, создает edge‑воркер и конфигурирует кэш для статики и ISR‑страниц (например, используя R2). После публикации Git‑интеграция Cloudflare автоматически разворачивает приложение при каждом пуше в GitHub или GitLab, а для pull‑request создает превью.</p><figure><img src="https://media.tproger.ru/user-uploads/136948/2026-03-25/ffd3d8f8-9e94-4ee2-b1b8-7b7d075a9bbd.webp" alt="Логотипы OpenNext, Cloudflare, AWS Amplify и Netlify, показывающие поддержку деплоя Next.js на разные cloud-платформы" /><figcaption>OpenNext как единый адаптер для деплоя Next.js приложений на разные платформы: Cloudflare, AWS и Netlify</figcaption></figure><h2>Кэширование и уровни производительности</h2><p>Архитектура headless WordPress + Next.js + Cloudflare обычно включает несколько уровней кэша:</p><ol><li>Кэш браузера - стандартный HTTP‑кэш на стороне клиента.</li><li>Кэш edge‑рантайма - Cache API Cloudflare Workers сохраняет HTML‑страницы или GraphQL‑ответы рядом с пользователем; при попадании в кэш контент отдаётся мгновенно, а промахи идут к воркеру или origin.</li><li>Кэш ISR Next.js - технология Incremental Static Regeneration сохраняет отрендеренные страницы на сервере и обновляет их по запросу, снижая нагрузку на WordPress API.</li><li>Кэш GraphQL - API WPGraphQL может реализовывать кэширование по времени или тегам (например, через WPGraphQL Smart Cache), чтобы управлять сроком жизни ответов.</li></ol><p>Эта многоуровневая иерархия кэша обеспечивает, что большинство запросов вообще не доходят до вашего WordPress‑сервера, повышая производительность и снижая нагрузку.</p><p>Пример конечной архитектуры показан на изображении ниже.</p><figure><img src="https://media.tproger.ru/user-uploads/136948/2026-03-25/37141150-e160-423b-a8cd-3784117e6499.webp" alt="" /><figcaption>Архитектура headless WordPress + Next.js на Cloudflare: edge-рендеринг, многоуровневый кэш и взаимодействие с WPGraphQL</figcaption></figure><h2>Автоматизация периодических задач</h2><p>Headless‑сайтам часто требуются периодические действия - например, обновление кэша ISR или синхронизация данных. Cron Triggers Cloudflare позволяют планировать запуск воркера по cron‑выражению. Обработчик scheduled() срабатывает по расписанию и подходит для обслуживания и получения сторонних данных. Триггеры выполняются на малоиспользуемых машинах по всему миру и легко управляются через Wrangler или панель Cloudflare.</p><h2>Модернизация PHP‑стека с Roots toolkit</h2><p>Хотя headless WordPress переносит рендеринг на JavaScript, CMS всё ещё нужно поддерживать. В качестве бонуса хочется порекомендовать экосистему <a href="https://roots.io/" rel="nofollow">Roots</a>, которая предлагает современный инструментарий для разработки на WordPress:</p><figure><img src="https://media.tproger.ru/user-uploads/136948/2026-03-25/27e070e5-39c8-425b-8142-b0b2ce0af69d.webp" alt="Скриншот сайта Roots с описанием инструментов для разработки WordPress: Bedrock, Sage, Trellis и Acorn" /><figcaption>Roots — современный инструментарй для разработки WordPress с использованием Composer, Blade и автоматизированного деплоя. Источник: Roots - https://roots.io/</figcaption></figure><ul><li><a href="https://roots.io/bedrock/" rel="nofollow">Bedrock</a> - шаблон WordPress, которая устанавливает ядро, плагины и темы через Composer. Таким образом Bedrock дает современную для PHP проектов структуру проекта, улучшает структуру папок, использует концепты Двенадцать факторов для конфигурации приложения с помощью .env‑файлы и тд. Более того, управление зависимостями через Composer повышает надежность и позволяет делать деплой приложения на разные сервера без страха что-то забыть или упустить.</li><li><a href="https://roots.io/sage/" rel="nofollow">Sage</a> - стартовая тема WordPress, использующая Blade от Laravel для шаблонов и интегрирующая Tailwind CSS. Sage автоматически генерирует theme.json из конфигурации Tailwind, поддерживает live preview блокового редактора с Vite и позволяет создавать компоненты на Blade. Это помогает фронтенд‑разработчикам отойти от устаревших подходов для разработки тем Wordpress с нуля.</li><li><a href="https://roots.io/trellis/" rel="nofollow">Trellis</a> - DevOps‑инструмент на базе Ansible, который поднимает серверы и автоматизирует деплой. Trellis предоставляет LEMP‑стек (Ubuntu 24.04, Nginx, PHP 8.3, MariaDB), выполняет деплой без downtimes и из коробки поддерживает SSL‑сертификаты. CLI помогает создавать и настраивать серверы, а также разворачивать проекты с атомарными релизами и откатами.</li><li><a href="https://roots.io/acorn/" rel="nofollow">Acorn</a> - интеграция, позволяющая использовать функционал Laravel в WordPress. С Acorn становятся доступны такие инструменты как Blade‑шаблоны, миграции, роутинг, кэширование и Artisan‑подобный CLI внутри WordPress. Это позволяет разработчикам строить плагины и фичи WordPress с использованием современных PHP‑подходов и современного фреймворка .</li></ul><p>Эти инструменты показывают, что экосистема WordPress продолжает развиваться и хорошо сочетается с современными подходами. Иными словами, WordPress - отличное решение, если знать, как его правильно готовить.</p><h2>Собираем всё вместе</h2><p>Архитектура приложения headless WordPress + Next.js + Cloudflare выглядит приблизительно так:</p><ol><li>WordPress (headless) - работает на традиционном сервере или в контейнере. Редакторы управляют контентом в админке. WPGraphQL и его расширения предоставляют GraphQL‑endpoint с данными, SEO и другой информацией, например данными о магазине.</li><li>Next.js фронтенд - React‑приложение, которое получает данные через GraphQL, рендерит страницы на сервере (SSR) или статически (ISR/SSG) и обрабатывает маршрутизацию и взаимодействие с клиентом. Код хранится в Git и автоматически разворачивается благодаря Git‑интеграции Cloudflare.</li><li>Cloudflare Workers - размещают приложение Next.js на edge через OpenNext. Workers исключают cold-starts и работают по аналогии с CDN как можно ближе к пользователю. Они также выполняют кэширование, обрабатывают API‑маршруты и запускают cron‑задачи.</li><li>Кэш на edge и в браузере - несколько уровней кэша гарантируют быструю отдачу статики и отрендеренных страниц. KV, R2 или D1 могут хранить дополнительные данные вроде сессий или объектов.</li></ol><h2>Заключение</h2><p>Headless‑архитектура объединяет универсальность WordPress и гибкость современных JavaScript‑фреймворков. Экспонируя контент через WPGraphQL и потребляя его в Next.js, можно получить больше контроля над рендерингом и тем самым улучшить производительность. Размещение фронтенда на Cloudflare Workers через OpenNext позволяет приблизить фронтенд код к пользователям, устраняет cold-starts, позволяет использовать free-tier и продвинутые уровни кэширования. Инструменты вроде Bedrock, Sage, Trellis и Acorn модернизируют PHP/Wordpress‑сторону и делают CMS такой же удобной в работе, как и современный Next.js/React-фронтенд. Вместе эти технологии создают мощный стек для создания быстрых, масштабируемых и безопасных сайтов, будь то хакатон, pet‑проект или серьёзный продакшн.</p>]]></content:encoded>
    </item>
    <item>
      <title>Создаём микросервис обработки изображений на Go с gRPC</title>
      <link>https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2</link>
      <comments>https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Go разработчик]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2</guid>
      <description><![CDATA[<p>В этой статье мы рассмотрим создание микросервиса обработки изображений на golang с использованием технологии gRPC. Цель статьи - показать как может выглядеть такой сервис и что он может в себя включать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2">Создаём микросервис обработки изображений на Go с gRPC</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[gRPC]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 17 Mar 2026 05:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Вступление</b></p><p>В этой статье мы рассмотрим создание микросервиса обработки изображений на golang с использованием технологии **gRPC**. Цель статьи - показать как может выглядеть такой сервис и что он может в себя включать. В результате мы получим полностью рабочий сервис по обработке изображений, который принимает данные, сохраняет исходную картинку,сжимает её, накладывает на неё ватермарку, изменяет размер изображения, и конвертирует его в нужный формат.</p><p>Разберём возможные варианты взаимодействия клиента с сервером для обработки больших объектов, в нашем случае это картинки:</p><p><b>1. HTTP/1.1 (REST)</b></p><p>Передача изображений в виде текстовых чанков (например, base64) приводит к значительным накладным расходам: бинарные данные увеличиваются на ~33% при кодировании в Base64, а текстовый формат неэффективен для больших объёмов.</p><p><b>2. WebSocket</b></p><p>Подходит для долгоживущих сессий и двустороннего обмена, но избыточен, если нам нужно просто «принять изображение → обработать → вернуть результат». Удержание тысяч соединений ради однократных операций — неоптимально.</p><p><b>3. gRPC</b> использует:</p><p><b>Protocol Buffers</b> — строго типизированный, компактный бинарный формат,</p><p><b>HTTP/2</b> — мультиплексирование, потоки, сжатие заголовков,</p><p><b>Client-Streaming</b> — идеально подходит для передачи одного большого файла (например, изображения) в одном вызове.</p><p><b>I. Постановка задачи</b></p><p><b>Сервис должен:</b></p><p>Принимать изображение и параметры (format, compress, watermark, width[], height[]),</p><p>Сохранять оригинал с уникальным путём (./download/YYYY/MM/DD/UUID/img/...),</p><p>Накладывать водяной знак,</p><p>Генерировать версии заданных размеров,</p><p>Сохранять полученные изображения,</p><p>Возвращать список путей.</p><p>Пример:</p><p>Запрос с width = [1920, 1280], height = [1080, 720], format = "webp", watermark = "logo.png"</p><p>→ Сервис вернёт два пути:</p><p>./download/2026/02/08/abc123/img/abc123_1920x1080.webp</p><p>./download/2026/02/08/abc124/img/abc124_1280x720.webp</p><p><b>II. Архитектура приложения</b></p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/af4f6a18-dac9-4728-bbb3-decfe99bc1c5.webp" alt="" /></figure><p><b>Обработка происходит в строгом порядке:</b></p><p>1.Приём → 2. Сохранение исходного файла→ 3. Сжатие → 4. Watermark → 5. Resize → 6. Конвертация → 7. Ответ.</p><p><b>Структура хранения:</b></p><p>./download/2026/02/08/a1b2c3d4-.../img/</p><p>├── a1b2c3d4-....jpg          ← оригинал</p><p>├── a1b2c3d4-..._800x600.png</p><p>└── a1b2c3d4-..._1024x768.png</p><p><b>Необходимые инструменты:</b></p><p>Для работы с WebP мы используем библиотеку <a href="https://pkg.go.dev/golang.org/x/image/webp" rel="nofollow">golang.org/x/image/webp</a> , а исходные утилиты можно скачать на <a href="https://developers.google.com/speed/webp/download?hl=ru" rel="nofollow">официальной странице Google</a>.</p><p>Для генерации protobuff нам нужен  <b>protoc-gen-go</b></p><p><b>protoc-gen-go-grpc</b></p><p>Позволяет генерировать определения сервисов Go для буфера протокола, заданного нашим .proto файлом <a href="https://github.com/grpc/grpc-go/releases" rel="nofollow">protoc-gen-go-grpc</a></p><p>Также для работы webp нам потребуется работа с CGO, которую мы рассмотрим отдельно.</p><p><b> III. Реализация proto файла</b></p><p>Для начала работы опишем наш proto файл. Это будет сервис с единственным rpc который будет обрабатывать картинки пользователей.</p><p>./proto/image.proto</p><p>Мы используем Client-Streaming RPC — клиент может отправить несколько сообщений, сервер — один ответ. Этот способ поможет нам в случае необходимости гибкого расширения и избежания ограничений на размер одного сообщения.</p><p><b>V. Реализация основных функций</b></p><p><b>1. Создание сервера</b></p><p><b>1.1 Генерация  go файлов из .proto:</b>  Сгенерируем файлы для реализации сервера с помощью protoc:</p><p>У нас должно получиться 2 файла image.pb.go и image_grpc.pb.go в директории proto</p><p><b>1.2 Реализуем конструктор сервера и interceptor</b> (аналог middleware в grpc) восстановления после паники:</p><p>./internal/app/server.go</p><p>Теперь реализуем функцию запуска нашего grpc сервера:</p><p>Мы создали наш grpc сервер, но пока нет никакой реализации ImageServiceServer который сгенерировал нам protoc, это просто интерфейс который нам и нужно реализовать.</p><p><b>2. Реализация ImageServiceServer</b></p><p>Нам необходимо создать структуру ImageServer которая реализует интерфейс ImageServiceServer с его методом DownloadImage, также создадим конструктор для него :</p><p>./internal/app/image.go</p><p>Нам осталось реализовать ключевые функции для нашего сервиса, а именно: saveSourceFiles: отвечает за сохранение исходных файлов и их сжатие, watermark: наложение ватермарки , resizeAndSave: изменения размера картинки и его конвертация в нужный формат изображения.</p><p><b>3. Сохранение оригинала</b></p><p>Мы создаем путь для сохранения картинки, сохраняем её с необходимым для клиента уровнем сжатия и потом для удобства всю метаинформацию об картинке помещаем уже в нашу структуру и работаем в дальнейшем только с ней:</p><p>./internal/app/save.go</p><p>Для ускорения нашего процесса обработки все этапы мы будем выполнять конкурентно с помощью горутин.</p><p><b>4. Водяной знак </b></p><p>Следующим этапом идёт наложение водяного знака на нашу картинку. Процесс наложения: мы передаем каждой горутине по изображению, они его обрабатывают, а для того чтобы убедиться что они все обработались мы применяем sync.WaitGroup. Сам процесс наложения водяного знака это задание параметров для установки его на исходную картинку, в нашем случае мы делаем её полупрозрачную с небольшим углом поворота и в случайном месте и сохраняем её:</p><p>./internal/app/watermark.go</p><p>Остаётся только изменить размер и сохранить в нужном формате наши обработанные изображения.</p><p><b>5. Resize и конвертация.</b></p><p>Теперь создадим файл resize.go и реализуем функцию изменения размера изображении и сохранения в нужном нам формате:</p><p>./internal/app/resize.go</p><p>Теперь реализуем main.go в котором создадим и вызовем наш сервис обработки изображений.</p><p>./internal/cmd/main.go</p><p><b>VI. CGO</b></p><p>Наше приложение полностью готово, но теперь нужно удостовериться, что у нас работает поддержка CGO. Для начала нужно убедиться что мы скачали и установили webp по ссылке [официальная страница Google](https://developers.google.com/speed/webp/download?hl=ru). Далее нам необходимо установить GCC, без него go не может распознать импортированные C файлы, скачиваем и устанавливаем [официальные зеркала GNU](https://gcc.gnu.org/mirrors.html). Теперь нужно проверить, что переменная CGO_ENABLED=1, для этого используем команду go env и проверяем, если она равна 0, то используем go set  CGO_ENABLED=1 и проверяем ,что она применилась, если нет то перезагружаем нашу систему и проверяем. Теперь мы готовы собрать наше приложение и приступить к тестированию.</p><p><b>VII. Тестирование и оптимизация</b></p><p><b>Тестирование с Bruno</b></p><p>Здесь вы можете тестировать удобными для вас средствами такими как Postman, Bruno, Yaak, grpccurl и т.д., главное чтобы они поддерживали тестирование grpc методов. Рассмотрим пример с Bruno:</p><p>1.Конвертируйте изображение в Base64: Image to Base64 Converter</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/3b10f151-2654-42b1-b6a2-1e6805d79ba2.webp" alt="" /></figure><p>2.Откройте Bruno создайте новый grpc запрос</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/94dba9c1-7930-43f5-accf-1753036005db.webp" alt="" /></figure><p>3. Выбираем метод grpc:</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/b614edcd-171f-49e5-8ba2-cd4b73283551.webp" alt="" /></figure><p>4.Уберите ползунок с reflection и укажите .proto файл</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/8a88b632-4d1a-41a0-9818-0822a6613551.webp" alt="" /></figure><p>5.Выберите метод DownloadImage</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/2a0f8f65-cb62-4442-a867-10d3c69f145d.webp" alt="" /></figure><p>6.В поле message заполните поле в соответствии с параметрами, например:</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/8f454490-7182-4641-8a31-f56fe6236546.webp" alt="" /><figcaption>если появляются проблемы при подключении к сервису, то не выносите текстовое представление картинки в переменную</figcaption></figure><p>В поле image нужно скопировать текстовую строку ,что идёт после запятой, сгенерированную на шаге 1</p><p>7.Далее нужно запустить наше приложение и подключиться к нему с помощью кнопки →</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/4a166e9e-22d3-4369-be1e-b68534623765.webp" alt="" /></figure><p>В случае успеха должен появиться статус streaming</p><p>8.Отправляем наше сообщение/сообщения нажав на кнопку "Send message" один или несколько раз и завершаем нашу передачу сообщений с помощью кнопки → (если не нажать то приложение будет ожидать приёма сообщений). Результатом будет возврат путей наших обработанных сообщений</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/7e269ec1-2cec-4926-8ccc-a9de76d3e9ff.webp" alt="" /></figure><p><b>VIII. Заключение</b></p><p>Подведем итоги, мы создали сервис который:</p><p>Использует gRPC для эффективной передачи данных,</p><p>Поддерживает WebP, JPEG, PNG,</p><p>Безопасен в конкурентной среде,</p><p>Можно легко масштабировать.</p><p>В результате получился сервис обработки изображений. Этот подход применим не только к изображениям, но и к любым бинарным данным.</p><p>Исходный код доступен по <a href="https://github.com/art9276/image-converter" rel="nofollow">ссылке</a></p><p><b>Спасибо за внимание!</b></p>]]></content:encoded>
    </item>
    <item>
      <title>Разработчик создал эмулятор процессора x86 на чистом CSS — без единой строчки JavaScript</title>
      <link>https://tproger.ru/news/emulyator-processora-x86-na-chistom-css--ni-strochki-javascript</link>
      <comments>https://tproger.ru/news/emulyator-processora-x86-na-chistom-css--ni-strochki-javascript?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Картофельный Повелитель]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/emulyator-processora-x86-na-chistom-css--ni-strochki-javascript</guid>
      <description><![CDATA[<p>Lyra Rebane создал полноценный эмулятор процессора x86 на чистом CSS — без JavaScript и WebAssembly. Проект использует экспериментальные функции CSS: if(), style queries и @function.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/emulyator-processora-x86-na-chistom-css--ni-strochki-javascript">Разработчик создал эмулятор процессора x86 на чистом CSS — без единой строчки JavaScript</a>»</p>]]></description>
      <category><![CDATA[Красивый хак]]></category>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 06 Mar 2026 07:44:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Lyra Rebane создал(а) <a href="https://lyra.horse/x86css/">x86CSS</a> — полноценный эмулятор процессора архитектуры x86 на чистом CSS. Никакого JavaScript или WebAssembly — все вычисления происходят исключительно силами браузерного движка стилей.</p><h2>Как это работает</h2><p>Эмулятор исполняет реальный машинный код для процессоров <a href="https://en.wikipedia.org/wiki/Intel_8086">Intel 8086</a>. Тактовый генератор построен на CSS-анимациях в сочетании со style container queries, поэтому система работает автономно и не требует от пользователя никакого взаимодействия — программа крутится сама.</p><p>Логика реализована благодаря новым возможностям CSS, которые пока доступны только в экспериментальном виде:</p><ul><li>условные операторы <b>if()</b></li><li><b>style queries</b> (стилевые запросы контейнера)</li><li>кастомные <b>@function</b></li></ul><p>На странице проекта есть скрипт-тег, но он лишь ускоряет работу тактового генератора. Если отключить JavaScript, эмулятор продолжит работать — просто чуть медленнее и менее стабильно.</p><h2>Запуск собственных программ</h2><p>В эмуляторе можно запускать собственные программы. Достаточно написать код на C и скомпилировать его через <a href="https://gitlab.com/tkchia/build-ia16">gcc-ia16</a> с помощью скрипта из <a href="https://github.com/rebane2001/x86css">репозитория</a> автора. На выходе — готовый HTML-файл со стилями, внутри которого исполняется ваш бинарник.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-06/46d28142-b0a2-47e0-85cf-923ecfdd4f03.webp" alt="Репозиторий x86CSS на GitHub" /><figcaption>Репозиторий проекта на GitHub — 726 звёзд, лицензия GPL-3.0</figcaption></figure><p>По умолчанию эмулятору доступно 1,5 КБ памяти, но этот лимит можно увеличить в конфигурации. Программа загружается по адресу 0x100, предусмотрены специальные адреса ввода-вывода для взаимодействия с «железом» — экранным выводом и клавиатурой.</p><h2>Ограничения и совместимость</h2><p>Практического применения у проекта нет — производительность крайне низкая. Зато это отличная демонстрация того, что современный CSS действительно стал тьюринг-полным.</p><p>Из-за использования экспериментальных CSS-функций запустить демку пока можно <b>только в браузерах на базе Chromium</b> (Chrome, Edge, Opera и т.д.). Firefox и Safari пока не поддерживают нужные спецификации, хотя все используемые фичи входят в официальный стандарт CSS.</p><p>Отдельно автор подчёркивает: проект создан полностью вручную, <b>без использования ИИ</b>. CSS написан в Sublime Text, а для генерации повторяющихся частей кода использовался Python-скрипт.</p><p>Попробовать эмулятор можно на <a href="https://lyra.horse/x86css/">сайте проекта</a>, исходный код доступен на <a href="https://github.com/rebane2001/x86css">GitHub</a> под лицензией GPL-3.0.</p>]]></content:encoded>
    </item>
    <item>
      <title>16 лучших конструкторов для создания интернет-магазинов в 2026 году</title>
      <link>https://tproger.ru/articles/16-luchwih-konstruktorov-dlya-sozdaniya-internet-magazinov-v-2026-g</link>
      <comments>https://tproger.ru/articles/16-luchwih-konstruktorov-dlya-sozdaniya-internet-magazinov-v-2026-g?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Ренат Ахметов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/16-luchwih-konstruktorov-dlya-sozdaniya-internet-magazinov-v-2026-g</guid>
      <description><![CDATA[<p>Полный рейтинг 16 лучших конструкторов интернет-магазинов в 2026 году. Сравнение тарифов, шаблонов, интеграций с платежными системами и CRM, SEO-возможностей. Выберите идеальную платформу для старта и масштабирования онлайн-бизнеса.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/16-luchwih-konstruktorov-dlya-sozdaniya-internet-magazinov-v-2026-g">16 лучших конструкторов для создания интернет-магазинов в 2026 году</a>»</p>]]></description>
      <category><![CDATA[Партнёрский материал]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 19 Feb 2026 05:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Надежная платформа для разработки и запуска маркетплейса снижает время выхода на рынок и шорт-лист технических задач: каталог товаров, обработка оплат, интеграции с CRM и 1С.</p><p>Правильно подобранный сервис дает готовые шаблоны, автоматизацию заказов и инструменты для масштабирования без найма команды разработчиков. Выбор непроверенной системы влечет риски – потеря данных, сбои при пиках трафика и скрытые комиссии, которые съедают маржу.</p><p>Здесь рассмотрим платформы, зарекомендовавшие себя по функционалу и реальным кейсам, а не по красивой демонстрации.</p><h2>Лучшие конструкторы интернет-магазинов для пользователей из России – выбор автора</h2><p><a href="https://www.advantshop.net/?a_aid=81aa408d" rel="nofollow">AdvantShop </a>— платформа для масштабируемой торговли, большой номенклатуры и мультискладовой логистикой. Есть инструменты маркетинга, привязка складов и региональные поддомены для разных городов.</p><p><a href="https://readyscript.ru/?r=lenren" rel="nofollow">ReadyScript</a> — это гибкая CMS с готовыми eCommerce-модулями. Комбинирует конструктор и набор инструментов для управления товарами, заказами и интеграций, удобна для кастомизации логистики продаж.</p><p><a href="https://www.insales.ru/signup?aff=378963ab9" rel="nofollow">InSales</a> — это единый инструмент для продаж в сайтах, соцсетях и маркетплейсах. Поддерживает быстрый старт и стандартные интеграции (платежи, доставки, маркетплейсы).</p><p><a href="https://craftum.com/" rel="nofollow">Craftum</a> — это конструктор с акцентом на скорость и масштабируемость. Подойдёт как небольшим магазинам, так и проектам с огромным ассортиментом товарных позиций: импорт CSV, шаблоны и интеграции с сервисами.</p><p><a href="https://tobiz.net/?inviter=319982" rel="nofollow">ToBiz</a> — это простой и понятный редактор для быстрого старта. Подходит для предпринимателей без технической команды: базовый набор (корзина, онлайн-оплаты, удобный WYSIWYG-редактор) и доступные тарифы.</p><h2>Полный рейтинг лучших конструкторов интернет-магазинов</h2><p><a href="https://www.advantshop.net/?a_aid=81aa408d" rel="nofollow"><b>AdvantShop</b></a></p><p><i>7 дней пробного периода.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/b47d94c1-b0b3-40f3-ba8a-9604066acfd9.webp" alt="" /></figure><p>AdvantShop – полнофункциональная платформа для тех, кто строит серьезный, масштабируемый магазин. Подходит для бизнесов разных размеров, от средних до гипермаркетов, с продвинутыми маркетинговыми и складскими сценариями.</p><p>Включает каталог товаров, импорт/экспорт CSV/YML, синхронизацию 1С, многоскладовость, маркетинговые инструменты (триггерные рассылки, сценарии воронок), SEO-настройки, аналитику, поддержку лендингов и автоворонок.</p><p>Плюсы:</p><ul><li>гибкая архитектура с возможностью доработок и модулей,</li><li>CRM и автоматизация маркетинга,</li><li>SEO-поддержка,</li><li>поддержка мультискладов,</li><li>синхронизация с 1С и другими системами,</li><li>современные шаблоны и трансформер дизайна,</li><li>возможность редактировать код и создавать собственные модули.</li></ul><p>Минусы:</p><ul><li>нет полноценного бесплатного тарифа, только тестовый период;</li><li>сложность освоения для новичков, интерфейс может быть перегруженным;</li><li>некоторые ключевые функции доступны только на дорогих тарифах.</li></ul><p>Тарифы: от 2 990 руб. до 9 990 руб. ежемесячно.</p><p><a href="https://readyscript.ru/?r=lenren" rel="nofollow"><b>ReadyScript</b></a></p><p><i>30 дней бесплатного тестирования функционала.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/342bac6f-163d-497c-80c7-a5ac703c526b.webp" alt="" /></figure><p>ReadyScript – это движок/конструктор, хорошо сбалансированный между гибкостью CMS и удобством SaaS.</p><p>Поддерживает интернет-магазин, интеграцию с 1С, управление клиентской базой, CRM, шаблоны, мобильные приложения, SEO-настройки.</p><p>Плюсы:</p><ul><li>открытый код движка, возможность кастомизации;</li><li>интеграция с 1С и другими учетными системами,</li><li>возможность выбора разных редакций под масштаб магазина,</li><li>встроенная CRM и аналитика,</li><li>проверенный временем движок,</li><li>возможность установки «коробочной» версии.</li></ul><p>Минусы:</p><ul><li>сравнительно высокая стоимость пакетов с полным функционалом,</li><li>для кастомных доработок потребуется опытный разработчик.</li></ul><p>Тарифы: от 18 900 руб. до 30 900 руб. в год.</p><p><a href="https://www.insales.ru/signup?aff=378963ab9" rel="nofollow"><b>InSales</b></a></p><p><i>Первые 7 дней тестирования функционала бесплатны.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/4d313212-40a4-4158-9ddf-caed6c80f805.webp" alt="" /></figure><p>InSales – один из наиболее популярных SaaS-конструкторов для онлайн-торговли в России. Хорош для продаж через маркетплейсы и соцсети.</p><p>Поддерживает визуальный редактор сайта, каталог товаров, интеграции с платежами, доставкой, маркетплейсами, более 200 приложений, SEO-инструменты, мульти-каналы продаж, CRM-аналитику.</p><p>Плюсы:</p><ul><li>быстрый старт и простота использования,</li><li>интеграции с маркетплейсами,</li><li>визуальный редактор не требует навыков программиста,</li><li>широкий каталог приложений и расширений,</li><li>SEO-инструменты,</li><li>CRM и аналитика продаж,</li><li>поддержка многоканальных продаж.</li></ul><p>Минусы:</p><ul><li>ограничения на количество товаров в дешевых тарифах,</li><li>для сложной кастомизации потребуются разработчики.</li></ul><p>Тарифы: от 2 295 руб. до 8 330 руб. в месяц.</p><p><a href="https://craftum.com/" rel="nofollow"><b>Craftum</b></a></p><p><i>Можно бесплатно ознакомиться с функционалом.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/24c176f1-f9a1-432b-aabc-ee16370baa9e.webp" alt="" /></figure><p>Этот сервис ориентирован на лёгкий и быстрый запуск проекта.</p><p>Поддерживает до 50 000 товаров, импорт из CSV, визуальный редактор блоков, ИИ-инструменты, SEO-настройки, платежи, блоги, раздел цифровых товаров.</p><p>Плюсы:</p><ul><li>доступный старт,</li><li>интуитивный визуальный редактор,</li><li>поддержка больших каталогов,</li><li>импорт из CSV,</li><li>интеграция ИИ-инструментов,</li><li>SEO-оптимизация встроена.</li></ul><p>Минусы:</p><ul><li>ограничения на сложные кастомные доработки,</li><li>в бесплатной версии доступен очень ограниченный функционал.</li></ul><p>Тарифы: от 149 руб. до 1 049 руб. в месяц.</p><p><a href="https://tobiz.net/?inviter=319982" rel="nofollow"><b>ToBiz</b></a></p><p><i>2 недели тестового периода бесплатно.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/420d2517-c89a-41d2-9218-2629f171012c.webp" alt="" /></figure><p>Подходящий вариант для предпринимателей, которые хотят быстро запустить онлайн-продажи, не вникая в технические детали, отличается минимализмом и интуитивным интерфейсом.</p><p>Поддерживает каталог товаров, корзину, редактор страниц, настройку дизайна и работу с клиентской базой.</p><p>Плюсы:</p><ul><li>быстрый старт без разработчиков,</li><li>поддержка онлайн-платежей,</li><li>удобство управления товарами,</li><li>минимальные технические требования,</li><li>интуитивность интерфейса.</li></ul><p>Минусы:</p><ul><li>меньше продвинутых функций и интеграций, чем у других конструкторов,</li><li>ограничения по масштабируемости при росте магазина,</li><li>ограниченная кастомизация.</li></ul><p>Тарифы: от 450 руб. до 6 750 руб. ежемесячно.</p><p><a href="https://lpmotor.ru/chatbot/?p=lenren" rel="nofollow"><b>LPmottor</b></a></p><p><i>Нет тестового периода или бесплатной версии.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/4cd2f473-4fdb-46a4-8e97-d8bb24aece2a.webp" alt="" /></figure><p>Это конструктор с упором на лендинги, но он поддерживает и создание интернет-магазина. Подходит для бизнеса, где нужно быстро собрать страницу-продажник и магазин, особенно если важны маркетинговые скрипты и форма «встроенных» лидов.</p><p>Шаблоны лендингов, элементы продаж, интеграция с CRM, приём платежей, подключение домена, редактор блоков, SEO-настройки.</p><p>Плюсы:</p><ul><li>быстрый запуск,</li><li>большой выбор шаблонов,</li><li>продающие шаблоны, ориентированные на конверсии;</li><li>прием платежей встроен,</li><li>SEO-оптимизация,</li><li>удобство для маркетологов и владельцев бизнеса.</li></ul><p>Минусы:</p><ul><li>не так гибок, как полнофункциональные CMS;</li><li>ограниченные возможности для крупных каталогов,</li><li>ограничения на кастомизацию.</li></ul><p>Тарифы: от 850 руб. до 1 990 руб. в месяц.</p><p><a href="https://nethouse.ru/?p=lenren" rel="nofollow"><b>Nethouse</b></a></p><p><i>Можно ознакомиться с функционалом бесплатно.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/1d3b7fb5-ffdb-4e6b-adbd-d00c2f5e589f.webp" alt="" /></figure><p>Это один из классических русскоязычных сервисов, подходящий для малого бизнеса.</p><p>Каталог товаров, корзина, приём платежей, простое управление заказами, SEO-инструменты, интеграция домена, формы обратной связи, базовая CRM.</p><p>Плюсы:</p><ul><li>наличие бесплатного тарифа,</li><li>простота в использовании,</li><li>интуитивная панель управления,</li><li>нет необходимости нанимать разработчиков,</li><li>мобильная адаптация,</li><li>быстрый старт,</li><li>возможность подключения своего домена,</li><li>подходит для небольших магазинов.</li></ul><p>Минусы:</p><ul><li>ограниченный функционал в бесплатном тарифе,</li><li>меньше возможностей масштабирования,</li><li>ограниченные маркетинговые инструменты.</li></ul><p>Тарифы: от 499 руб. до 3 500 руб. ежемесячно.</p><p><a href="https://umi.ru/affiliate/?partner_id=6308" rel="nofollow"><b>UMI</b></a></p><p><i>Можно бесплатно создать сайт, но публикация платная.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/e055a7e9-93f5-4815-91da-3c77a0b4f8e7.webp" alt="" /></figure><p>Этот вариант подходит для тех, кому нужен контроль над структурой, дизайном и логикой, но при этом не хочется стартовать «с нуля».</p><p>Поддерживает каталог товаров, корзину, модуль заказов, SEO-настройки, интеграцию с платежными системами, CRM, готовые шаблоны, блоги, мультиязычность, модули продаж, аналитику.</p><p>Плюсы:</p><ul><li>гибкость и кастомизация,</li><li>проверенная CMS,</li><li>SEO-поддержка,</li><li>расширяемость через модули,</li><li>возможность создания сложных магазинов,</li><li>интеграция с разными системами,</li><li>подходит для долгосрочных проектов.</li></ul><p>Минусы:</p><ul><li>порог вхождения выше, чем у простых конструкторов;</li><li>требуется больше времени на конфигурацию,</li><li>дополнительные расходы на доработку и поддержку.</li></ul><p>Тарифы: от 330 руб. до 1 100 руб. ежемесячно.</p><p><a href="https://flexbe.ru/?p=4129" rel="nofollow"><b>Flexbe</b></a></p><p><i>Доступен ограниченный тестовый период использования сервиса в течение 2 недель.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/fd4de354-df4f-48da-9c17-3ed6196db4be.webp" alt="" /></figure><p>Это конструктор сайтов и магазинов, ориентированный на простоту редактирования, визуальный редактор и быструю сборку страниц.</p><p>Сервис предоставляет визуальный редактор страниц, блоки для товаров, каталог, корзина, формы заказа, приём платежей, SEO-блоки, интеграция с доменом, маркетинговые виджеты.</p><p>Плюсы:</p><ul><li>удобный визуальный редактор,</li><li>доступность для новичков,</li><li>быстрый запуск,</li><li>прием платежей,</li><li>SEO-инструменты,</li><li>опция адаптации дизайна.</li></ul><p>Минусы:</p><ul><li>сравнительно небольшие опции для кастомизации,</li><li>не самый лучший вариант для крупных каталогов.</li></ul><p>Тарифы: от 790 руб. до 1 590 руб. в месяц.</p><p><a href="https://affiliates.ukit.com/?flow=6105" rel="nofollow"><b>uKit</b></a></p><p><i>2 недели тестового периода.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/2de87e3a-e955-464b-80df-abc4e01ced6b.webp" alt="" /></figure><p>Это удобная платформа для клиентов, которых интересует простой и максимально короткий путь к запуску небольшого магазина.</p><p>Поддерживает каталог товаров, корзину, базовый магазин, SEO-инструменты, адаптивные шаблоны, работу с доменом, SSL, формы заказа, интеграцию платежей.</p><p>Плюсы:</p><ul><li>простой интерфейс,</li><li>быстрый старт без технических знаний,</li><li>есть бесплатный период для ознакомления с функционалом,</li><li>адаптивные шаблоны,</li><li>SEO-инструменты,</li><li>SSL поддерживается.</li></ul><p>Минусы:</p><ul><li>меньше функций, чем у более продвинутых CMS,</li><li>ограничения по количеству товаров,</li><li>сравнительно невысокая гибкость кастомизации,</li><li>не самый подходящий выбор для крупных или сложных проектов.</li></ul><p>Тарифы: от 990 руб. до 1 650 руб. в месяц.</p><p><a href="https://bazium.ru/" rel="nofollow"><b>Bazium</b></a></p><p><i>Основной функционал доступен для бесплатного ознакомления, но публиковать сайт нельзя.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/ade3b8a9-8330-48b5-975f-e443c4a6e669.webp" alt="" /></figure><p>Это платформа по типу «всё включено» для создания интернет-магазинов и других сайтов с большим набором готовых блоков. Подходит предпринимателям, дизайнерам и тем, кто хочет быстро стартовать без разработки «с нуля».</p><p>Более 200 готовых блоков, гибкая настройка, экспорт-импорт товаров через CSV, онлайн-платежи, личный кабинет, промо-коды, программа лояльности, SEO-настройки.</p><p>Плюсы:</p><ul><li>быстрый запуск маркетплейса,</li><li>более 200 визуальных блоков для гибкой кастомизации,</li><li>импорт-экспорт товаров через CSV,</li><li>поддержка цифровых и физических товаров,</li><li>можно подключить свой домен и SSL,</li><li>CMS-оптимизация под SEO.</li></ul><p>Минусы:</p><ul><li>глубокая кастомизация потребует навыки разработки,</li><li>нет полностью бесплатного тарифного плана, только пробный период.</li></ul><p>Тарифы: от 450 руб. до 3 480 руб. в месяц.</p><p><a href="https://ru.wix.com/" rel="nofollow"><b>Wix</b></a></p><p><i>Есть бесплатная возможность ознакомления с функционалом, но для приёма платежей нужен платный пакет.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/fcac4e59-b0a6-4ab0-bf29-73db4e626a96.webp" alt="" /></figure><p>Это конструктор сайтов с мощным визуальным редактором drag-and-drop.</p><p>Создание страниц с помощью визуального редактора, каталог товаров, корзина, прием онлайн-платежей, SEO-инструменты, интеграция с маркетинговыми приложениями и аналитика.</p><p>Плюсы:</p><ul><li>быстрый старт без знания кода,</li><li>адаптивность под мобильные гаджеты,</li><li>SEO-инструменты встроены,</li><li>хостинг уже включён,</li><li>можно масштабировать магазин,</li><li>поддержка встроенной почты и домена.</li></ul><p>Минусы:</p><ul><li>на бесплатном тарифе нельзя принимать платежи,</li><li>сравнительно высокая стоимость тарифных планов.</li></ul><p>Тарифы: от 9 долларов до 48 долларов ежемесячно.</p><p><a href="https://tilda.ru/?r=c2cga06" rel="nofollow"><b>Tilda</b></a></p><p><i>Можно попробовать бесплатно с ограничениями по функциональности и числу блоков.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/ae8c5999-8fe5-4c96-848d-7412159d302c.webp" alt="" /></figure><p>Это универсальный конструктор сайтов, ориентированный на визуальный дизайн, лендинги и небольшие интернет-магазины. Подходит тем, кому важен эстетичный, продуманный дизайн, и кто хочет контролировать структуру страниц.</p><p>Более 550 блоков, каталог товаров, корзина, онлайн-платежи, SEO-настройки, блог и аналитика.</p><p>Плюсы:</p><ul><li>полный визуальный и дизайн-контроль,</li><li>много шаблонов и кастомных блоков,</li><li>инструменты SEO-оптимизации,</li><li>адаптивные страницы,</li><li>простой экспорт данных.</li></ul><p>Минусы:</p><ul><li>ограниченные возможности без оплаты,</li><li>требуется время на освоение zero-блоков и настройку страниц.</li></ul><p>Тарифы: 750 руб. в месяц за 1 сайт или 1 250 руб. в месяц за 5 сайтов.</p><p><a href="https://www.diafan.ru/" rel="nofollow"><b>Diafan</b></a></p><p><i>Есть бесплатный тарифный план с ограниченным функционалом.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/62daefe8-1d6e-424a-85a5-53bf05f80b26.webp" alt="" /></figure><p>Diafan – это CMS-конструктор с хорошей гибкостью, предназначенный для интернет-магазинов, сайтов-каталогов и корпоративных проектов.</p><p>Каталог товаров, корзина, система заказов, форма обратной связи, SEO-настройки, модули управления пользователями, интеграция через API, мультиязычность, кастомные поля, шаблоны.</p><p>Плюсы:</p><ul><li>полный контроль над кодом и данными,</li><li>гибкость для сложных проектов,</li><li>возможность доработок и кастомизации,</li><li>SEO-поддержка,</li><li>модули для разных типов сайтов,</li><li>интеграции с внешними системами,</li><li>подходит для долгосрочных проектов.</li></ul><p>Минусы:</p><ul><li>для запуска полномасштабного маркетплейса потребуется разработчик,</li><li>хостинг, обновления и безопасность не включены в пакеты и интегрируются отдельно.</li></ul><p>Тарифы: от 1 890 руб. до 27 990 руб. в месяц.</p><p><b>Яндекс KIT</b></p><p><i>Есть бесплатный тариф без продвижения товаров.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/a15a9149-f197-4bee-8ef8-ed8a53adbde9.webp" alt="" /></figure><p>Яндекс KIT – технологическая платформа от Яндекса для запуска и масштабирования интернет-магазина. Отличный вариант для производителей, брендов и ритейлеров, которые хотят собственный магазин с мощной инфраструктурой и маркетинговыми инструментами Яндекса.</p><p>No-code-конструктор магазина, готовые шаблоны, подключение ERP/CRM, платежные и логистические интеграции, ИИ-ассистент, чекаут в один клик, аналитика, автоматическое продвижение, API, передача товарных фидов в Яндекс Поиск и Директ.</p><p>Плюсы:</p><ul><li>быстрый запуск маркетплейса,</li><li>нет комиссии Яндекса с продаж в бесплатном тарифе,</li><li>ИИ-помощник для аналитики и роста,</li><li>чекаут в один клик,</li><li>полная инфраструктура, хостинг ибезопасность;</li><li>возможность настройки CSS/HTML для кастомизации.</li></ul><p>Минусы:</p><ul><li>требуется серьезный бюджет на продвижение, чтобы перейти на платные программы;</li><li>неподходящий вариант для небольшого стартапа.</li></ul><p>Тарифы: платные тарифные планы с продвижением товаров – от 100 000 руб. в месяц.</p><p><a href="https://vigbo.com/" rel="nofollow"><b>Vigbo</b></a></p><p><i>Бесплатного тарифного плана нет, но можно ознакомиться с базовыми функциями до оплаты.</i></p><figure><img src="https://media.tproger.ru/user-uploads/135737/2026-02-18/f04abae4-e6f1-46fd-85dd-cdc7315ad4eb.webp" alt="" /></figure><p>Это простой и компактный конструктор сайтов, инструмент без избыточной сложности, ориентированный на визуальное редактирование и минимальный порог входа.</p><p>Редактор страниц, шаблоны, каталог товаров, корзина, SEO-настройки, приём платежей и интеграции с CRM.</p><p>Плюсы:</p><ul><li>простой интерфейс без перегрузки,</li><li>быстрый старт для небольших сайтов и магазинов,</li><li>не нужен программист,</li><li>базовые инструменты SEO,</li><li>неограниченное дисковое пространство,</li><li>готовые шаблоны под разные задачи.</li></ul><p>Минусы:</p><ul><li>меньше возможностей для масштабных магазинов,</li><li>ограниченные интеграции по сравнению с крупными CMS.</li></ul><p>Тарифы: 75 долларов или 125 долларов в год, скидки при оплате на 2 года.</p><h2>Вывод</h2><p>Выбор конструкции интернет-магазина зависит от ваших задач, масштаба бизнеса и бюджета. Новичкам особенно подойдут простые визуальные инструменты: Wix, Tilda или Vigbo – они дают быстрый старт без технического опыта.</p><p>А более продвинутым или растущим бизнесам стоит рассмотреть гибкие и масштабируемые системы: Bazium для блокового подхода, Diafan CMS, если нужен контроль и кастомизация, или Яндекс KIT, если хотите попасть в экосистему Яндекса и масштабировать продажи.</p><p>Протестируйте бесплатные или пробные периоды, оцените интерфейс и функционал, а затем сделайте окончательный выбор.</p>]]></content:encoded>
    </item>
  </channel>
</rss>