Веб-платформа – Telegram
Веб-платформа
2.03K subscribers
4 photos
2 videos
153 links
📍 О том, как всё устроено в веб-платформе и что происходит в индустрии фронтенда

⭐️ Новости, полезные выжимки, находки и напоминания

👨‍💻 Вопросы и предложения @web_platform_support

🔗 webplatform.tech
Download Telegram
Веб-платформа
#Пульс_веб_платформы 15.12.2023 Новости - вышел Safari 17.2, много мелких и классных обновлений в уходящий год, чтобы подбить статистику Interop 2023: аккордеон на <details> + <summary>, onetimecode для инпутов, «расслабленный» CSS-nesting, обновления CSS…
Продолжение

CSS
- кодим SVG-спиннер голыми руками без сторонней помощи (и без страховки)
- что из CSS зарелизилось в браузерах в 2023 (огромное количество класных фич, на 2024 уже даже столько интересного не осталось): тригонометрические функции, микросинтаксис селекторов An+B, scope, nesting, subgrid, initial-letter, text-wrap, color-mix(), relative color syntax, @container и @container style(), :has(), новые возможности медиа-выражений, View Transitions API, linear(), событие scrollend, скролл-анимации с ViewTimeline, анимация дискретных свойств типа display: none, @starting-style, Popover API, <hr> в <select>, псевдоклассы :user-valid и :user-invalid, аккордеон на <details>
- минималистическая сборка CSS с помощью Lightning CSS (немного свело олдскулы)
- будущие нативные функции и миксины в CSS
- SVG-адвент-календарь

HTML
- использование респонсив <video> (аля <picture>) теперь кроссбраузерно (а также зачем-то респонсив <audio>)
- инспекция дерева доступности страницы теперь доступно в Хроме

Платформа
- разбор HTTP/2 по байтам: очень дотошно, душно и исчерпывающе
- исследование Яндекса о частоте использования тех или иных фич доступности на смартфонах: оказывается очень много людей используют системное увеличение шрифта и тёмную тему
- подготовка к мониторингу метрики INP: в целом, рекомендации те же — не допускать долгих блокирующих тасок всеми возможными способами
5👍2🔥2
#Пульс_веб_платформы

Короч, FF 121 вышел, селектор :has() доехал везде, теперь можно! 💫


<body>
<div class="one"></div>
<div class="two"></div>
</body>



.one {
background-color: green;
}

.two {
background-color: orange;
}

body:has(.two:hover) .one {
background-color: red;
}


демо
🔥71
#Пульс_веб_платформы 22.12.2023

Новости
- появился новый линтер oxlint: написан на Rust; можно не настраивать (convention over configuration); плагинов пока нет, но обещают, что можно будет писать их без использования JS или Rust; быстр, но в том числе потому что проверяемых правил мало
- вышел SvelteKit 2: Vite 5 под капотом, подготовка к будущему Svelte 5, shallow routing; tldr: Svetle продолжает прорастать в экосистему
- Vue 2 станет deprecated 31 декабря 2023
- вышел Firefox 121: главное поддержан :has()!
- вышла библиотека date-fns v3: теперь 100% типизирована, уменьшен размер бандла, функции экспортируются через named exports и кое-что ещё
- обновился Tailwind CSS v3.4: динамические viewport units, поддержка :has(), text-wrap: balance, субгриды и многое другое

Проекты
- waku — минималистичный React-фреймворк с поддержкой ServerComponents: включает клиент, сервер и роутер
- constate: библиотека для решения проблемы плодящихся контекстов в Реакте
- simple-web-server: простая декстопная аппка для настройки и запуска дев-сервера

Статьи и демки

JS
- список всех известных (и неизвестных) JS рантаймов и движков на все случаи жизни (даже чтобы выполнять JS в с/с++)
- если промис ушёл и не вернулся, он попал в чёрную дыру: чтобы это исправить нужно отказаться от асинхронных функций в угоду генераторов
- профилируя приложение для локализации автор пришёл к тому, что node --prof и инструмент speedscope — хорошая отправная точка для анализа перфоманса
- члены tc39 устали отвечать на одни и те же вопросы в ишью, и создали faq, в котором можно узнать, почему JSX не появится в ES, почему JSON никогда не поменяется, а также почему числа в JS такие странные
- в конкурсе на самый быстрый способ проброса состояния с сервера на клиент победил <noscript type="mime/invalid" id="myState">{"foo":"bar"}</noscript> window.__STATE__ = JSON.parse(window.myState.innerHTML)
- темы для холиваров в вашей команде, если вы работатете с Реактом: как писать экспорты, как называть файлы и пропсы, нужны ли стрелочные функции, а также тернарники vs early return
- TS-фичи «следующего» уровня: satisfies, infer, exhaustive type checking
- эволюция синхронного рекурсивного обхода папок в ноде достигла вершины — await fs.readdir(dir, { recursive: true })
- всё про Unicode для разработчиков: символы, их объединение, эскейп в JS, сравнение строк и регекспы

CSS
- смена стилей в зависимости от количества элементов с помощью element:has(> :nth-child(10))
- лок скролла из глубины DOM-а с помощью body:has(.lock-scroll) { overflow: hidden} <dialog class="lock-scroll">
- четыре способа создать анимированные градиентные рамки
- свойство animation-composition, позволяет начать анимацию с нуля либо с того значения свойства, которое уже задано на момент начала анимации (удивительно, но поддерживается везде!)

HTML
- в каких случаях подходит использование <link rel=preconnect>
- при использовании атрибута sizes="auto" у img нужно указывать также width и height
- создание шумной текстуры в SVG (секрет в применении SVG-фильтров)
- древнее знание: атрибут form у кнопки позволяет сабмитить форму, даже если кнопка снаружи неё
👍4🔥2
#Лаборатория_веб_платформы

Таймер без фриза с помощью Web Worker

Если в JS запустить таймер с помощью setInterval, который срабатывает довольно часто, например, раз в 100мс, а затем уйти из таба на некоторое время, то окажется, что браузер остановит таймер на время «неактивности» таба. «Фриз» таймера в неактивном табе можно посмотреть тут https://codesandbox.io/p/sandbox/dreamy-bartik-vkkmjr.

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

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

Вот пример таймера в отдельном файле воркера, к примеру, timerWorker.ts :



let timerId: number | null = null;

self.onmessage = (event: MessageEvent) => {
const { data } = event;

switch (data) {
case "start":
timerId = self.setInterval(() => {
self.postMessage("tick");
}, 100);
break;
case "stop":
if (timerId) {
clearInterval(timerId);
timerId = null;
}
break;
}
};


В воркере нет объекта window, но есть self, местный аналог https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/self. С основным приложением воркер общается с помощью команды postMessage. При этом из приложения также можно дёргать postMessage воркера и подписываться на событие onmessage:



