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

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

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

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

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

Регистрация в перечне РКН: https://tprg.ru/64ai
Download Telegram
Наверное, в каждом втором резюме среди навыков есть «системное мышление». С ним не рождаются, ему учатся в процессе работы, с накоплением опыта. Оно помогает видеть картину целиком и структурировать всё, что вы делаете.

Сейчас у этого навыка появилось новое применение: с появлением ИИ-агентов умение поставить задачу и проверить результат стало ещё важнее. И ему можно научиться.
Какие ошибки часто совершают разработчики, стараясь мыслить системно, и что с этим можно сделать, читайте в статье: https://tproger.ru/articles/sistemnoe-mywlenie-dlya-razrabotchika-owibki-kotorye-vy-delaete
❤1
CSS в письме умеет кликать за пользователя, и это самый безобидный приём в списке

Гарет Хейс когда-то разобрал песочницу AngularJS. Последние месяцы он ломал почтовые клиенты: Gmail, Outlook, Fastmail, ProtonMail, Yahoo. Всё, что ниже, проходит через санитайзеры как безопасная разметка.

Начинается скромно. Тег label, у которого в for стоит чужой id, отдаёт клик по элементу, до которого у письма доступа быть не должно. В Outlook так открывается лента интерфейса и закрепляется сообщение. Не починено до сих пор.

Рядом лежат обходы прокси картинок, из-за которых отправитель видит, что письмо открыли, и его IP на экране в ProtonMail.

Дальше становится ещё интереснее. Связка ::before, ::after и opacity разводит то, что видит человек, и то, что читает ИИ-браузер: письмо превращается в промпт-инъекцию.

А вишенкой на торте в статье лежат кража токенов при CSP, который блокирует вообще все внешние ресурсы, и кража паролей.

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

Запрещать label при этом не нужно, режьте у него for: опасна не подпись, а привязка к чужому id. Совет автора даже шире — отдавать чужую разметку в iframe с sandbox. И не пускайте в белый список :has, :checked, :focus и :not: на них собирают поддельные элементы интерфейса.

#css #html #фронтенд #безопасность
🤯4👍1
Чему учиться взрослому профессионалу?

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

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

В новом материале на Tproger собрали семь таких моделей. Они помогают увидеть свою работу как систему и понять, куда двигаться дальше.

https://tproger.ru/articles/kak-ponyat-chemu-uchitsya-vzroslomu-7-modelej-dlya-professionaln
❤3
60–90 КБ в вашем бандле браузер уже умеет сам

К package.json мы обычно ходим с вопросами про уязвимости и версии, но редко с вопросом, делает ли библиотека что-то, чего платформа ещё не умеет. Разбор в Smashing Magazine оценивает цену этой привычки: в среднем приложении 60–90 КБ после минификации и сжатия весят зависимости, которые дублируют то, что браузер уже умеет сам.

Самый жирный кусок — форматирование. timeago.js на 1 КБ заменяется на Intl.RelativeTimeFormat, numeral на 3,9 КБ — на Intl.NumberFormat, humanize-duration на 6,6 КБ — на Intl.DurationFormat. Самописные функции, склеивающие массив в строку через запятую, закрывает Intl.ListFormat, вместе с оксфордской запятой.

Отдельно разобран случай, когда менять не надо вовсе. Temporal лучше Date, но в стабильном Safari его пока нет, а официальный полифил весит 44 КБ против 3 КБ у dayjs. Сегодня такая замена не экономит, а добавляет к бандлу около 41 КБ, поэтому dayjs остаётся на месте до тех пор, пока Temporal не доедет до Safari.

Рекомендую перепроверять зависимости раз в квартал, за это время как раз может выйти полезное обновление. Смотреть статус фич можно на webstatus.dev, значок Baseline есть на каждой странице MDN, а для проверки пачкой в сборке ставится пакет web-features.

#javascript
❤5
Плавные переходы могут сломать интерактивность вашего сайта, но этого легко избежать

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

Дело не в вашем коде. На время перехода браузер кладёт поверх страницы псевдоэлемент ::view-transition размером во весь вьюпорт, и клики достаются ему. Разобрал это Крис Койер, придумавший CSS-Tricks и CodePen: в его демке рядом с анимацией стоит кнопка с alert(), и пока идёт переход, она не отвечает.

Проверить у себя просто: растяните длительность перехода секунд до десяти и откройте в DevTools дерево псевдоэлементов. Наведите курсор на ::view-transition — подсветится весь экран.

