Dev News от Максима Соснова
2.78K subscribers
15 photos
1.25K links
Привет! Меня зовут Максим Соснов и по утрам я читаю всякие разные дайджесты про фронтенд, разработку и управление разработкой. Самые интересные, по моему мнению, ссылки из этих дайджестов я кидаю в этот канал с небольшим описанием.

Контакт: @msosnov
Download Telegram
Node.js Testing Best Practices

Репозиторий с 50+ бест практисами тестирования в Node.js. Как обычно - часть пунктов странные, часть очевидные, часть интересные. Каждый точно найдет что-то интересное для себя. Я лишь выделю пару громких интересных поинтов.

1. Всегда начинайте с интерационных тестов. E2E-тестов и юнит-тестов должно быть мало.
2. Пишите тесты во время разработки, а не после
3. Поднимайте реальную БД для тестирования с помощью докера
4. Используйте бест-практисы юнит-тестирования для интеграционных тестов
5. Структурируйте тесты по роутам и историям
6. Изолируйте компонент (в терминах Component Testing) на уровне HTTP. То есть, грубо говоря, мокайте запросы к внешним сервисам.
7. По умолчанию на все исходящие запросы надо отвечать ошибкой. Каждый тест должен явно прописывать ожидаемые ответы и запросы.
8. Не забывайте тестировать негативные кейсы, в том числе сетевые проблемы, некорректные ответы и сообщения
9. Используйте фейковый брокер сообщений для тестирования

https://github.com/goldbergyoni/nodejs-testing-best-practices

#development #javascript #nodejs #testing #bestPractices #github
👍81
Вот почти и прошёл очередной год.

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

Словом года, по мнению известного словаря, стало слово "Слоп". LLM и ИИ прочно вошли в медиа, бытовую и профессиональную жизнь.

Текущие инструменты с ИИ (почти бесплатные между прочим) очень сильно упростили и ускорили работу - написание кода, доки, отчётов, поиск информации и решений. Cursor, chatgpt и perplexity - три инструмента которые я использую почти ежедневно как в работе, так и в сайд проектах (все последние фичи в хром расширении почти полност сделаны курсором) и просто в бытовых ситуациях.

Также теперь воочию наблюдаю как молодёжь изучает программирование с ИИ. Взял студента из новосибирского университета сделать важную фичу в расширении. Теперь наблюдаю, как появляется рабочий код, но "автор" не понимает как он работает и как делать в нем правки. Но, если помогать человеку учить базу программирования, то обучение идёт прям бодро.

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

В общем, посмотрим, как разгонится весь ИИ-движ в следующем году.

Всех с наступающим новым годом (или с наступившим, если читаете это в 2026 гожу). Всем быстрых фронтендов, интересных проектов и челленджей, чутких и умных руководителей (и подчинённых, если вы руководитель).

Ну и, конечно же, успехов в личных делах и гармонии в семье
🎉🎉🎉
19🎉15👍5
How to Steal Any React Component

Статья показывает, как восстановить react-компонент с любого сайта без доступа к исходникам. Способ не со 100% гарантией, но, тем не менее, достаточно интересный. Также в статье очень прикольные интерактивные элементы - очень сильно помогают в чтении материала.

Итак, по шагам

Шаг 1: Есть 2 дерева - DOM и React-Fiber и их можно связать.

Первое доступно в браузере
Второе - внутреннее представление компонентов в React, которое также доступно в браузере. React, начиная с 16 версии, выставляет API для минимальной работы с этим деревом, чтобы нам было удобно дебажить сайты в React Developer Tools. В этом API есть возможность узнать, каким React-компонентом создан DOM-элемент и с какими пропасами.

Таким образом мы можем пройтись по всем элементам DOM-дерева, чтоб узнать, какими компонентами они рендерятся и с какими пропсами что-то рендерилось.

Шаг 2: Собираем рендеры одного компонента в кучку
Например, мы обнаружили, что базовый элемент "Кнопка" был отрендерен 10 раз. Тогда мы можем собрать 10 кейсов мапинга props => HTML для кнопки

Шаг 3: Просим LLM на основе мапинга компонента восстановить компонент
Берем полученный мапинг, докидываем минифицированный код компонента (который можно получить через .toString в React Fiber) и просим LLM восстановить читемый код.