function App() {
const [time, setTime] = useState<number>(0);
const workerRef = useRef<Worker | null>(null);

useEffect(() => {
workerRef.current = new Worker("/timerWorker.ts");

workerRef.current.postMessage("start");

workerRef.current.onmessage = (event) => {
if (event.data === "tick") {
setTime((prevTime) => prevTime + 1);
}
};

return () => {
workerRef.current?.postMessage("stop");
};
}, []);

return <div>{time}</div>;
}


В воркере, к сожалению, нет доступа к DOM-у, но зато доступны разные API, например, Fetch или Canvas, так что выгружать в воркер что-то тяжёлое или важное — вполне себе рабочая тема, о которой не стоит забывать.
👍81
#Пульс_веб_платформы 05.01.2024

Новости
- вышел TenStack Router — полностью типизированный (не только на TS, но и сами роуты защищены от ошибок типами) роутер от известного в узких кругах разработчика
- подведены итоги 2023 года в экосистеме JS по версии Rising Stars: победители — shadcn/ui, Bun и Excalidraw

Проекты
- refractror — хайлайтер синтаксиса, основанный на Prism, но отдающий на выходе не строку HTML, а объекты AST
- observable-membrane — создание обсервабл-объектов на основе Proxy
- tokenami — ещё одна CSS-in-JS либа на Тейлвинде + custom properties, типизация из коробки
- catalyst — первая демка UI-кита для Реакта на Тейлвинде, от создателей Тейлвинда
- devicenoscript — среда в VS Code, эмулятор и компилятор TS для программирования IoT-девайсов, контроллеров и прочего хардверного стафа
- оживление текста анимациями «ручных» обводок и подчёркиваний

Статьи и демки

JS
- оказывается цикл forEach всё таки можно остановить (но вряд ли нужно) с помощью throw внутри try с переходом в catch
- в каких случаях нужен flushSync в Реакте: по умолчанию изменения UI батчатся и затем применяются асинхронно, что не всегда подходит (Реакт иногда обновляет UI позже, чем нужно); если нужно гарантировано обновить UI «здесь и сейчас», то flushSync — подходящй инструмент (например, чтобы корректно установить фокус или позицию скролла)
- гайд по паттернам проектирования в JS с простыми примерами
- все JS и TS фичи за последние 3 года: чтиво на ночь для лёгкого засыпания либо для постновогоднего рефлексивного настроения
- кодогенерация и парсинг TS с помощью TS (конкурс на лучший юзкейс объявляется открытым!)
- если для работы с датами не хочется тащить библиотеку, то можно воспользоваться встроенным Intl.DateTimeFormat, который довольно много умеет сам по себе

CSS
- свойство align-content выравнивает элементы не только внутри флексбокса, но также и display: table-cell и list-item
- как происходит загрузка «невидимых» картинок: картинки без loading="lazy" грузятся всегда (даже в скрытом виде), а вот с loading="lazy" грузятся внутри visibility: hidden и не грузятся внутри display: none или <details>
- как выполнить невозможное calc(100vw / 5px) с помощью тригонометрических функций

HTML, SVG
- интерактивный гайд по path (залипательный)

База
- абсолютный минимум о Unicode, который должен знать каждый уважающий себя разработчик в 2023 (и 2024, всё ещё никаких отговорок!)
- сложность алгоритмов. Разбор Big O: для освежения в памяти после новогодних каникул
👍7🔥4👨‍💻1
Телеграм-перестрелка с каналом Евгения Черкасова «Записки тимлида»

Евгений ведёт свой блог давно и по истории канала видно, что он прошёл путь от «фронтенд бати» к роли тимлида в большой компании (вот саммари). Я люблю изучать такие истории людей: в них можно найти что-то близкое по душе или почерпнуть что-то новое из житейской мудрости.

1. В двух словах: история Евгения — история превращения из разработчика, который решает вопросики на уровне кода, в пипл-менеджера, который решает вопросики на уровне людей. История в чём-то позитивная, про успех человека, который идёт вверх по карьерной лестнице, но в чём-то трагическая, так как он при этом неминуемо выпадает из кодинга. В таком состоянии ловишь и синдром самозванца, и синдром менеджера, «у которого лапки», и в целом испытываешь тщетность бытия от потери возможности получать сиюминутный дофамин от решения конкретных задач.

2. Сейчас канал Евгения — это рефлексия о жизни и работе, но разработческие и фронтовые темы тоже иногда проскакивают. Например, за ссыль на conventional commits моё увожение (там есть ещё пара постов про коммит-мессаджи, 1 и 2). Или вот напоминашка про свежие единицы измерения в CSS. Из найденных тимлидовых интересностей и жизненных тем: пост про небольшие изменения, к которым люди постепенно привыкают, пост про обнуление бэклога и годный пост про размытие коллективной ответственности. Также есть душевные истории из жизни: про первого ученика или про балет.

3. Что не понравилось.

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

«Блогеские» темы и призывы к действиям. Налейтай, подпишись, бусты, лайки. Это уже и так везде и всюду, кажется, что это уже не работает, надо по-другому (см предыдущий тейк про аутентичность).

4. Самое ценное, что есть в постах Евгения — его жизненный опыт и живой взгляд на мир. Хочется пожелать ему писать больше годноты в эту сторону, так как чувствуется, что ему есть что сказать. И не терять жизненность историй, это располагает к доверию ❤️

В общем, рекомендую подписаться на @frontend_lead_mentor. А я пойду почитаю разнос разбор моего канала у Евгения 😅
3
#Лаборатория_веб_платформы

Proxy и мемоизация функции

Есть такая платформенная штука — Proxy. Это когда берёшь обычный объект в JS, создаёшь для него прокси и получаешь возможность перехватывать и переопределять основные операции, которые с объектом можно совершить: get, set, delete… Внутри перехватчиков можно, например, логировать, валидировать или дополнять значения. Например:




const target = {
message1: "hello",
message2: "everyone",
};

const handler = {
get(target, prop, receiver) {
console.log(`Свойство ${prop} считалось`);
return target[prop];
},
set(target, prop, value) {
console.log(`Свойству ${prop} задано значение ${value}`);
target[prop] = value;
return true;
},
};

const proxiedObj = new Proxy(target, handler);

proxiedObj.message1
// log: Свойство message1 считалось

proxiedObj.message2 = 'nobody'
// log: Свойству message2 задано значение nobody


Так вот, проксировать можно не только объекты, но и функции. В случае функций через прокси можно перехватывать момент вызова функции (перехватчик apply) и, например, манипулировать аргументами до вызова.




const a = () => {
// функция
}

const b = new Proxy(a, {
apply: (target, thisArg, argumentsList) => {
// перехватчик вызова
}
})


До вызова функции мы получаем референс на саму функцию, контекст и массив агрументов и можем с ними делать что угодно перед тем, как непосредственно вызвать (или даже не вызвать) функцию. К примеру, можно организовать кэш, чтобы по переданному набору аргументов запомнить вычисленное значение и при повторном вызове брать его из кэша.




