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

Контакт: @msosnov
Download Telegram
ffetch

ffetch - ещё одна библиотека для замены нативного fetch в коде. Эта библиотека предоставляет поддержку typescript, таймауты, ретраи с динамическим таймаутом между ретраями, хуки, менеджмент ошибок, мониторинг, circuit breaker и другие фичи. Выглядит недурно - все самое базовое и необходимое для сетевых запросов уже в комплекте.

Пример базового использования
import createClient from '@fetchkit/ffetch'

// Create a client with timeout and retries
const api = createClient({
timeout: 5000,
retries: 3,
retryDelay: ({ attempt }) => 2 ** attempt * 100 + Math.random() * 100,
})

// Make requests
const response = await api('https://api.example.com/users')
const data = await response.json()


https://github.com/fetch-kit/ffetch

#development #javascript #github #fetch
🔥181
Array.prototype.pushAll

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

Например
arr2.forEach(item => arr.push(item))

// или
arr.push(...arr2)

// или
for(const item of arr2) { arr.push(item)}


Но, как оказывается, есть нюанс.

В случае использования spread оператора arr.push(...arr2) все работает, но, т.к. каждый элемент массива arr2 надо теперь сделать отдельным аргументом, то это влечет за собой необходимость поработать js-движку. И, оказывается, есть обращения в github nodejs, когда чуваки спредят массивы из миллионов элементов и у них падает приложение из-за stack overflow

Окей, допустим спред не ок использовать для больших массивов, но ведь остается вариант с пушом в цикле. Но он тоже не без проблем. Т.к. добавление идет по одному элементу, js-движку может потребоваться несколько раз переалоцировать память. Для движка лучше если он сразу будет знать, сколько данных надо вставить в массив.

Это, наверняка, обходится с помощью первоначального указания новой длинны массива (arr.length += arr2.length), но это будут помнить малое количество разработчиков.

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


https://github.com/tc39/proposal-bulk-add-array-elements

#development #javascript #tc39
21🔥7👍6
Bun 1.3

Вышел Bun 1.3. Основные фишки: улучшили поддержку фулстэк-разработки, встроили MySQL и Redis клиенты, улучшили работу с Cookie и роутингом, сделали улучшения для монорепо

Теперь обо всем по порядку

Если вы разрабатывается чисто фронтенд, то теперь достаточно запустить bun './**/*.html' и bun сделает транспиляцию и сборку всех исходников и сразу подтянет HMR. В релиз ноутсах также показывается насколько быстро работает HMR - текст на сайте обновляется мгновенное вместе с редактированием tsx исходника. Выглядит мощно.

Также в bun встроили простой роутинг и стриминг логов с браузера в терминал
import homepage from "./index.html";
import dashboard from "./dashboard.html";
import { serve } from "bun";

serve({
development: {
// Enable Hot Module Reloading
hmr: true,

// Echo console logs from the browser to the terminal
console: true,
},

routes: {
"/": homepage,
"/dashboard": dashboard,
},
});


Также фулстек приложения можно собирать в исполняемые файлы на разные ОС.

Появились новые хелперы для работы с SQL и новые встроенные DB-клиенты: mysql и redis. Встроенный redis-клиент в разы быстрее внешних библиотек (node-redis и ioredis). По замерам создателей Bun, конечно же. В любом случае - встроенная поддержка популярных СУБД это большой плюс.

Также много работ сделано в менеджере пакетов. В частности - внедрены isolated installs для монореп. Эта настройка делает так, что пакет не сможет достучатся до зависимости, которая не объявлена в его package.json. Эта настройка включена по дефолту. Если нужно вернуть старое поведение необходимо в конфиг bun добавить linker = "hoisted"

Также из интересного: добавили Security Scanner API. Теперь можно устанавливать внешние решения для аудита безопасности пакетов.