К счастью, лечится проблема всего в две строки. Снимаем у :root дефолтный view-transition-name, чтобы корень не попадал в снимок, и разрешаем кликать сквозь оверлей:

:root { view-transition-name: none; }
::view-transition { pointer-events: none; }


Альтернатива — вызывать startViewTransition() не на document, а на контейнере с нужными элементами: тогда и оверлей накроет только его. Но поддержка у этого варианта хуже, так что по умолчанию проще держать две строки выше.

#css
❤4
Ваш сайт может обслуживать ИИ-агентов напрямую, не заставляя их кликать по вёрстке

Агенты уже ходят по вашим страницам и работают с ними как человек: ищут нужную кнопку, разбираются в модалке, заполняют форму и ошибаются ровно там, где интерфейс неочевиден. WebMCP предлагает другой путь. Это экспериментальный стандарт, уже поехавший в Chrome 146: на странице появляется document.modelContext, сайт регистрирует через него свои инструменты, а агент вызывает их напрямую.

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

Один из наборов проксирует ваш собственный MCP-сервер: мост спрашивает у него список инструментов через tools/list и регистрирует каждый как свой. Когда агент такой инструмент вызывает, мост идёт на /mcp того же origin с сессией посетителя. То есть агент работает с вашим бэкендом под правами залогиненного пользователя.

Пока это developer preview с двумя наборами инструментов, и всё исполняется в браузере посетителя. Прежде чем щёлкать тумблер, пройдитесь по tools/list: агенту станет доступно ровно то, что там объявлено, поэтому всё меняющее состояние, от оформления заказа до правки профиля, либо не выкладывайте, либо оставляйте за подтверждением пользователя.

#mcp
❤4
Карьерный потолок не щадит никого: время идёт, таски закрываются, приходит скука и предел. Можно ли вырваться из «Матрицы»?

https://tproger.ru/articles/zhizn-posle-senora-kak-ya-haknul-matricu
❤1👎1
В гриде и флексбоксе наконец заработали нативные разделители между элементами

Линию между колонками мы до сих пор рисуем обходным путём: вешаем бордер на соседний элемент или заводим псевдоэлемент, а потом правим это на переносах строк и по краям сетки. Со 149-й версии Chrome и Edge задача закрывается штатно: свойство column-rule, работавшее раньше только в многоколоночной вёрстке, теперь понимают grid и flexbox, а для второй оси появилось row-rule. Firefox и Safari фичу пока не умеют.

Разработчик из команды Edge рассказывает, что поменялось в фиче с раннего превью:
— почему outset переименовали в inset;
— зачем понадобились отдельные свойства для концов и пересечений линий;
— как gap-rule-paint-order стал rule-overlap;
— для чего появилось rule-visibility-items.

Полифил для отставших браузеров только пишут. Значит, включать фичу можно там, где линии остаются украшением: без поддержки просто ничего не нарисуется, и вёрстка не поедет. А если без разделителей блоки визуально слипаются, придётся ждать полифила или Safari.

#css
🔥7❤3
Ваш сайт может обслуживать ИИ-агентов напрямую, не заставляя их кликать по вёрстке

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

WebMCP предлагает сайту объявить свои действия явно, чтобы искать их не приходилось. Стандарт экспериментально поехал в Chrome 146: на странице появляется document.modelContext, и сайт регистрирует через него инструменты, то есть именованные операции с описанием и параметрами, вроде search_products с поисковым запросом. Агент вызывает нужную операцию как функцию и получает готовый ответ.

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

Отдельный набор пробрасывает наружу ваш собственный MCP-сервер, если он уже есть: скрипт запрашивает у него список инструментов, регистрирует каждый как свой, а вызовы отправляет на /mcp того же origin с сессией посетителя. То есть агент работает с вашим бэкендом под правами залогиненного пользователя.

Пока это developer preview с двумя наборами инструментов, и всё исполняется в браузере посетителя. Прежде чем щёлкать тумблер, пройдитесь по списку инструментов: агенту станет доступно ровно то, что в нём объявлено, поэтому всё меняющее состояние, от оформления заказа до правки профиля, либо не выкладывайте, либо оставляйте за подтверждением пользователя.

#mcp
❤3
Почему хорошие идеи так и остаются в заметках?

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

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

В новом материале на Tproger разбираем три ловушки, которые убивают инициативу внутри компании.