Шаг 4: Проверяем, что компонент корректно восстановился
Проверяем, что с теми же входными данными мы получаем тот же HTML. Если это не так - просим LLM поправить код

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


https://fant.io/react/

#development #javascript #react #ai #llm
👍14🤩21
Бизнес Tailwind сокращается из-за AI

Комментарий к пул-реквесту на github, где автор tailwind сообщает, что из-за AI пришлось уволить 75% разработчиков tailwind.

Tailwind состоит из двух частей:
1. Опенсорсная часть, на которой очень хорошо обучен LLM
2. Tailwind labs - там платные UI-киты, сапорт и все такое

Повсеместное использование LLM разработчиками привело к тому, что:
1. Люди перестали заходить в доку tailwind и видеть рекламу платных фич
2. LLM и сами могут создать хорошие компоненты, поэтому снижается потребность в платных фичах

В общем, tailwind, который опенсорсный, еще жив и, скорее всего, продолжит развиваться. А платный функционал не выдержал конкуренции с LLM - tailwind labs не успели адаптироваться к новым реалиям. На хабре есть хороший резюмирующий комментарий по этому поводу

К tailwind можно относиться по разному (лично я - не фанат описания десятка классов, но мне ок если это делает LLM), но его автор сделал крутой инструмент и даже придумал как монетизировать опенсорс продукт - это достойно уважения.




#development #javascript #tailwind #ai
6👍6😢3😁2🤩1
JavaScript: заметка об Anchor Positioning API

Статья на Habr, которая вводит в новый Web API - Anchor positioning. Он позволяет позиционировать элементы относительно другого якорного элемента. Простыми словами - это как position: absolute, но не относительно ближайшего родителя с нужным position, а относительно объявленного якорного элемента

Если честно, я никогда не был силен в CSS. Но если какое-то время CSS был относительно простым и понятным, то теперь он становится все сложнее. Anchor Positioning - как раз одна из сложных, на мой взгляд, фич.

Наивное использование более менее простое: объявляем элемент якорем, а другой элемент связываем с якорем и говорим, где хотим отображаться
#dropdownTrigger {
anchor-name: --dropdownTrigger;
}

#dropdownMenu {
position-anchor: --dropdownTrigger;

/* Снизу */
position-area: bottom;
/* absolute или fixed */
position: absolute;
}


Но ведь элемент может не влезть туда, куда мы его хотим поместить? Для этого есть директива position-try-fallbacks: flip-block;, которая говорит, что если элемент не влезает с одной стороны - надо пробовать с другой. При этом также будут изменены соответствующие margin (например, если элемент отображается снизу и имеет верхний отступ от якоря в 10px, то при переворачивании отступ станет отступом снизу).

Еще появляется возможность высчитывать что-то, относительно размера якоря
width: calc(anchor-size(width) - var(--p) * 2 - 2px);


Вот, например, можно заняться выставлением стрелки тултипа по середине тултипа
#tooltip {
anchor-name: --tooltip;

/* Стрелка */
&::before {
position: fixed;
left: calc(anchor(--anchor center) - var(--d) / 2);
top: calc(anchor(--tooltip top) - var(--d) / 2);
/* translateX(-50%) больше не нужен */
transform: rotate(45deg);
}
}



Правда, если сработает flip-block, то стрелка не перевернется. Для этого делают переопределение top через container query
#tooltip {
/* Нам больше не нужен --customTop */
position-try-fallbacks: flip-block;
/* Делаем тултип anchored query container */
container-type: anchored;
}

@container anchored(fallback: flip-block) {
#tooltip::before {
top: calc(anchor(--tooltip bottom) - var(--d) / 2);
}
}


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

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

https://habr.com/ru/companies/timeweb/articles/979180/

#development #css #anchorPositioning
🔥9👍4
Дайджест за 2026-01-14 - 2026-01-16

How to Steal Any React Component
Статья показывает, как восстановить react-компонент с любого сайта без доступа к исходникам. Способ не со 100% гарантией, но, тем не менее, достаточно интересный. Также в статье очень прикольные интерактивные элементы - очень сильно помогают в чтении материала.

Бизнес Tailwind сокращается из-за AI
Комментарий к пул-реквесту на github, где автор tailwind сообщает, что из-за AI пришлось уволить 75% разработчиков tailwind.