Еще сделали большой блок изменений во встроенный в Bun тест-реймворк. Во первых, сделали официальное расширение для VSCode, которое интегрирует bun test в VS Code Test Explorer UI, т.е. тесты можно запускать из UI vscode и там же смотреть результаты. Во вторых - дали явную возможность помечать тесты, как готовые для запуска в параллельном режиме или как требующие последовательного запуска. Это крайне полезно. По умолчанию в параллель запускаются не более 20 тестов, но это значение можно изменить. Важное отличие новой фичи от того, что уже есть в vitest или jest - можно запускать в параллель тесты, написанные в одном файле. Это, конечно, не новая фича (условный ava умеет такое с самого начала, если я правильно помню), но все равно звучит полезно.

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

test.failing("known bug: division by zero", () => {
expect(divide(10, 0)).toBe(Infinity);
// This test currently fails but is expected to fail
// Remove .failing when the bug is fixed
});

test.failing("TDD: feature not yet implemented", () => {
expect(newFeature()).toBe("working");
// Remove .failing once you implement newFeature()
});



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

https://bun.sh/blog/bun-v1.3

#development #javascript #bun #releaseNotes
👍152
React Compiler v1.0

Вышел React Compiler v1.0. Его можно поставить и, по заверениям разработчиков, забыть о ручном менеджменте useMemo, useCallback, React.memo в 99% кейсах - теперь эту работу должен забрать на себя React Compiler. В остальных 1% кейсов можно заняться ручной оптимизацией для достижения лучших результатов.

React Compiler уже используется в приложениях. Например в Meta Quest Store - магазин приложений для VR гарнитуры Oculus Quest. Использование React Compiler ускорило работу навигации на 12%, а некоторые взаимодействия ускорились в 2.5 раза.

Штош, ждем посты на хабре и доклады на конфах про то, как люди включили React Compiler и их сайт ускорился или им пришлось потратить неделю на поиск бага.

https://react.dev/blog/2025/10/07/react-compiler-1

#development #javascript #react #reactCompiler
🔥15💩144👍1
Oxlint JS Plugins Preview

Oxlint представили API для плагинов на JS. При этом есть 2 версии API - частично совместимое с Eslint, что позволяет подключить eslint-правила в oxlint без доп приседаний, и oxlint API, которое позволяет делать более производительные правила.

Пока что это превью, поэтому нет полноценной поддержки eslint API и плюс есть еще куда ускорится. Тем не менее, переход на oxlint в моменте даст значительное ускорение - даже с кастомными плагинами oxlint работает в 15 раз быстрее eslint.

При этом API плагинов для oxlint не сильно отличается от eslint. С миграцией кода с eslint на oxlint вполне справится любая LLM. С точки зрения разрабов oxlint было бы правильно выложить prompt или rules для переписывания правил на основе LLM или AI-агентов.

https://oxc.rs/blog/2025-10-09-oxlint-js-plugins.html

#development #javascript #oxlint #eslint
🔥12👍3
Node.js 22 Features You Should Be Using

Nodejs 22 стал LTS, а значит пора обновляться и смотреть, чего же там нового принесли в Nodejs.

Основные изменения:
- WebSocket клиент теперь стабильная фича, можно смело переходить на него
- fetch теперь также стабильная фича, можно смело переходить на встроенный fetch
- улучшили модель разрешений. Можно лочить использование файловой системы или env-переменных
node --experimental-permission \
--allow-fs-read=/app/data \
--allow-env=NODE_ENV index.js

- Стабилизировали использование require из ES-модулей. Это должно упростить жизнь на время перехода экосистемы к ES-модулям
- Встроенный тест-раннер теперь поддерживает кастомные репортеры, сбор тестового покрытия и мокирование таймеров
- Поддержка AbortController в нативных API


https://nodesource.com/blog/nodejs-22-features

#development #javascript #nodejs #releaseNotes
🔥14
Исходники веб-версии app store

Чуваки из эпла, которые разрабатывают веб версию апстора, случайно сделали сорсмапы кода открытыми на проде. И теперь исходный код апстора стал общественным достоянием - энтузиасты скачали его и залили на гитхаб. Репозиторий уже прикрыли, но вы легок можете найти другие репозитории поиском по гитхабу по строке apps.apple.com. Скорее всего уже можно посмотреть и не на гитхабе.

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

