📝 Рассказ фронтендера


Гео и язык канала: Россия, Русский
Категория: Технологии


Пишу про frontend (JS/TS/React), задачки с собесов с разбором и теория, советую книжки и многое другое 🤭
Contact: @atrapeznikov

Связанные каналы  |  Похожие каналы

Гео и язык канала
Россия, Русский
Категория
Технологии
Статистика
Фильтр публикаций


Ну с выходом opus 4.8, точно нет 🥵


Уууу валит

811 0 20 4 34

♊️Gemini CLI и Subagents

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

Читать тут


🌐 Превращаем любой сайт в приложение с помощью Pake.

Из интересного: тут не используются Electron или браузеры, а какие-то нативные библиотеки, и написано это всё на Rust. В итоге объем этого приложения может быть меньше 5 МБ, у electron минимум 100 МБ...


# Install Pake CLI
pnpm install -g pake-cli

# Basic usage - automatically fetches website icon
pake https://github.com --name GitHub

# Advanced usage with custom options
pake https://weekly.tw93.fun --name Weekly --icon https://cdn.tw93.fun/pake/weekly.icns --width 1200 --height 800 --hide-title-bar

696 0 21 3 19

Опять тут вышла самая умная. лучшая модель - Qwen 3.7-Max.

И результаты тестов интересные 😁


Когда ты null null, а хотел быть [object Object] 🥲


💦Жидкое стекло в вебе: canvas, WebGPU и без CSS blur

Интересная либа liquid-dom - считывает HTML-структуру страницы, переносит её в Canvas и использует WebGPU/WebGL для рендеринга физически корректных преломлений, бликов и капель в реальном времени.

🌿Github https://github.com/AndrewPrifer/liquid-dom
🌿Демка https://liquid-dom-showcase.vercel.app/


Не забываем 🗒️