JavaScript: заметка об Anchor Positioning API
Статья на Habr, которая вводит в новый Web API - Anchor positioning. Он позволяет позиционировать элементы относительно другого якорного элемента. Простыми словами - это как position: absolute, но не относительно ближайшего родителя с нужным position, а относительно объявленного якорного элемента

——————————————

Спасибо что читаете, ставите реакции и отмечаетесь в комментариях. Если вы хотите помочь каналу - расскажите о нем своим коллегам или друзьям. Также оставляйте фидбек по формату, материалу и чему-угодно еще 🙂
🔥12
The Package Management Landscape

Просто страница со списком различных менеджеров пакетов и всем, что связано с менеджерами пакетов. Начиная от самих менеджеров пакетов для разных языков, и заканчивая стандартами, RFC, тулингом вокруг менеджеров пакетов

https://nesbitt.io/2026/01/03/the-package-management-landscape.html

#development #packageManagers
6
Building Type-Safe Compound Components

Статья про правильную организацию связанных компонентов (Compound Components) с корректной проверкой типов. Каноничные примеры таких компонентов: Select+Option, Modal+ModalHeader+ModalFooter+ModalContent

Сначала автор разбирает Select+Option
import { Select, Option } from '@/components/select';

function ThemeSwitcher({ value, onChange }) {
return (
<Select value={value} onChange={onChange}>
<Option value="system">🤖</Option>
<Option value="light">☀️</Option>
<Option value="dark">🌑</Option>
</Select>
);
}



Какие тут проблемы видит автор:
1. Появляется возможность всунуть в children не Option, чего мы не хотим. Типизировать компонент так, чтобы можно было всунуть только конкретный Option - неправильно с точки зрения идеологии компонентов React
2. Select не нужен для статичных данных, особенно если там меньше 5 элементов. Select нужен для динамичных данных
3. Писать Option в разметке, когда мы там ничего больше и не хотим видеть - странное лишнее занятие

Поэтому лучшее решение - сделать проп options, а сам Select - generic-компонентом, у которого options, onChange и другие пропсы связаны одним типом

import { Select } from '@/components/select';
import { useSuspenseQuery } from 'some-query-library';

function UserSelect({ value, onChange }) {
const userQuery = useSuspenseQuery(userOptions);

return (
<Select
value={value}
onChange={onChange}
options={userQuery.data}
/>
);
}

// Типизация Select компонента
type SelectValue = string | number;

type SelectOption<T extends SelectValue> = {
value: T;
label: string;
};

type SelectProps<T extends SelectValue> = {
value: T;
onChange: (value: T) => void;
options: ReadonlyArray<SelectOption<T>>;
};



Те же критерии верны и для модалки - нет смысла давать возможность указывать children, вместо этого лучше воспользоваться слотами

function ModalDialog({ header, body, footer }) {
return (
<DialogRoot>
<DialogBackdrop />
<DialogContent>
<DialogHeader>{header}</DialogHeader>
<DialogBody>{body}</DialogBody>
<DialogFooter>{footer}</DialogFooter>
</DialogContent>
</DialogRoot>
);
}

// Usage:
<ModalDialog header="Hello" body="World" footer="!" />




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

import { RadioGroup, RadioGroupItem } from '@/components/radio';
import { Flex } from '@/components/layout';

function ThemeSwitcher({ value, onChange }) {
return (
<RadioGroup value={value} onChange={onChange}>
<Flex direction={['row', 'column']} gap="sm">
<RadioGroupItem value="system">🤖</RadioGroupItem>
<RadioGroupItem value="light">☀️</RadioGroupItem>
<RadioGroupItem value="dark">🌑</RadioGroupItem>
</Flex>
</RadioGroup>
);
}



Чтобы достичь типизации, можно сделать RadioGroupItem дженериком
<RadioGroupItem<ThemeValue> value="system">🤖</RadioGroupItem>


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

type ThemeValue = 'system' | 'light' | 'dark';

type ThemeSwitcherProps = {
value: ThemeValue;
onChange: (value: ThemeValue) => void;
};

const Theme = createRadioGroup<ThemeValue>();

function ThemeSwitcher({ value, onChange }: ThemeSwitcherProps) {
return (
<Theme.RadioGroup value={value} onChange={onChange}>
<Flex direction={['row', 'column']} gap="sm">
<Theme.RadioGroupItem value="system">🤖</Theme.RadioGroupItem>
<Theme.RadioGroupItem value="light">☀️</Theme.RadioGroupItem>
<Theme.RadioGroupItem value="dark">🌑</Theme.RadioGroupItem>
</Flex>
</Theme.RadioGroup>
);
}