Я посмотрел краем глаза, что увидел:
- Используется svelte и scss
- Не смотря на использование svelte, встречается импеативная работа с DOM (создание элементов, навешивание классов)
- Иногда встречаются достаточно объемные комментарии к работе кода - респект людям, описывающие нюансы работы решения в комментариях
- У каждой уважающей себя команды непременно должен быть написан свой логгер. Чтобы было уж совсем по-взрослому - нужен базовый логгер и его наследник - ConsoleLogger. У эпла все серьезно - логгеры с наследованием
- Используется нативный dialog для модалок + полифилл. Также респект за использование нативного dialog

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

https://github.com/rxliuli/apps.apple.com

#development #javascript #svelte #appStore #apple
👍13
ESLint Plugin for Baseline JavaScript

Eslint Plugin для проверки использования слишком нового синтаксиса и фичей веба. Вы выбираете baseline threshold, а плагин контролирует, чтобы вы его придерживались

https://baselinejs.vercel.app/

#development #javascript #eslint #baseline
🔥11👍1
Error chaining in JavaScript: cleaner debugging with Error.cause

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

Решаемая проблема
Когда в коде возникает ошибка, а вы ее заворачиваете во что-то более читаемое, то вы теряете корневой источник ошибки. Как это делается без Error.cause

try {
JSON.parse('{ bad json }');
} catch (err) {
throw new Error('Something went wrong: ' + err.message);
}


Здесь мы сохраняем исходную ошибку только через упоминание в error.message и не сохраняем стак-трейсы

Решение: Error.cause
Стандартизировали возможность передать исходную ошибку как причину новой ошибки, что позволяет сохранять весь контекст на любом уровне

try {
try {
JSON.parse('{ bad json }');
} catch (err) {
throw new Error('Something went wrong', { cause: err });
}
} catch (err) {
console.error(err.stack);
console.error('Caused by:', err.cause.stack);
}


В выводе содержатся оба стактрейса
Error: Something went wrong
at ...
Caused by: SyntaxError: Unexpected token b in JSON at position 2
at JSON.parse (<anonymous>)
at ...


Это и есть вся фича. В целом так делали и до стандартизации этого подхода, но хорошо что стандартизировали

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

Например, у вас в иерархии 3 уровня: ошибка сети => ошибка доступа к БД => ошибка сервиса

class ConnectionTimeoutError extends Error {}
class DatabaseError extends Error {}
class ServiceUnavailableError extends Error {}

try {
try {
try {
throw new ConnectionTimeoutError('DB connection timed out');
} catch (networkErr) {
throw new DatabaseError('Failed to connect to database', { cause: networkErr });
}
} catch (dbErr) {
throw new ServiceUnavailableError('Unable to save user data', { cause: dbErr });
}
} catch (finalErr) {
logErrorChain(finalErr);
}


Можно реализовать logErrorChain следующим образом
function logErrorChain(err, level = 0) {
if (!err) return;
console.error(' '.repeat(level * 2) + `${err.name}: ${err.message}`);

if (err.cause instanceof Error) {
logErrorChain(err.cause, level + 1);
} else if (err.cause) {
console.error(' '.repeat((level + 1) * 2) + String(err.cause));
}
}


Тогда мы увидим вот такой вывод
ServiceUnavailableError: Unable to save user data
DatabaseError: Failed to connect to database
ConnectionTimeoutError: DB connection timed out



https://allthingssmitty.com/2025/11/10/error-chaining-in-javascript-cleaner-debugging-with-error-cause/

#development #javascript #error
🔥16👍4
JavaScript engines zoo

Сколько JS-движков вы можете вспомнить с ходу? Скорее всего большинство назовет 3: v8 в хроме, что-то в firefox и что-то в safari. Более прошаренные чуваки вспомнят еще штуки 3-4 специфичных. А их оказывается десятки. На сайте собрана сравнительная таблица существующих (и существовавших) JS-движок с верхнеуровневым сравнением движков друг с другом

https://ivankra.github.io/javascript-zoo/

#development #javascript #jsEngines
10👍7