function memoize(target) {
const cache = new Map();

return new Proxy(target, {
apply: (target, thisArg, argumentsList) => {
const key = JSON.stringify(argumentsList);
if (cache.has(key)) {
console.log(
`Результат для ${argumentsList} взят из кэша`,
);
return cache.get(key);
} else {
const result = target.apply(thisArg, argumentsList);
cache.set(key, result);
return result;
}
},
});

const add = (a, b) => a + b;
const memoizedAdd = memoize(add);

memoizedAdd(3, 7); // Вычисляет и записывает в кэш
memoizedAdd(3, 7); // Берёт результат из кэша
}


Аргументами функции, то есть и ключами в кэше могут быть не только примитивы, но и объекты, за счёт того, что ключ формируется с помощью JSON.stringify.

Таким образом, с помощью Proxy можно на коленке собрать «мидлвари» для объектов, массивов и функций, в общем-то, с любыми целями.
👍9🔥7
#Пульс_веб_платформы 12.01.2024

Новости
- вышел Vue 3.4: переписан парсер шаблонов на htmlparser2 (стало 2x быстрее), улучшена система реактивности и добавлен шортхэнд для дублирующих значений атрибутов (<img :id="id" :src="src" :alt="alt"> 👉 <img :id :src :alt>)
- круг замкнулся: в Remix появится классический SPA-режим работы, с возможностью опционально включить SSR (сейчас в Remix приложениях вся загрузка данных происходит на сервере)
- в Chrome начали выпиливать сторонние (3-party) куки (у 1% пользователей)
- в React появятся API для прелоадинга ресурсов: preload, preconnect и другие

Проекты
- PWA-приложение, показывающее все возможности PWA-приложений
- zed — быстрый мультиплеерный редактор кода (почему, зачем, за что?)
- fontsource — опенсорсные шрифты в npm-пакете (для установки шрифтов как контроллируемых зависимостей вместо гугл-фонтс)
- fsx — либа для работы с файловой системой в ноде, дено и памяти (в том числе браузерах) от создателя eslint

Статьи и демки

JS
- напоминание, что во всех браузерах доступны немутирующие аналоги reverse(), splice(), sort() – toReversed(), toSplice(), toSorted() и with()
- в JS-движке JavaScriptCore (в Safari), в отличие от V8 (в Chrome) реализован механизм оптимизации хвостовой рекурсии (Tail Call Optimization), позволяющий вызывать рекурсивно функцию сколько угодно раз без переполнения стека и код можно сделать таким же быстрым, как и в цикле for
- разбор классических «странностей JS»: 0.2 + 0.1 = 0.300000001., преобразование типов, автодобавление ;
- история, как создали npm-пакет everything, который включает ВСЕ пакеты npm, включая себя; из-за политики, что нельзя снять с публикации пакет, от которого зависит любой другой пакет, стало невозможно убрать из npm ВСЕ пакеты
- туториал по стейт-менеджеру Jotai, состоящему из атомов
- в Next.js теперь можно будет запускать проект на https локально с помощью next dev --experimental-https
- здравый смысл восторжествовал и в Next.js не будут больше патчить fetch
- document.getAnimations() возвращает в виде промисов все текущие CSS-анимации
- анатомия shadcn/ui: безголовые компоненты с отдельным слоем стилей, для установки разных состояний используется cva
- гайд по микрофронтендам на single-spa: такие штуки кажутся с первого взгляда сложными, но стоит попасть в ситуацию больших проектов, когда нужно шарить данные между разными приложениями, и уже становится понятно, зачем вся эта сложность
- чтоб не заморачиваться с выводом типа события TS в React, можно воспользоваться общим «доставатором» типа React.ComponentProps<"input">["onChange"]
- особенности использования enum в TS: например, const enum Name {} полностью удалит этот фрагмент из скомпилированного кода, но есть нюансы

CSS
- гайд по container queries (с живыми примерами)
- как написать круглый индикатор прогресса со скролл-анимацией
- в Chome 120 появилось @media (noscripting: none) для определения выключенных скриптов
- директива @property: создание, дебаг, юзкейсы
- кликабельную область вокруг интерактивных элементов лучше увеличить (удобно для мобилок), как это лучше сделать
- трюки и находки при создании нового сайта vercel: SVG-лучи, пиксельные логотипы на гридах, CSS-счётчики, круговая анимация

HTML, SVG
- топ-10 ошибок в доступности на сайтах в 2023: пустые ссылки, некорректный tabindex, отсутствие alt и другое

Платформа
- победители в народном голосовании за фичи в Interop 2024: JPEG XL image format, View Transitions Level 1, Scroll-driven Animations
9🔥5👍3
#Фикшн_веб_платформы

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

А Настоящее Айкидо — оно было совсем другое. Оно заключалось в том, чтобы победить Неприятеля так, чтобы самому не сильно напрягаться. Для этого даже не обязательно с этим Неприятелем встречаться.


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

Приходит вам в голову мысль, как реализовать эту фичу с помощью Костылей. «Что поделать, инженерия — она такая», — думаете вы и берётесь за работу. В процессе к одному Костылю приходится прилепить ещё парочку и скрепить это для прочности подручными материалами. В общем, вы по ходу встречаете всё большие сложности и затем героически с ними боретесь. Получившееся решение громоздкое, хрупкое, но время на него уже потрачено, выкинуть жалко, да и в целом оно работает (почти всегда), так что что уж тут, оставляем.

Вроде бы вы и победили, но гаденько как-то, нет этого приятного ощущения, ради которого вы когда-то давно вообще этим всем начали заниматься. Это не Настоящее Айкидо.

Либо же вы ищете похожую задачу на Стэковерфлоу или спрашиваете у Чат-бота. И таким образом вы находите «Либу, которая решит все ваши проблемы». Правда помимо вашей задачи она решает ещё и парочку других проблем по пути, ну и тянет набор зависимостей на 500кб. Но это ладно, думаете вы, фичу-то надо сделать ещё вчера. «Ок, для временного решения сойдёт», — решаете вы и используете либу.

А потом, спустя год-другой нужно вам зависимости проекта обновить и вы находите эту либу, вспоминаете что к чему, хотите версию этой либы заодно поднять. Но либа уже заброшена владельцем и вообще новым Реактом не поддерживается. «Что поделать, надо выпиливать», — думаете вы и снова оказываетесь в самом начале.

Это не победа, Неприятель вас обхитрил, притворился побеждённым и вам снова нужно с ним сражаться. Это тоже не путь Настоящего Айкидо.