https://tproger.ru/articles/chto-mewaet-zapustit-novye-produkty-vnutri-kompanii
🔥3
Почему учиться в IT стало сложнее?

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

Работает это не так: необходимость разбираться в том, как всё устроено, применять знания и читать код никуда не делась.

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

Почему разбираться теперь приходится глубже и быстрее, и что с этим делать — читайте на Tproger: https://tproger.ru/articles/uchitsya-v-it-stalo-slozhnee-chto-na-samom-dele-izmenil-vajbkoding
❤3
Откройте свой логотип в Chrome и Firefox рядом: в одном он будет толще

Растровая иконка размером пикселей в пятнадцать в двух браузерах выглядит по-разному: в Chrome штрихи полнее, в Firefox ближе к оригиналу. Оказалось, что некоторые изображения Chrome целиком даже не распаковывает.

Разработчик разобрал, почему так: сколько мегабайт памяти браузер на этом экономит, при чём тут блоки 8 на 8 и почему тот же приём годится не только для уменьшения.

Проверить у себя можно за минуту: откройте страницу в двух браузерах и приблизьте иконку. Если разница видна, читайте разбор целиком, он короткий и с примерами до и после. Заодно узнаете, чем это лечится.
❤1
😁22🤯2
uBlock Origin больше не фильтрует рекламу в *Facebook

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

Интереснее механика, из-за которой гонка проиграна. Слово Sponsored на карточке рекламы разбито на отдельные буквы, каждая живёт в своём элементе, и приёму этому около пяти лет. Порядок букв иногда перемешивают, а между ними подставляют фиктивные символы, так что фильтр, ловящий объявление по тексту, получает мусор.

*Компания Meta и её продукты признаны экстремистскими, их деятельность запрещена на территории РФ.
🤯7😁2🗿1
Утечки памяти в JS: почему фронтенд тормозит со временем

Долгоживущие вкладки часто тормозят из-за мелких ссылок, которые не дают сборщику мусора освободить память. В JavaScript объект живёт, пока на него остаётся ссылка, и удаление последней ссылки отправляет его в следующий проход сборщика мусора.

Чаще всего утечки дают забытые таймеры и обработчики событий, отсоединённые DOM-узлы, оставшиеся в массивах, и глобальные переменные без let, const или var. Замыкания тоже держат ссылки дольше, чем нужно.

Проверить проще, чем кажется: в Chrome DevTools вкладка Memory покажет снимок кучи и найдёт объекты, которые висят дольше положенного. А для метаданных объектов посмотрите на WeakMap: при удалении основной ссылки данные уйдут вместе с ней. Подробнее в азборе от Sharique Siddiqui.
❤3
Выбираем менеджер пакетов

При десятке JS/TS-проектов вопрос — не «кто быстрее ставит», а «кто не раздует node_modules и не даст импортнуть левое». Автор сравнения оценил npm, Yarn, pnpm и Bun по этому критерию.

Разбор по ссылке.
👍5❤2👎2
Какой побеждает в тебе?
😁19👍7🔥2🤣1
React не следит за фокусом — useFocus из @reactuses/core делает это за него

В React нет состояния, которое говорит, активно ли сейчас поле ввода. document.activeElement показывает ответ, но не перерендеривает компонент при смене фокуса, а autoFocus стреляет один раз и не даёт вернуть фокус программно. Приходится вешать onFocus и onBlur вручную.

Хук useFocus из @reactuses/core сворачивает это в [isFocused, setFocused]: первая часть отражает реальное состояние элемента, вторая вызывает focus() или blur() по вашей логике. Например, при программном фокусе на поиске.

Для подсветки рамки хватит CSS :focus, но как только фокус начинает управлять JSX через подсказки, плавающие лейблы или паузу тикера, хук убирает шаблонный код.

Я бы сохранил его для форм и модалок, где фокус важен для UX, а не только для стилей. Разобрали в статье.
👍6❤2👎1
Forwarded from IT Юмор
😁35
JWT-аутентификация: лучшие практики

LogRocket разобрал, как не уронить безопасность аутентификации одним неверным решением. Их вывод простой: access короткоживущий и живёт в оперативной памяти, а refresh длинноживущий — прячется в httpOnly-куках, куда JavaScript не достаёт. Даже при XSS атакующий получит только короткий токен, а не ключ к бесконечному входу.

В статье есть и менее очевидные моменты. Если сейчас проектируете аутентификацию или проверяете текущую схему, рекомендую разбор по ссылке.
👍3❤1