😱 Вчера злоумышленник опубликовал 84 вредоносные версии в 42 пакетах @tanstack/*, которые были доступны около 20 минут, пока они не были обнаружены.

Хорошая новость: атаку выявили быстро, пакеты были помечены как устаревшие.
Плохая новость: если вы запускали npm install вчера и у вас есть в проекте @tanstack/* - у вас возможно есть эти вредоносные пакеты...

🥲 А как так получилось ???

Атака строилась на цепочке из трёх уязвимостей. Вредоносный PR использовал pull_request_target в GitHub Actions, чтобы отравить общий pnpm-кэш кастомным payload.

Когда в следующий раз запускался релиз, он восстановил этот заражённый кэш - и код злоумышленника извлёк OIDC-токен прямо из памяти раннера, чтобы опубликовать пакет в npm, не прикоснувшись ни к одному сохранённому credential. Для npm заражённая версия выглядела на 100% легитимной.

Что делал вредоносный payload:

🙈 Сбор учётных данных - AWS, GCP, Kubernetes, Vault, GitHub-токены, SSH-ключи, ~/.npmrc. Всё, до чего можно дотянуться с заражённого хоста

🙊Самораспространяющийся червь - запрашивал реестр npm в поисках других пакетов, которые поддерживает жертва, и заражал их тоже.

🙉 «Мёртвая рука» — скрипт ~/.local/bin/gh-token-monitor.sh устанавливался как systemd-сервис (Linux) или LaunchAgent (macOS) и каждые 60 секунд проверял api.github.com/user с украденным токеном. Если пользователь отзывал токен - срабатывал rm -rf ~/. 

Вот такие новости.

https://github.com/TanStack/router/issues/7383




Вроде там и код на русском пишут....


🖥 Интересная альтернатива Firebase и Supabase - PocketBase
Есть даже SDK для JS.

Но есть нюанс 🤔

Please keep in mind that PocketBase is still under active development and full backward compatibility is not guaranteed before reaching v1.0.0. PocketBase is NOT recommended for production critical applications yet, unless you are fine with reading the changelog and applying some manual migration steps from time to time.


@frontend_tales





896 0 23 3 22

Интересненько 🌚


📹Атрибут poster для тега

Атрибут poster в HTML-теге задаёт изображение-заставку, которое показывается до начала воспроизведения видео. Это как обложка у книги - первое, что видит пользователь.


Ваш браузер не поддерживает видео.


❗Что важно учитывать

☑️Размер и соотношение сторон. Лучше всего, когда размер постера совпадает с размерами видео - иначе браузер растянет или сожмёт картинку, и может появиться некрасивая рамка. Например, для видео 1920×1080 используйте постер такого же разрешения или пропорций 16:9.

☑️Вес файла. Постер загружается раньше видео, поэтому он должен быть лёгким. Имеет смысл сжать JPG или использовать WebP - пользователь увидит заставку быстрее.

☑️Отсутствие постера. Если poster не указан, браузер покажет либо пустой чёрный прямоугольник, либо первый кадр видео (поведение зависит от браузера и атрибута preload).

Практический пример:






Здесь preload="metadata" в паре с poster - хорошая комбинация: браузер не качает само видео заранее, но сразу показывает красивую заставку.


📝 Форматируем списки

Intl.ListFormat - это встроенный JavaScript API для форматирования списков на естественном языке. Вместо ручной склейки строк через запятые и союзы, он делает это автоматически, учитывая правила конкретного языка.

Основной синтаксис:
new Intl.ListFormat(locale, options)

options принимает два ключевых параметра:

🟠type — тип списка: "conjunction" (и), "disjunction" (или), "unit" (просто перечисление)
🟠style — стиль: "long", "short", "narrow"

Примеры:

const items = ['Яблоко', 'Банан', 'Вишня'];

// Союз «и» (conjunction) — по умолчанию
const conjRu = new Intl.ListFormat('ru', { type: 'conjunction' });
conjRu.format(items);
// → "Яблоко, Банан и Вишня"

// Союз «или» (disjunction)
const disjRu = new Intl.ListFormat('ru', { type: 'disjunction' });
disjRu.format(items);
// → "Яблоко, Банан или Вишня"

// Простое перечисление (unit)
const unitRu = new Intl.ListFormat('ru', { type: 'unit', style: 'narrow' });
unitRu.format(items);
// → "Яблоко Банан Вишня"

// Английский для сравнения
const conjEn = new Intl.ListFormat('en', { type: 'conjunction' });
conjEn.format(['Apple', 'Banana', 'Cherry']);
// → "Apple, Banana, and Cherry"

Метод formatToParts - возвращает массив объектов, если нужен контроль над каждой частью:

const fmt = new Intl.ListFormat('ru', { type: 'conjunction' });
fmt.formatToParts(['Кот', 'Пёс', 'Хомяк']);
// → [
// { type: 'element', value: 'Кот' },
// { type: 'literal', value: ', ' },
// { type: 'element', value: 'Пёс' },
// { type: 'literal', value: ' и ' },
// { type: 'element', value: 'Хомяк' }
// ]

Это удобно, например, когда нужно обернуть каждый элемент в с отдельным стилем.


🔵Практический кейс - вывод имён авторов:

function formatAuthors(authors, locale = 'ru') {
if (authors.length === 0) return 'Автор неизвестен';
return new Intl.ListFormat(locale, {
style: 'long',
type: 'conjunction',
}).format(authors);
}

formatAuthors(['Толстой', 'Достоевский']);
// → "Толстой и Достоевский"

formatAuthors(['Толстой', 'Достоевский', 'Чехов']);
// → "Толстой, Достоевский и Чехов"

676 0 12 1 59

CSS-библиотека, которая превращает интерфейс в 8-битную игру 😈

https://nostalgic-css.github.io/NES.css/

@frontend_tales


🔠🔠🔠 Новый раздел в Roadmap'е - инструменты сборки.

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

➡️ Переходим https://frontendtales.ru/ru/roadmap


@frontend_tales


🈵🈹 Регулярки в мультиязычных приложениях

Если вам нужно провалидировать имя при помощи регулярки, будьте аккуратны: в имени могут быть специфичные символы. 😁

Например, такая регулярка /^[a-zа-яё]+$/i - вроде норм, но есть нюанс. Пользователи с именем René или Bożena не пройдут. Изменим регулярку /^\w+$/u - тоже ошибка. В некоторых языках это пройдет, но вот в JavaScript нет - \w строго привязан к латинице ASCII ([a-zA-Z0-9_]) даже с флагом u. Эта регулярка не пропустит кириллицу или арабскую вязь, зато пропустит цифры и нижнее подчёркивание. Для React-приложений с формами это не подходит 👎

🟠/^\p{L}+$/u - разрешает только буквы во всех языках. Флаг u включает поддержку Unicode, а \p{L} (Letter) означает любую букву любого алфавита в мире.

Люди часто имеют двойные имена или именные частицы (Anna-Maria, d'Artagnan, Mary Jane). Строгая регулярка выше такие имена не пропустит. Для продакшена лучше использовать расширенный вариант:
/^[\p{L}\s'-]+$/u - пропускает буквы любых языков, а также пробелы, дефисы и апострофы.

🧑‍💻 Пример функции

export const isValidName = (name) => {
// Используем расширенный вариант для реальной жизни
const nameRegex = /^[\p{L}\s'-]+$/u;
return nameRegex.test(name);
};


@frontend_tales

Показано 20 последних публикаций.

1 806

подписчиков
Статистика канала