https://tkdodo.eu/blog/building-type-safe-compound-components

#development #react #typescript #javascript #compoundComponents
👍7👎21
Дайджест за 2026-01-19 - 2026-01-23

The Package Management Landscape
Просто страница со списком различных менеджеров пакетов и всем, что связано с менеджерами пакетов. Начиная от самих менеджеров пакетов для разных языков, и заканчивая стандартами, RFC, тулингом вокруг менеджеров пакетов


Building Type-Safe Compound Components
Статья про правильную организацию связанных компонентов (Compound Components) с корректной проверкой типов. Каноничные примеры таких компонентов: Select+Option, Modal+ModalHeader+ModalFooter+ModalContent



——————————————

Спасибо что читаете, ставите реакции и отмечаетесь в комментариях. Если вы хотите помочь каналу - расскажите о нем своим коллегам или друзьям. Также оставляйте фидбек по формату, материалу и чему-угодно еще 🙂
👍12
Mitigating Denial-of-Service Vulnerability from Unrecoverable Stack Space Exhaustion for React, Next.js, and APM Users

В node.js недавно исправили уязвимость в async_hooks, которая позволяла крашнуть node.js сервис. Node.js некорректно обрабатывал ошибку переполнения стека во время обработки async_hooks и просто завершал процесс, вместо кидания исключения. async_hooks достаточно популярный модуль, который используется в React Server Components, Next.js, Datadog, OpenTelemetry и других популярных проектах.

Простейший код для демонстрации уязвимости - создаем в хуке функцию, которая рекурсивно вызывает саму себя, перед первым вызовом оборачиваем ее в try-catch.

Ожидаемое поведение: когда наступит переполнение стека, код попадет в catch ветвь для обработки RangeError
Наблюдаемое поведение: node.js прекращает работу с кодом ошибки 7

import { createHook } from 'node:async_hooks';

// This simulates what APM tools do
createHook({ init() {} }).enable();

function recursive() {
new Promise(() => {}); // Creates async context
return recursive();
}

try {
recursive();
} catch (err) {
console.log('This never runs', err);
}



Кейс из реального мира: на вход в API приходит огромный JSON с вложенными массивами. API обрабатывает его рекурсивно и пробивает ограничение по стеку и приложение падает

// pages/api/process.js
export default async function handler(req, res) {
try {
const data = req.body;
const result = processNestedData(data); // Deeply nested = stack overflow
res.json({ success: true, result });
} catch (err) {
// THIS CATCH BLOCK NEVER RUNS
console.error('Processing failed:', err);
res.status(500).json({ error: 'Processing failed' });
}
}

function processNestedData(data) {
if (Array.isArray(data)) {
return data.map(item => processNestedData(item));
}
return transform(data);
}




Пример json
[[[[[[[[[/* и еще 50 тысяч раз*/]]]]]]]]]


В статье также идет погружение в специфику движка с поверхностным разбором работы v8 и node.js.

Уязвимость была зарепорчена 7 декабря, а поправлена 13 января - достаточно оперативно.

Насколько я понял, уязвимость актуальная для старых версий node.js (т.к. async_hooks реализованы еще в node.js 8), начиная с версии 24.х приложения на React Server Component и Next.js не подвержены уязвимости т.к. перешли с async_hooks на AsyncLocalStorage.

https://nodejs.org/en/blog/vulnerability/january-2026-dos-mitigation-async-hooks

#development #react #node #dos #security
👍4
Вот и реальные примеры наивной замены node на bun - значительное замедление :)

btw подписывайтесь на канал - Рома пишет редко, но метко
👍1
Forwarded from Рома вещает
Node.js vs Deno vs Bun

У нас есть SSR-сервис для перегона реакт компонентов в html. Он написан на ноде.

Ради интереса решили попробовать его завести на deno и на bun: вдруг они покажут себя лучше.

В первом подходе начали с малого: просто завели текущий код на альтернативных рантаймах. Мы не заменяли пакеты ноды на пакеты его собратьев и ничего не адаптировали специально под конкретный рантайм.

Просто взяли установили текущие зависимости через deno и bun (благо оба умеют работать как с пакетами из npm, так и с пакетами ноды). Попробовали запустить.

Deno