А как бы поступил Мастер Настоящего Айкидо? Он бы сел, подумал и вспомнил, что Браузер, для которого он пишет программу, уже и сам умеет в нужную фичу. И вот Мастер на митинге скажет «Это умеет Платформа», а потом возьмёт и напишет несколько строк кода, чтобы дёрнуть нужный браузерный API, закроет задачу и пойдёт пить чай. И его решение никогда не протухнет, ведь Платформа всегда обратно совместима.

Мастер Настоящего Айкидо прилагает большего всего сил, чтобы освоить базу, и затем стремится к применению усвоенных принципов. А когда ему приходит мысль, что ему всё ясно, то он говорит себе: «Этого недостаточно», и идёт дальше копать Базу. 🥷
👍7🔥7🤡4😐21🤔1
#Пульс_веб_платформы 19.01.2024

Новости
- в Safari TP 186 допиливают @scope, добавили align-content для табличных ячеек и сделали анимируемым свойство content-visibility
- обновилась Node v20.11.0 (LTS): появились esm import.meta.dirname и import.meta.filename на замену CommonJS __filename и __dirname
- вышел Prettier 3.2: поддержан формат файлов jsonc (если вы, также как и я не знали, что это такое, — это творение Microsoft, json с комментами // и /**/)
- вышел Next.js 14.1 — ускорен стартап и Turbopack, улучшен вывод ошибок, добавлена поддержка нативных window.history.pushState и window.history.replaceState, логирование использования кэша, расширены возможности работы с картинками
- в TS 5.4 появится новый тип NoInfer<T>, чтобы блокировать инфер пришедшего типа

Проекты
- The AHA Stack — всем панкрок! или Astro, htmx и Alpine.js объединились в банду, шатают SPA-мир и хотят вернуть веб-разработке простые ментальные модели и воркфлоу (интересно, доколе ещё ждать наступления прекрасного будущего?!)
- remote-storage — localStorage с сохранением на удалённый сервер (даже бесплатный, чтобы вы туда насохраняли инфы, а потом душили жабку за подписку, которая вскоре появится)
- templ — серверный рендеринг HTML на Go (внутри можно редерить и React-компоненты)
- worker-timers — таймеры, которые не фризятся при неактивном окне за счёт выноса в worker
- dep-tree — 3d визуализация внутренних связей проекта
- symbiotejs — а что если вы завтра проснётесь и React окажется дурным сном, а все приложения вокруг будут написаны близко к нативным API, без прятания за абстракциями и «магических ящиков»

Статьи и демки

JS
- новомодные написанные на Rust линтеры (oxlint, biome…) быстры в том числе потому, что не интегрированы с TS type checking API, которое, увы, довольно медленное, но зато фичёвое
- ещё одно напоминание, что в Google Chrome во второй половине 2024 будут отключены сторонние (3d-party) куки, что поломает Google же Analytics, Google Pixel, инструменты ретаргетинга…, но в целом останутся ещё другие безкукисовые инструменты, чтобы показать вам баннер с рекламой кредитной карты — опыт команды Sentry
- React Server Components не требует наличия сервера или Анонс курса Дэна Абрамова «Нейминг от бога» (а Astro, кстати, требует)
- с помощью Clipboad API можно копипастить не только текст, но и картинки в PNG, гайд как это сделать на React
- как с помощью современных JS-рантаймов (bun, deno, node) собрать самодостаточный выполняемый файл
- золотое правило написания тестов: «Тест должен не проходить, тогда и только тогда, когда цель системы не выполнена.», то есть в тесте не стоит вдаваться в детали имплементации, а сфокусировать один тест только на одной цели
- сравнение либ типизированной проверки данных: Zod vs Valibot
- querySelector отличается от getElementById тем, что не признаёт id начинающиеся с цифры

CSS
- набор молодого интернационалиста: margin-inline, dir, :lang() и writing-mode
- на что способно свойство border-image: полупрозрачный фейд, скошенный фон на весь экран, градиентные бордеры
- ещё один способ центровки контента без обёртки — max-width: max-content; margin-inline: auto
- юзкейсы скролл-анимации с помощью animation-timeline (пока только в Chrome)
- способы описания кастомных easing-функций в JS для Web Animations API: предвычисление массива keyframes, новая функция linear(), а также предложение добавить встроенную функцию document.registerTimingFunction

HTML
- чтобы убрать элемент от показа в описании сайта в гугл-поиске нужно добавить тегу атрибут data-nosnippet

Платформа
- прошедший год у npm: 184 миллиарда скачиваний пакетов в месяц; март самый активный месяц по публикации версий пакетов; топ зависимостей — TS, react, eslint, @types/node, react-dom, jest, prettier; самое длинное возможное название пакета из 214 символов
- как выводить в консоль браузера анимированные 3D-SVG картинки и стилизованный текст, а также бонусом либа для определения открытости консоли и факт, что console.table(['foo']) растягивается на всю ширину консоли
🔥4👍21👏1
#Лаборатория_веб_платформы

Окей, когда что-то нужно перестроить в интерфейсе при изменении разрешения экрана, используется media query в CSS.

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

Первая мысль, как поступить в этой ситуации — подписаться на resize окна и смотреть в хендлере, нужная сейчас ширина окна или нет.



function handleResize() {
if (window.innerWidth >= width) {
// setIsGreaterThanOrEqual whatever
}
}

window.addEventListener('resize', handleResize);


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

Триггерить только срабатывание определённого условия ширины можно… теми же mediaQuery, только в JS. Для этого существет API window.matchMedia https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia, который принимает строку с медиавыражением и возвращает объект MediaQueryList, содержащий информацию о медиавыражении, применённом к документу.



const matchQueryList = window.matchMedia("(max-width: 600px)")


Для разовой проверки соответствия используется свойство matches:



matchQueryList.matches // true or false


А для постоянного отслеживания соответствия, есть подписка на событие change:



function handleChange(e) {
// e.matches whatever
}

matchQueryList.addEventListener("change", handleChange)


Для Реакта всё это заворачивается в хук и получается удобное отслеживание медиавыражений в JS:



function App() {
const isMobile = useMatchMedia("(max-width: 768px)");

return <h1>Browsing with {isMobile ? "mobile" : "desktop"}</h1>;
}


Код тут https://codesandbox.io/p/devbox/frosty-mcclintock-93ghzg
🔥11👍8
#Пульс_веб_платформы 26.01.2024

Новости
- состоялось заседание рабочей группы по веб-компонентам W3C, результаты: Declarative Shadow DOM появится в Firefox 123 в конце февраля (эта фича, позволяющая использовать Shadow DOM напрямую в HTML без вызова attachShadow() из JS); начнёт разрабатываться Scoped Element Registries, позволяющий создавать элементы с одинаковым именем в рамках одной страницы; Container Style Queries быть во всех движках в ближайшем будущем 🎉
- грядущие нововведения в «клиентском» Реакте: use(Promise) — саспендинг на клиенте; use(Context) — такой же, как useContext, но можно вызывать в условиях; хуки и апи для работы с формами Form Actions, useFormState, useFormStatus; а также useOptimistic — специальный хук, чтобы смотреть на «классический» Реакт с оптимизмом
- обновления в Chrome 121: появились свойства scrollbar-color и scrollbar-width (раньше работало только в FF, так что если у вас были стили только для FF в Хроме тоже внезапно включится!); font-palette для управления цветовыми шрифтами; псевдоэлементы ::spelling-error и ::grammar-error для стилизации ошибок; Speculation Rules API для программного префетча и пререндера страниц в классических MPA; showPicker() для программного выпадения <select> (кажется, я когда-то ждал этого, но так давно, что уже забыл)
- вышел Safari 17.3: пофикшен @supports и цвет каретки на iOS, закольцовывание медиа с нулевой длиной и другие мелочи

Проекты
- bun shell — возможность запускать shell-скрипты в JS (с помощью и во славу Bun)
- workerpool — централизованный способ выгрузить воркеры (если у вас их много разных) в отдельный пул с очередью выполнения
- partytown — запуск 3d-party скриптов в воркере (для выгрузки Google Tag Manager, Google Analytics, Amplitude из основного потока)

Статьи и демки

JS
- как отделить 0 от null и undefined: напоминание про разницу операторов || и ??
- c AbortController.abort() удаляет разом несколько обработчиков событий (не нужно писать множество removeListener, yay!)
- если вы захотите обновиться на 18 Реакт, возможно вам тоже придётся сделать что-то из того, что уже сделали в команде SonarQube
- Реакт-стартеры в 2024: Vite, Next или Astro?
- возможная замена проп-дриллингу — {children}
- туториал по Next.js App Router от мейнтейнера Node.js и webpack: минималистично и интерактивно
- как уменьшить размер бандла — рецепты с разных сторон: мониторинг через Lighhouse, Sentry; анализ с помощью Webpack Bundle Analyzer, Statoscope, bundlephobia; распространённые приёмы — отключить сорсмапы, оптимизировать импорты библиотек типа lodash, выделение чанков, динамические импорты и фреймворкоспецифичные подходы типа React.lazy

CSS
- частичный фейд текста с помощью градиентов (именно текста, а не покрывающий слой!): способы с mask-image и background-clip: text
- сборник мелких, точных (и злых) «CSS-однострочников», которые уже можно заносить в проекты (и за это не придётся оправдываться): aspect-ratio, object-fit, margin-inline, text-underline-offset…
- ещё одна подборка юзкесов селектора :has(): делаем выборку родителя, предыдущего сиблинга, по количеству элементов, в любом месте или всё, кроме меня
- в догонку к предыдущему пункту демка с плавным переходом между радио-кнопками, которая стала возможна в CSS благодаря :has()
- в 123 Chrome появится свойство field-sizing, авторасширяющее инпуты и текстареа при вводе длинного текста (неужели это когда-нибудь свершится, боже)

HTML,
SVG
- эффект движущейся линии по скроллу на SVG элементах <linearGradient>, <path> и <clip-path>
- чтобы улучшить метрику CLS достаточно просто один раз в день… задавать размеры <img> в атрибутах width и height (и без px)
- aria-hidden в жизни: для сокрытия визуальных декоративных элементов, скрывает интерактивные элементы не всегда, aria-hidden !== aria-hidden="true"

Платформа
- рецепты как выключить браузерное кеширование в серверных заголовках, HTML, htaccess, PHP и других бэкендах
- каталог известных (и не очень) дизайн-систем на случай, если вам понадобится впечатлить коллег проведённым обширным ресёрчем
🔥83
#Лаборатория_веб_платформы

Веб-платформа регламентирована как backwards и forwards совместимая.

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

Работает это так. Вам вдруг приходит задача, что что-то поломалось в коде. Причём в старом коде, который уже давно не менялся и был написан прото-программистами, которые уже давно уволились. Казалось бы, что может пойти не так? А дело в том, что сами браузеры обновляются и в них что-то вдруг начинает работать по-другому. В том числе код, который вам предстоит исправить. Самые «любимые» баги.

Как это такое происходит, ведь платформа должна быть обратно совместима? Главным образом так: далеко не всегда сначала появляются стандарты, а потом браузеры пилят фичи по этим каноническим стандартам. Иногда фичи просто пропушиваются вендорами (яркий пример — префиксы -webkit-feature, -moz-feature), а потом уже под них подгоняются стандарты или же они адоптятся стандартами и… всё это обратной волной докатывается до браузеров. Браузеры немного меняют имплементацию и ваш код, который просто работал, становится как бы сломанным.

Что поделать, ваш код признан устаревшим и приговаривается к утилизации, приговор обжалованию не подлежит!

Но ок, вендорные префиксы были всеми явно признаны как фейл. Есть и более прозаические примеры.

Есть такой метод play() у аудио и видео HTML-элементов. Он появился ещё в Chrome 3. Он просто работал и включал медиа. То есть можно было запустить, например, видео и тут же его поставить на паузу, чтобы оно сразу прогрузилось.


<noscript>
  video.play();
  video.pause();
</noscript>


Потом в Chrome 32 появились Promise. Затем обновились стандарты. И уже в Chrome 50 метод play() стал возвращать промис вместо того, чтобы синхронно выполнить запуск медиа. То есть ваш код сломался и выдаёт эксепшн, который даже даёт ссылку на специальную страничку https://developer.chrome.com/blog/play-request-was-interrupted.

Ещё один пример, немного с другого бока подсвечивает эту же проблему. Люди издревле желали стилизовать скроллбары. Поэтому в Chrome появился целое семейство свойств для стилизации (::-webkit-scrollbar, ::-webkit-scrollbar-track…), в которых можно было задавать ширину или высоту скроллабара (в пикселях!), его цвет фона. Потом это дело ушло вариться в стандарты, ранние черновики были реализованы в Firefox: это были свойства scrollbar-width и scrollbar-color. Причём в scrollbar-width уже нельзя было задавать значения в пикселях (только thin или auto), а scrollbar-color принимал два цвета через пробел (для фонового цвета трека и «таскалки»). И вот так оно и жило где-то с 64 версии FF до наших дней: для стилизации в FF использовался «правильный» вариант с scrollbar-width/scrollbar-color, а в Chrome работали вендорные префиксы.

Что же могло пойти не так? В Chrome 121 завезли (https://developer.chrome.com/docs/css-ui/scrollbar-styling) так же стандартные scrollbar-width и scrollbar-color! И ваш код, хоть и не упал, но начал работать по-другому, так как скроллбары стали другими, и хорошо, если просто стали другими. В целом не то чтобы критично. Но возможно сегодня где-то в далёком офисе одинокий разработчик сдувает пыль с давнего проекта и добавляет хак, чтобы всё оставалось как раньше, и в Chrome по-прежнему применялась только стилизация через вендорные префиксы:


@media screen and (min--moz-device-pixel-ratio:0) {
.scrollable_styled {
scrollbar-width: thin;
scrollbar-color: gray transparent;
}
}

.scrollable_styled::-webkit-scrollbar {
width: 8px;
}

.scrollable_content::-webkit-scrollbar-thumb {
background-color: gray;
}


Directed by robert b weide 🥁

А для тех, кто дочитал до конца, приятный бонус: список задепрекейченых и выпиленных платформенных API: JS, HTML, CSS.
👍10🔥3
#Пульс_веб_платформы 02.02.2024

Новости
- в React 19 появятся нативные custom elements (мама, неужели они решили задепрекейтить jsx?!)
- что в последнее время появилось нового в браузерах: <hr> в <select>, HTMLSelectElement.showPicker, стилизация скроллбаров, анимация font-palette, transfer() и transferToFixedLength() у ArrayBuffer
- анонсирован Typenoscript 5.4 beta: улучшение сужениях типов в замыканиях, новый утилитарный тип NoInfer для запрета вывода типов, Object.groupBy и Map.groupBy, улучшение quick-fix, а также анонс грядущих депрекетов в TypeScript 5.0
- минорно обновлены версии Node 18, 20, 21 для фиксов безопасности
- в V8 v9.1 выпущена поддержка import assertions (это такое import json from './foo.json' with { type: 'json' }, для того, чтобы не запустить зловредное ПО, маскирующееся под JSON)

Проекты
- expressive-code — решение для интеграции блоков кода в контенте сайта (для astro, next)
- unlazy — универсальная либа для ленивой загрузки картинок (с плейсхолдерами)
- веб-компонент авторастягивающейся textarea
- анимация прыгающего мяча кучей возможных способов (без JS, на чистом JS, с либами, на canvas, видео и гифка)
- type-coverage — мониторинг и зачистка (от any) типов в проекте

Статьи и демки

JS
- мнение, что вся React-движуха завела часть индустрии не туда, отзывается: неестественный для браузера DX, в который двигаются React, Next и иже с ними, оказывают медвежью услугу (и, конечно, зарабатывают на этом), и, в целом, во многих случаях не нужны, так как являются легаси из 2013, когда в
браузерах не было шаблонных строк и BFCache
- ещё одно мнение, что система, которая вынуждает переписывать кодовую базу каждые 2-3 года — слабая, и напоминание о «правиле минимальной мощности», когда для решения задачи следует выбирать минимально необходимый по мощности язык/технологию
- не поверите, ещё одно мнение о том, что стоит попробовать Qwik вместо React (по мне так шило на мыло, нужны другие ментальные модели для написания кода для платформы)
- сначала придумывается SSR, потом решается, как же быть, когда нужно узнать что-то из клиентского браузера, а потом придумываются костыли — надёжный план!
- попытки замерять Core Web Vitals не только на первой загрузке SPA, но и на последующей клиентской навигации — спец событие soft navigation для PerformanceObserver
- pnpm поддерживает страницу с бенчмарками npm, pnpm, yarn (они поддерживают страницу, потому что pnpm быстрый или следят за быстротой pnpm из-за поддержки страницы 🤔)
- современный стартер для либы: TS, тесты нативные node:test, билд npm-скриптами, конфиг для CI на GitHub Actions в yml, автодеплой в npm, provenance и секреты
- event loop – мифы и реальность: браузерные и небраузерные среды исполнения, почему понятия нет в спеке ECMA-262, макротасков не бывает, а task queue это не очередь, а set
- улучшаем качество кода React-приложения с помощью Compound Components

CSS
- блюрная backdrop-тень с помощью mask, backdrop-filter и box-shadow
- если вы всё ещё убираете обводку (outline: 0), то это можно уже не делать, так как есть :focus-visible
- попытка объять необъятное шрифтовые единицы измерения длины: cap, ch, em, ex, ic, lh, а также из «рутовые» аналоги rem, rlh, rex, rch, ric и другая магия
- выделение текста с помощью скролл-анимации: animation-timeline и background-size
- строим тоггл: с :has(), адаптивно, доступно, с «ручками» для кастомизации стилей
- анимация цветовых шрифтов font-palette (жаль, что самих шрифтов мало)
- анимация движения по линии в SVG с offset-path и offset-distance
- свежий взгляд на старую как мир стилизацию <table>

HTML, SVG
- про тег <abbr> и атрибут noscript: лучше не использовать и с noscript, и без него
- плохие стороны HTML: лучше НЕ использовать <select multiple>, атрибут noscript, <datalist>, <input type=number>, <input type=date>, <menu> во избежание проблем

Платформа
- базовые различия jwt и session-вариантов аутентификации: jwt более модное, но сложнее в реализации, сессия попроще и понадёжнее
- что намечается в рамках Interop 2024: хотеть custom properties, declarative shadow DOM, relative color syntax, @starting-style
🔥12👍32
Недавно мы с Александром, автором канала «Frontend Everyday» , решили подискутировать на тему «Отберёт ли ИИ работу у разработчиков».

По моему мнению, в обозримом будущем работа разработчиков существенно изменится.

Недавно мне попался рейтинг профессий Job Impact Index, в котором показано на сколько % сейчас та или иная работа затронута ИИ. Так вот, 70% условных задач frontend-разработчика уже сейчас автоматизируется и может быть делегирована (выполнена с помощью) ИИ.

Что же там в оставшихся 30% задач? Кастомизация и нешаблонные вещи, высокоуровневые задачи, которые сложно сформулировать, или которые находятся в контексте больших существующих систем, работа на стыках нескольких систем, проприетарщина и тд.

Но главное, что входит в эти 30% — это ответственность, которую человек берет на себя за результат.

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

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

То есть ИИ неминуемо, прямо или косвенно, в обозримом будущем уменьшает численность команд разработки, лишает многих из нас работы. Это уже происходит прямо сейчас в бигтехах, которые оптимизируют процессы и штат, со временем раскатится и на всех остальных. Бизнесы в основном устроены так, что если можно где-то срезать, то так это и делается, либо вас обходят соптимизированные конкуренты.

И мы оказываемся в ситуации, когда люди с определенным опытом, которые могут брать на себя ответственность за крупные задачи и системы (условно «сеньоры»), востребованы и их зарплата продолжает расти. В то же время начинающие разработчики, которые с ходу большую ответственность не могут потянуть (условно «джуны») теряют: во-первых, в деньгах, так как вдобавок растёт конкуренция среди других джунов, а во-вторых, в возможности вообще куда-то устроиться на работу, так как работу делают сеньоры и их дрессированные роботы.

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

Это может производиться либо с помощью классического прикрепления 1-1 джуна к сеньору (подмастерье <-> мастер), чтобы в максимально синхронном режиме вкатываться в рабочий процесс. Либо, если нужны промышленные масштабы, в некой симулирующей среде (тренажёре, симуляторе, инкубаторе, акселераторе…) джун на решении смоделированных задач ускоренно прокачивается и набирает нужное число часов «налёта» перед выходом в «реальный мир». Возможно даже и одно, и другое по очереди: симулятор -> парная работа.

Такие дела.

А теперь время пойти почитать, что скажет Александр в @front_everyday и решить, кто же из нас двоих прав. 😊
🔥6
#Пульс_веб_платформы 09.02.2024

Новости
- вышел Million 3 (кастомный компилятор для React): авторы обещают, что просто выполнив npx million@latest можно добиться ускорения работы Реакта с O(n) до O(1)
- вышла jQuery 4.0.0 BETA: без шуток внушительный чейнджлог, в который разве что не влез отказ от IE11
- вышел Vite 5.1: появился экспериментальный режим Vite Runtime API, позволяющий сделать прослойку между сервером и рантаймом и делать там что-то своё, такая мидлваря, но мощная, и отвязанная от сервера; поддержка запуска CSS-препроцессоров в отдельных потоках (перф улушается); более быстрый холодный старт; улучшенная поддержка .css?url и другие фишки
- вышел биндинг GSAP для React @gsap/react, включает удобный хук useGASP()
- вышел Remix v2.6.0, который однажды утром проснулся и обнаружил, что он превратился в Vite-плагин

Проекты
- drab — коллекция headless кастомных элементов (для расширения кругозора, что кастомные элементы можно использовать как обёртку как для ui-элемента, так и для процесса, например, prefetch)
- noscriptfm — визуальный конструктор SVG-фильтров, позволяющий собирать фильтры в цепочки (написано на JS!)
- baklava — приятная дизайн-система и ui на нативных веб-компонентах без примудростей
- replay — «проигрывание» действий в интерфейсе puppetier-ом с помощью Chrome DevTools Recorder (попробуйте, это вкладка есть в девтулзах Хрома)
- knip — либа для нахождения неиспользуемых файлов, зависимостей и экспортов в проекте
- simple-git-hooks — суперлайтовые и простые гит-хуки, если не нужно сложности и нужна быстрота и простота
- npmgraph — визуальное отображение зависимостей проекта в виде интерактивного графа

Статьи и демки

JS
- типобезопасные id в TS с помощью template literal types (`node_${string}`): в комментариях приводят более общее решение через branded types
- как Deno изменился за 2023 год, а также кое-что под названием JSR (JavaScript Registry), «смутно напоминающий npm», но с нативной интеграция TS и ESM-only пакетами, автоматически генерируемой документацией
- стата о самом востребованном JS-фреймворке: конечно, это React по количеству вакансий; в Бельгии больше всего востребован Vue, а в Швейцарии — Ангуляр (интересно, а отсутствие JS-фреймворка это хоть сколько-нибудь востребовано?)
- оказывается есть не только <input type="color"> (везде), но и цветовой пикер new EyeDropper() (в Хроме)
- очередной герой самоотверженно бросается в пучину настройки фронтовой монорепы и выясняет, что для него лучшим оказалось сочетание инструментов Turborepo + pnpm
- бестпрактисы и юзкейсы переменных окружения .env: можно задавать при запуске ноды, в .env-файлах можно задавать фича-тогглы, переменные для разных окружений и хранить секреты
- попытка ещё раз взять и запомнить различия между типами ReactElement, ReactChild и ReactNode
- когда может пригодиться as never в TS (спойлер: в этом кейсе не поможет даже as any!)
- шоукейс про микрофронты от команды Dodo: в 1 и 2 рассказано, как переходили на SingleSPA + SystemJS, а заодно и на Vite и Vitest
- а может и не нужны эти ваши микрофронты и достаточно ограничиться npm modules или даже git submodules?
- организация кэша в JS с помощью Cache Storage API и его преимущества перед local storage и indexed db

CSS
- юзкейсы all: revert-layer: более лайтовый ресет, чем all: revert, точечное восстановление ранее сброшенных значений, а также антихрупкие дефолты для переменных var(--size, revert-layer)
- градиентная рамка с помощью linear-gradient и mask
- боковая шторка на <dialog> (не обошлось без заворачивания в веб-компонент)
- CSS-анимация SVG-элементов и тонкости настройки transform-box и transform-origin

HTML, SVG
- пятёрка атрибутов, улучшающих UX: hreflang, translate, reversed, controls и autocomplete (в порядке возрастания полезности)

Платформа
- история о том, как веб нарушил конвенцию квадратных чекбоксов и круглых радиокнопок
- дзен и искусство ухода за маком в 2024: чеклист от и до
- кто такой и зачем нужен CORS с бонусным списком как не нужно его обходить (принимать всё отовсюду, выключать preflight checks плагинами в браузере и устанавливать mode в no-cors)
👍11🔥1😐1
Чему равно сравнение 0X0 === 0B0
Anonymous Quiz
44%
true
39%
false
17%
Error
Объяснение 👇

В JS можно записывать числа помимо десятичного формата в двоичном, 8-ричном и 16-ричном. Для этого нужно начать число с 0, а дальше:

- поставить B, а после него записать двоичное число, например, 0b10 === 2
- поставить O, а после него записать 8-ричное число, например, 0o10 === 8
- поставить X, а после него записать 16-ричное число, например, 0x10 === 16

0x0 — это 0 в 16-ричном формате, а 0B0 — это тоже ноль, но в двоичном формате. Но ноль любом формате — это всё тот же ноль, поэтому они равны между собой.

Завтра будет пост с одним интересным юзкейсом чисел в двоичном формате в JS 🛠️
👍8🔥2
#Лаборатория_веб_платформы

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


// все три слота свободны
000

// первый слот занят, остальные свободны
100

// первый и третий слоты заняты, второй свободен
101


Ок, идём дальше. То, что состояния теперь заданы в виде двоичных чисел, даёт возможность применять к ним двоичные операции! Например, это могут быть двоичные И и ИЛИ. Обозначаются они операторами & и |. Двоичные числа сравниваются побитово (первый бит одного числа с первым битом другого, второй бит одного числа со вторым битом другого…).

В случае логического И оба бита должны быть равными 1, чтобы в результате получить 1, в остальных случаях будет 0:


0 & 0 === 0
0 & 1 === 0
1 & 0 === 0
1 & 1 === 1


В случае логического ИЛИ любой из битов может быть равен 1, чтобы получить в результате 1:


0 | 0 === 0
0 | 1 === 1
1 | 0 === 1
1 | 1 === 1


И теперь, если вернуться к примеру со слотами, мы можем «складывать» два состояния с помощью побитового ИЛИ: 100 | 001 === 101 (первый занятый слот ИЛИ третий занятый слот — это занятые 1 и 3 слот). А из «суммы» двух состояний можно убрать все состояния, кроме определённого, с помощью побитового И: 101 & 100 === 100 (первый с третьим занятые слоты И первый занятый слот — это первый занятый слот).

Теперь к юзкейсу. Вся мякотка маппинга состояний на битовые карты раскрывается в кейсе, когда побитовое ИЛИ используется для создания композиции нескольких отдельных состояний. Представьте, что у нас есть некие состояния:


const MOBILE = 0b0001;
const TABLET = 0b0010;
const LAPTOP = 0b0100;
const DESKTOP = 0b1000;


Можно использовать как просто отдельное состояние, например, MOBILE, так и композицию нескольких состояний, к примеру, MOBILE | LAPTOP (что буквально так и считывается мобайл ИЛИ лаптоп, спасибо TS👋).

Это можно использовать для задания динамических ключей объектов:


const objectMap = {
[MOBILE]: "mobile stuff",
[LAPTOP]: "laptop stuff",
[MOBILE | LAPTOP]: "mobile or laptop stuff",
};


Как вы уже, возможно, догадались, распаковать этот ключ можно с помощью логического И (&), обратной операции. Предположим, что нужно отфильтровать только те ключи, в которых есть MOBILE, то есть нужно ко всем ключам применить & MOBILE:


MOBILE & MOBILE === MOBILE
// у 0b0001 и 0b0001 есть общая 1, получаем 0b0001

LAPTOP & MOBILE === 0
// у 0b0100 и 0b0001 нет общей 1, получаем 0b0000

(MOBILE | LAPTOP) & MOBILE === MOBILE
// у 0b0101 и 0b0001 есть общая 1, получаем 0b0001


Дальше отфильтровываем те значения, ключи которых выдали нули и готово!

Вот как выглядит функция-фильтровщик:


function getFilteredValues(objectMap, filterKey) {
return Object.entries(objectMap)
.map(([key, value]) => {
const shouldInclude =
(key & MOBILE) === filterKey ||
(key & TABLET) === filterKey ||
(key & LAPTOP) === filterKey ||
(key & DESKTOP) === filterKey;
return shouldInclude ? value : null;
})
.filter(Boolean);
}


Код https://codepen.io/juwain/pen/KKEGRrB?editors=0011

Кстати, небольшой оффтоп: обратите внимание на ссылку. Codepen тоже использует битовую карту, чтобы обозначить, какие редакторы по умолчанию скрыть (0), а какие показать (1) 👾

Я использовал такой подход для динамического создания стилей для каждого типа девайса. Иногда стили для соседних девайсов повторялись, не хотелось их дублировать и получилось сгруппировать по типу MOBILE | LAPTOP.

Пример (это Styled Components):


${setResponsiveStyles({
[MOBILE]: css`
// some only mobile styles
`,
[MOBILE | TABLET]: css`
// some mobile or tablet styles
`,
[LAPTOP]: css`
// some only laptop styles
`,
[DESKTOP]: css`
// some only desktop styles
`
})}
🔥8👍5
#Пульс_веб_платформы 16.02.2024

Новости
- вышел Safari TP 188: добавлена поддержка альтернативного синтаксиса свойства content, поддержка supports внутри директивы @import, выпилена поддержка нестандартного resize: auto и много всего мелкого пофикшено
- из-за противостояния бюрократии и бигтехов в iOS в Европе перестанут работать PWA, как работают сейчас (по сути останется возможность только создать «закладку» со ссылкой 🤷‍♂️)
- мейнтейнер Express решил взбодрить проект и запостил планы на 5, 6 и 7 версии (которые подозрительно напоминают план начать с нового года жизнь заново): больше координации с LST-версиями Ноды, меньше манкипатчинга и использования внутрянок Ноды, официально поддерживаемые типы

Проекты
- hono — серверный фреймворк для все JS-рантаймов: недавно вышла версия 4, которая во времена Реакта, идущего на сервер, наоборот стала уметь в SSG, клиентские компоненты (c jsx и реактовскими хуками), file-based роутингом и другими плюшками. Безусловно, радует что не next-ом единым!
- glaze — если вдруг вам нравится tailwind-подход к написанию стилей, этой либой можно так же «декларативно» описывать GSAP-анимации
- tabgod — запуск JS-скрипта одновременно в нескольких табах сразу (для гугления сразу в нескольких гуглах, например)
- react-joyride — либа для создания туториалов и онбордингов по сервису
- type-fest — набор базовых утилитарных дженерик-типов TS (автор разрешил копипастить код без импорта либы 😊)
- tempo — yet another библиотека для работы с датами от команды Formkit

Статьи и демки

JS
- иногда сидишь, думаешь, как пробросить что-то из состояния в DOM или наоборот, и тут, хоба!, можно же пробросить значение в кастомном свойстве!
- подход к рефакторингу кода, который оброс множественными ветками условий или кейсов: найти общий паттерн, выделить его в интерфейс и причесать ветки кода так, чтобы каждая имплементировала выделенный интерфейс
- как хэндлить события за пределами компонента в Реакте, из которого я узнал в том числе о нативном методе event.composedPath(), выдающие массив всех таргетов, через которых пройдёт событие при всплытии
- дружеское напоминание, что Array.prototype.with работает везде и может «заменять» элементы массива немутабельно
- новые методы Set.prototype.union, Set.prototype.intersection, Set.prototype.difference и другие (похожие на SQL) методы доступны в Chrome 122+ и Safari 17+

CSS
- объёмный (я бы даже сказал) справочник по цветовым пространствам, функциям в CSS от базовых до современных от гугловцев: color(), display-p3, oklch, градиенты, проверка фич в supports()
- пока мы тут работу работаем, в CSS тихо варятся нативные mixin-ы и функции
- новые функции возведения в степень pow(), квадратный корень sqrt() и другая математика (даже есть примеры!)
- задание диапазона жирности насыщенности шрифта с font-weight для вариативных шрифтов
- как побороть поведение iOS, когда неправильно определяется цвет скроллбара, и он оказывается белым на белом фоне
- на три вещи можно смотреть вечно: на огонь, воду и центровку блоков в CSS — современное прочтение без transform: translate(-50%)
- если нужно вставить SVG фоном, можно встроить его прямо в CSS, и оказывается, можно даже не энкодить его в base64

HTML, SVG
- ещё одно дружеское напоминание, что элемент <dialog>: 1) поддерживается везде и 2) из коробки имеет центровку, оверлей, закрывается по esc, а также ловит фокус и возвращает его при закрытии
- дизейблить кнопки ок, но не совсем ок дизейблить элементы форм (особенно кнопки, тк это ридонли-элементы)

Платформа
- ежегодное обновление поста Андрея Ситника о том, как подключать favicon (кажется, с каждым годом он всё короче и когда-нибудь схлопнется до 1 строки)
- никогда не будет лишним вспомнить или узнать хитрости по работе с гитом: config, blame, diff, rerere (не путать с ололо)
🔥6