С толчка не завелся. Кидал ошибки. Их было несколько и они последовательно всплывали после починки предыдущей. В конце концов завелся.

Bun

Сразу завелся. Но в некоторых кейсах всплывала ошибка, которую не сразу заметили. Поправили. В итоге тоже заработал.

Сравнение на проде

У нас есть несколько инстансов SSR-сервиса. Выбрали из них три для эксперимента:
- первый - остался на ноде;
- второй - на дино;
- третий - на бане.

Все три инстанса работают на одинаковом железе и нагрузка на них идёт одинаковая.

Результаты

Нода и дино оказались в нашем кейсе примерно равны по скорости ответа. Дино даже на несколько ms был быстрее.

Бан оказался в два раза медленней своих конкурентов.

Что дальше

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

P.S. если у вас есть опыт сравнения разных серверных js-рантаймов – делитесь кейсами в комментах. Будет интересно почитать.
👍12🔥6
Stop turning everything into arrays (and do less work instead)

Простая статья с основным посылом прямо в заголовке - хватит превращать все в массивы, можно делать проще и эффективнее. Если коротко - базовые цепочки типа arr.map().filter().slice().map() для большой нагрузки (или больших массивов) эффективнее заменить на итераторы items.values().filter().map().take().toArray().

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

Если у вас массив из 5000 элементов и вы сделаете arr.map(fn).map(fn2).filter(fn3).slice(0,10) то, несмотря на то, что вам нужно всего 10 элементов, движок обработает перед slice все 5000 элементов дважды в map. Т.е. в массивной цепочке операции выполняются друг за другом для всего потока данных.

Аналогичная цепочка в итераторах выглядит так items.values().map(fn1).map(fn2).filter(fn3).take(10).toArray(). Эта цепочка выполняет каждую операцию друг за другом для каждого элемента в отдельности и цепочка завершится ровно тогда, когда take(10) наберет 10 элементов после filter.

Еще в статье приводится юзкейс с загрузкой пагинированных данных через итераторы
async function* fetchPages() {
let page = 1;
while (true) {
const res = await fetch(`/api/items?page=${page++}`);
if (!res.ok) return;
yield* await res.json();
}
}

const firstTen = await fetchPages()
.filter(isValid)
.take(10)
.toArray();


Выглядит достаточно лаконично

Когда не следует использовать итераторы:
1. Нужен доступ по индексу (arr[10])
2. Алгоритм изменяет массив
3. Мало данных - в этом случае проще будет обойтись методами массива

Достаточно простая заметка, но напоминает о возможностях итераторов в современном JS

https://allthingssmitty.com/2026/01/12/stop-turning-everything-into-arrays-and-do-less-work-instead/

#development #javascript #array #iterators
👍24🔥2
War story: the hardest bug I ever debugged

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

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

Были обращения пользователей, но не прям массовые. Из обращений пользователей вида "баг происходит когда я делаю Х" ни одно не повторилось. Вообще не было уверенности, что этот баг вообще происходит. Но если он происходит — это точно блокер. Единственное, что известно — на баг жалуются пользователи Google Chrome.

Автор запустил дев-версию Google Docs и начал по-разному играться с UI. Ну, насколько это возможно для Google Docs — копировал, вставлял, игрался с форматированием, переносами и т. д. и т. п. В один момент он решил сделать скрипт, который создаёт 50 страниц текста и меняет жирность всего текста 100 раз. И оказалось, что баг повторяется между 10 и 40 итерациями! Постоянная смена жирности текста в итоге крашила что-то в приложении и появлялся огромный отступ.

Был найден способ воспроизвести баг, но всё ещё непонятно, где он конкретно появляется, т. к. движок рендера Google Docs был достаточно особенным — в те годы весь текст под меню позиционировался через абсолюты. Чтобы это работало быстро, большинство расчётов кешировалось. По стек-трейсу удалось понять, что кто-то записывает в кеш неправильное значение, которое затем крешит приложение.

Автор был более опытен в бекенде, поэтому позвал более опытного в UI коллегу разбираться с багом.

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

В такие моменты начинаешь проверять самые безумные теории. Было решено залогировать вывод Math.abs() — вероятность ничтожно мала, но мало ли. Но оказалось, что Math.abs() для отрицательного числа может вернуть то же самое отрицательное число. ВАУ!

Благо ребята работали в Google и просто зашли к чувакам, которые разрабатывают браузер. Там им ответили чисто по корпоративному: «Да, это баг, но технически он не наш — это вам в команду V8 движка». Оказалось, что баг уже пофикшен и выйдет в следующем релизе. Ребята оптимизировали работу Math.abs() в движке и допустили небольшую ошибку, приводящую к тому, что Math.abs() возвращал не то значение.

Достаточно интересная история с неожиданным источником проблемы. Всё-таки мы всегда доверяем встроенным в движок методам (особенно если это Math.abs(), где и ошибиться-то негде). Но вот бывает и такое.

https://www.clientserver.dev/p/war-story-the-hardest-bug-i-ever

#development #javascript #bug #googleDocs
😱27🔥7😁21🤩1
Дайджест за 2026-01-26 - 2026-01-30

Mitigating Denial-of-Service Vulnerability from Unrecoverable Stack Space Exhaustion for React, Next.js, and APM Users
В node.js недавно исправили уязвимость в async_hooks, которая позволяла крашнуть node.js сервис. Node.js некорректно обрабатывал ошибку переполнения стека во время обработки async_hooks и просто завершал процесс, вместо кидания исключения. async_hooks достаточно популярный модуль, который используется в React Server Components, Next.js, Datadog, OpenTelemetry и других популярных проектах.

Stop turning everything into arrays (and do less work instead)
Простая статья с основным посылом прямо в заголовке - хватит превращать все в массивы, можно делать проще и эффективнее. Если коротко - базовые цепочки типа arr.map().filter().slice().map() для большой нагрузки (или больших массивов) эффективнее заменить на итераторы items.values().filter().map().take().toArray().

War story: the hardest bug I ever debugged
Наверняка вы сталкивались с багами, которые настолько неуловимые, что аж бесит. Только кажется, что нашёл причину, как оказывается, что это тупик. Статья как раз про такую историю с очень интересным багом.

——————————————

Спасибо что читаете, ставите реакции и отмечаетесь в комментариях. Если вы хотите помочь каналу - расскажите о нем своим коллегам или друзьям. Также оставляйте фидбек по формату, материалу и чему-угодно еще 🙂
6🔥5
7 practical animations tips

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

Разобраны следующие примеры:
- Изменение scale на кнопке при взаимодействии
- Анимацию появления чего-либо (например тултипов) следует делать не со scale(0), а с хотя бы scale(0.9)
- Если у вас в интерфейсе есть задержка перед появлением тултипов, то для рядом расположенных элементов задержка имеет смысл только при первом появлении тултипа, а дальше тултип можно показывать сразу
- Выбирайте правильную кривую анимации. Для своих кейсов можно сделать кастомную
- Анимация появления должна быть направлена от точки, где пользователь взаимодействовал с интерфейсом (этот пример в статье заметен только с включением замедления анимации)
- Анимации должны быть быстрыми. Быстрые анимации дают ощущение быстрого продукта
- Если нужно сделать анимацию изменения состояния, а состояния разные - используйте blur.

Лучше зайти в статью и глянуть разницу анимаций своими глазами

https://emilkowal.ski/ui/7-practical-animation-tips

#development #javascript #css #animations
👍10
Yarn 6 Preview

Я уже давно не следил за развитием Yarn, а тут оказывается, они уже готовят шестую версию (пятую пока еще, правда, не выпустили). Собственно, основная большая фича Yarn 6 - это реализация пакетного менеджера на Rust

Работы по переписыванию уже ведутся какое-то время и текущая версия реализации уже работает в разы быстрее.

Кроме переписывания на Rust (и, следовательно, более быстрой работы) обещают:
- Ленивую установку пакетов - это когда вы делаете Yarn run, а Yarn сам поймет: надо ли установить какие-то пакеты или нет
- Yarn Switch - свой менеджер менеджеров пакетов. Вы в package.json указываете, какой пакетный менеджер используется в проекте, а Yarn Switch занимается установкой и запуском этого менеджера пакетов

https://yarn6.netlify.app/blog/2026-01-28-yarn-6-preview/

#development #javascript #yarn #rust
👍6💩31
gogcli

gogcli - инструмент для терминала, позволяющий работать с сервисами Google: почта, диск, документы, календарь и другое. Очень удобно, просто и хорошо интегрируется с AI-агентами

https://gogcli.sh/

#development #google #commandLine #tool
1