Node.JS [ru] | Серверный JavaScript

Node.JS [ru] | Серверный JavaScript

@we_use_js

Node.js, backend и AI-разработка: статьи, новости, вайбкодинг, автоматизация и работа с ИИ-агентами.Личный блог автора - @just_genychПо вопросам рекламы или разработки: @g_abashkinРКН: https://vk.cc/cJPGOP

11 217подписчиков
Ежедневноmixed

Похожие каналы

Все →

Последние посты

⁣Стратегии борьбы с throttle в event loop при работе с Native Addons и FFI через worker_threadsNode.js живёт на одном потоке — это знают все. Но когда в дело вступают Native Addons (napi, C++ модули) и FFI (Foreign Function Interface), event loop может неожиданно "зависнуть". Даже если ты используешь worker_threads, throttle всё равно случается. Почему? Потому что нативные вызовы не всегда изолируются полностью. Блокирующий системный вызов в аддоне может зацепить libuv thread pool или V8, и основной поток начинает тормозить.FFI тут особенно неприятен. Библиотеки типа ffi-napi или koffi вызывают shared library синхронно — event loop просто стоит и ждёт, пока вызов вернётся. Все остальные задачи замораживаются.Что с этим делать?1. Вынос в dedicated worker.Создаёшь отдельный worker, грузишь туда аддон, общаешься через MessageChannel. Главное — не передавай shared memory без синхронизации, если аддон не thread-safe.const { Worker } = require('worker_threads');const worker = new Worker('./native-worker.js', { workerData: {} });worker.postMessage({ task: 'heavyCalc', data: [1, 2, 3] });worker.on('message', result => console.log('Результат:', result));Внутри worker:const { parentPort } = require('worker_threads');const nativeAddon = require('native-addon');parentPort.on('message', msg => { const result = nativeAddon.heavySync(msg.data); parentPort.postMessage(result);});2. Асинхронные API для аддонов.Если пишешь аддон сам — используй n-api async work (napi_create_async_work). Для FFI — заворачивай вызовы в setImmediate или setTimeout с нулевой задержкой. Это даёт event loop шанс обработать другие задачи.3. Пул worker'ов с очередью.Задачи распределяются, и один тяжёлый вызов не может монополизировать все ресурсы. Стандартный паттерн — берёшь задачу из очереди, отдаёшь свободному воркеру.4. Atomics и SharedArrayBuffer.Блокировка без захвата event loop. Но требует поддержки SharedArrayBuffer и аккуратной реализации.5. Мониторинг.Замеряй время вызовов через process.hrtime.bi

19 июн. 2026 г.677В Telegram

⁣WeakRef, FinalizationRegistry и утечки в нативных коллбэках: ловушки памяти в V8Node.js и GC V8 делают много работы за нас, но есть сценарии, где автоматическое управление памятью отключается. Особенно когда в дело входят нативные аддоны на C++ с N-API и коллбэки, которые живут дольше, чем само JS-окружение. WeakRef и FinalizationRegistry часто подают как спасение, но на практике это западня, если не понимать деталей.WeakRef: иллюзия безопасностиWeakRef хранит слабую ссылку на объект и не мешает GC. Выглядит удобно для кэширования, но deref() может вернуть undefined в любой момент:const cache = new Map();function cachedGet(key, factory) { let ref = cache.get(key); if (ref && ref.deref()) return ref.deref(); const obj = factory(); cache.set(key, new WeakRef(obj)); return obj;}* Практический совет: никогда не рассчитывай на то, что объект жив после deref().* Типичная ошибка: думать, что WeakRef продлевает жизнь объекту. Нет, GC может уничтожить его сразу.FinalizationRegistry: не деструкторFinalizationRegistry вызывает коллбэк после сборки мусора, но это не гарантированный cleanup:const registry = new FinalizationRegistry((heldValue) => { console.log(Cleanup for ${heldValue});});registry.register(obj, 'some-id');* Подводный камень: время вызова не определено, и если процесс завершился, коллбэк может не случиться.* Практический совет: используй FinalizationRegistry только для логирования или диагностики, а не как основной механизм освобождения ресурсов.Утечки в нативных коллбэках: скрытый убийцаНативные аддоны с N-API могут захватить JS-коллбэк через napi_ref и забыть его освободить. В результате объект зависает навсегда:nativeModule.on('data', (msg) => console.log(msg));// В C++: napi_create_reference(env, callback, 1, &ref);// И никогда не вызывается napi_delete_reference(ref);* Production-oriented пример: обработчик событий в long-running процессе, где каждый вызов on создает новую ссылку без очистки.* Решение: в аддонах используй napi_create_reference с 0 — э

18 июн. 2026 г.764В Telegram

⁣AbortController в Node.js production: сквозные дедлайны, cleanup ресурсов и защита от «висящих» операцийAbortController важен не как таймаут для fetch, а как контракт жизненного цикла операции. В production частая ошибка - клиент уже ушел, SLA истек, а сокеты, стримы и временные файлы продолжают жить.Сквозной дедлайнУ HTTP-запроса, джобы или RPC должен быть один бюджет, который прокидывается вниз: handler - сервис - БД - внешний API - stream - timer.const client = new AbortController();req.on('close', () => { client.abort(new Error('client disconnected'));});const signal = AbortSignal.any([ client.signal, AbortSignal.timeout(1500)]);try { const r = await fetch(reportUrl, { signal }); await pipeline(r.body, createWriteStream(file), { signal });} finally { await rm(tmpDir, { recursive: true, force: true }).catch(() => {});}Типичная ошибкаНе ставьте независимые timeout: 1000 в каждом слое. Так запрос легко живет 3+ секунды, хотя общий SLA был 1 секунда. Практический совет: передавайте сверху signal, а локальный меньший бюджет делайте через AbortSignal.any().Abort кооперативенОн работает только там, где API принимает signal: fetch, timers/promises, stream.pipeline, часть fs, http, child_process, клиенты БД. Предупреждение: Promise.race() с таймаутом не отменяет реальную работу, он только перестает ждать результат.Cleanup обязателенabort() не удалит временные файлы, не вернет connection в pool и не снимет listeners. Освобождайте ресурсы в finally и прокидывайте внутрь signal, а не controller.Вывод:Сильный production-паттерн - один сквозной AbortSignal, понятный signal.reason и гарантированный cleanup каждой операции.

18 июн. 2026 г.898В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

Сатурация libuv thread pool в Node.js: как crypto, fs и dns.lookup ломают latency в productionВ Node.js async не значит "без очередей": часть операций конкурирует за общий libuv thread pool. Частая ошибка в production - смотреть только на event loop lag и не видеть очередь внутри пула.Где возникает проблемаПо умолчанию UV_THREADPOOL_SIZE=4 на процесс. Туда попадают crypto.pbkdf2, scrypt, часть randomBytes, многие fs.*, dns.lookup, zlib.for (let i = 0; i < 8; i++) crypto.pbkdf2(p, s, 500_000, 64, 'sha512', cb);await fs.readFile('./config.json');await dns.lookup('api.internal');Первые 4 pbkdf2 занимают весь пул, остальные операции ждут. Маленький config-файл или DNS lookup внезапно дают сотни миллисекунд.Production-сценарийЛогин считает password hash, HTTP-клиент часто резолвит hostname, а hot path читает сертификат или metadata с диска. CPU может быть не 100%, event loop - "здоровым", но p99 растет из-за очереди к worker'ам.DNS-нюансdns.lookup использует системный resolver через getaddrinfo и libuv pool. dns.resolve4/6/Mx используют c-ares и не конкурируют с fs/crypto так же. Предупреждение: массовый dns.lookup легко принять за "медленную сеть".Что делать* выносить тяжелый crypto в worker_threads, отдельный сервис, процессы или queue;* не читать файлы на hot path - грузить и кэшировать заранее;* включать keep-alive, pooling и DNS cache;* менять UV_THREADPOOL_SIZE только после load test:UV_THREADPOOL_SIZE=32 node server.jsБольше thread'ов - не silver bullet: CPU-bound задачи могут ухудшить p99 из-за context switching.Вывод:libuv thread pool - маленький общий ресурс процесса, поэтому latency-sensitive I/O нельзя смешивать с тяжелым crypto и частым dns.lookup без изоляции и измерений.

17 июн. 2026 г.954В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

Undici в production: почему исходящие HTTP-запросы должны иметь пулы, deadline и собственный backpressurefetch() в Node.js использует Undici, но в production часто нужен явный контроль: сколько socket'ов держим, сколько ждём upstream и что делаем, если входящий трафик быстрее внешнего API. Типичная ошибка - создавать запросы без лимитов и надеяться, что пул всё спасёт.Пул создаётся на уровне приложенияНе заводите клиент внутри handler'а. Для критичных интеграций держите Pool per-origin и переиспользуйте его:import { Pool } from 'undici'const api = new Pool('https://api.example.com', { connections: 32, pipelining: 1, connectTimeout: 2_000, headersTimeout: 3_000, bodyTimeout: 10_000})async function callApi(payload) { const { statusCode, body } = await api.request({ method: 'POST', path: '/v1/process', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload), signal: AbortSignal.timeout(12_000) }) const text = await body.text() if (statusCode >= 500) throw new Error(upstream ${statusCode}) return JSON.parse(text)}Важно: тело ответа нужно дочитать или корректно сбросить, даже если оно не нужно. Иначе socket может не вернуться в пул вовремя.connections - это capacity, а не магическое ускорениеМаленький пул даёт очередь и рост latency. Слишком большой пул перегружает upstream, плодит открытые socket'ы, упирается в NAT / ephemeral ports и ухудшает tail latency.Практический ориентир: если upstream отвечает за 100 ms, то 32 соединения дают примерно 320 RPS без pipelining. Но финальный размер выбирайте по SLO, payload size, TLS, сети и rate limits.Таймауты должны быть разнымиОдин общий timeout скрывает причину деградации.- connectTimeout - TCP/TLS connect- headersTimeout - ожидание заголовков- bodyTimeout - пауза между чанками body- AbortSignal.timeout() - общий deadline операцииПредупреждение: bodyTimeout не равен лимиту на весь response body.Backpressure делайте до UndiciНе запускайте Promise.all(items.map(callApi)) на тысячи э

16 июн. 2026 г.857В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

Graceful shutdown в Kubernetes: почему одного SIGTERM мало для keep-alive, HTTP/2 и фоновых задачВ production Pod редко умирает мгновенно: ingress, kube-proxy, LB и клиенты с keep-alive могут ещё слать трафик в terminating Pod. Частая ошибка - считать, что server.close() уже дождался всех клиентов и задач.Что реально нужно drain'ить* HTTP/1.1 keep-alive соединения* HTTP/2-сессии и активные stream'ы* фоновые задачи: BullMQ, RabbitMQ, Kafka, cron, batch jobsИначе на rolling deploy получаются редкие 502/499, оборванные stream'ы и повторная обработка сообщений.Staged shutdown для Node.jsПрактический порядок:* включить режим draining* /readyz начинает отдавать 503* дать ingress/LB несколько секунд убрать Pod из ротации* остановить новые TCP-соединения* закрыть idle keep-alive* дождаться активных запросов и задач в рамках бюджетаprocess.on('SIGTERM', async () => { draining = true; await sleep(5000); server.close(); server.closeIdleConnections?.(); h2sessions.forEach(s => s.goaway()); await waitInFlight(25_000); workers.abort(); server.closeAllConnections?.(); process.exit(0);});Важное предупреждениеserver.close() не означает "все клиенты ушли". Он только перестаёт принимать новые соединения. Уже открытые keep-alive соединения нужно отдельно закрывать через closeIdleConnections(), а в крайнем случае - через closeAllConnections().HTTP/2 и фоновые задачиДля HTTP/2 нельзя просто рубить socket: одна TCP-сессия содержит много stream'ов. Сначала отправляйте GOAWAY, чтобы запретить новые stream'ы, затем ждите завершения активных.Для workers на SIGTERM нужно остановить получение новых задач, не запускать новые cron-итерации, дождаться текущих и уметь отменять долгие операции через AbortController.Вывод:Graceful shutdown - это не обработчик SIGTERM, а управляемый drain всего, что может продолжать работу после удаления Pod из ротации.

15 июн. 2026 г.949В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

AsyncLocalStorage в production: как не потерять traceId через очереди, таймеры и connection poolingAsyncLocalStorage надежно держит контекст внутри await, промисов и I/O. Но в production traceId чаще теряется на границах: очереди, scheduler'ы, worker'ы и connection pool.Базовый слойСоздавайте контекст на входе в систему: HTTP, consumer, cron tick. Не ждите, что ALS сам перенесет его через процесс или брокер.const als = new AsyncLocalStorage();const withTrace = (traceId, fn) => als.run(Object.freeze({ traceId }), fn);const getTraceId = () => als.getStore()?.traceId;ОчередиДля in-memory очереди сохраняйте store в момент enqueue и восстанавливайте при выполнении.function enqueue(payload) { queue.push({ payload, store: als.getStore() });}function processJob(job) { return job.store ? als.run(job.store, () => handleJob(job.payload)) : handleJob(job.payload);}Для Kafka, RabbitMQ, BullMQ, SQS ALS не участвует. Практический совет: кладите traceId в headers или payload и считайте это частью контракта сообщения.Таймеры и scheduler'ыТаймер, созданный внутри контекста, обычно его сохранит. Опасность появляется, когда callback зарегистрирован в одном месте, а вызван позже из scheduler'а.Для cron/background задач создавайте новый traceId на каждый tick. Иначе получите "вечный" traceId процесса или случайный traceId старого запроса.Connection poolingТипичная ошибка - записывать traceId в client или connection object.client.traceId = getTraceId(); // плохоConnection живет дольше запроса и переиспользуется другим request'ом. Логируйте query через текущий ALS-контекст, а trace в БД передавайте на уровне конкретной операции или транзакции, например через transaction-local setting.Вывод:AsyncLocalStorage работает хорошо только внутри async chain, а на production-границах traceId нужно явно фиксировать, передавать и восстанавливать.

15 июн. 2026 г.925В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

Диагностика event loop stalls в production через monitorEventLoopDelay и async_hooks без гадания по p99 latencyEvent loop stall важен там, где Node.js обслуживает API, воркеры, очереди и webhooks. Типичная ошибка - видеть рост latency и сразу винить БД, не проверив, не заблокирован ли сам JS thread.Первый сигнал - monitorEventLoopDelayperf_hooks.monitorEventLoopDelay() дает histogram задержек event loop и дешево работает как постоянная production-метрика.import { monitorEventLoopDelay } from 'node:perf_hooks';const h = monitorEventLoopDelay({ resolution: 20 });h.enable();setInterval(() => { const p99 = h.percentile(99) / 1e6; if (p99 > 100) { log.warn({ event: 'event_loop_stall', p99Ms: p99.toFixed(1), maxMs: (h.max / 1e6).toFixed(1), ctx: als.getStore() }); } h.reset();}, 10_000).unref();Если p99 delay внезапно стал 200-500ms+, процесс не успевает выполнять callbacks вовремя: CPU-bound JS, sync I/O, тяжелый JSON.parse, regexp, crypto, zlib или GC pressure.Контекст дает async_hooksmonitorEventLoopDelay отвечает на вопрос "есть ли stall", но не говорит "кто виноват". Для production связывайте AsyncLocalStorage с request id, route, job name, tenant или queue message id.Практический пример: при stall логируйте route/job из ALS, а не только глобальный p99. Так можно увидеть, что задержки появляются рядом с POST /reports или конкретным batch job.Что отправлять в метрики* event_loop_delay_p50/p95/p99/max* CPU user/system* RSS и heap used* active handles/requests* route/job labels - осторожно, без высокой кардинальностиПредупреждение: request id кладите в логи или трейсы, но не в метрики.Важный нюансAsyncLocalStorage не профилирует CPU и не покажет строку кода. Он сохраняет контекст. Для строки нужен sampling profiler: inspector, --cpu-prof, perf/eBPF, Clinic или APM profiler.Нормальный flow: постоянно держать дешевый delay histogram, при threshold писать структурированный лог, при повторении включать profiler на короткое окно.Вывод:Event loop

14 июн. 2026 г.936В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

Совет на ближайшие годы — изучайте ВАЙБ-КОДИНГИИ уже пишет код, чинит баги, генерирует тесты, документацию и помогает запускать продукты быстрее, чем это делали классические команды разработки. И это уже не "будущее когда-нибудь", а реальность, которая меняет рынок уже сегодняИ те, кто научится вайбкодить сейчас, будут увереннее конкурировать на рынке и зарабатывать больше тех, кто по-прежнему делает всё вручную.Стартовать с нуля поможет канал Вайб-кодинг. Там ребята круглосуточно мониторят более 320 российских и зарубежных источников и публикуют только главное: релизы, инструменты, гайды, курсы и практические кейсы.Подписывайтесь, нас уже 45 тысяч: @vibecoding_tg

14 июн. 2026 г.1 020В Telegram

⁣AsyncLocalStorage в Node.js: request-scoped контекст для логов, трассировки и транзакций без prop drillingВ production это нужно в Node.js-сервисах, SSR, API integration и backend-for-frontend слоях, где requestId, traceId, tenant или транзакция должны проходить через async-код. Частая ошибка - протаскивать ctx через десятки методов или, наоборот, прятать в нём бизнес-состояние.Как это выглядитAsyncLocalStorage использует async_hooks и привязывает store к async execution flow: promise, timeout, I/O callback и большинству стандартных API Node.js.type Ctx = { requestId: string; traceId?: string; tx?: unknown };const als = new AsyncLocalStorage<Ctx>();app.use((req, _res, next) => { als.run({ requestId: req.headers['x-request-id']?.toString() ?? randomUUID(), traceId: req.headers.traceparent?.toString(), }, next);});const getCtx = () => als.getStore();function logInfo(msg: string, meta = {}) { const c = getCtx(); logger.info({ requestId: c?.requestId, traceId: c?.traceId, ...meta, }, msg);}Теперь сервисный код не знает про HTTP middleware и req, но логи автоматически получают correlation metadata.Транзакции без протаскивания txДля DB слоя можно делать withTransaction(), который запускает als.run({ ...ctx, tx }, fn), а getDbExecutor() возвращает ctx.tx ?? db. Trade-off хороший: меньше шума в API сервисов, но граница ответственности остаётся инфраструктурной, а не бизнесовой.Где границы* не заменяйте аргументы функции: бизнес-данные передавайте явно;* не кладите в store req, res, большие payload или ORM graph;* context не пересекает process boundary: worker threads, очереди, cron jobs и другие сервисы требуют явной передачи ids;* нестандартные callback-based библиотеки могут разорвать async chain.Практическое правило: используйте AsyncLocalStorage для логов, tracing, tenant/user metadata, аудита и текущей транзакции, а не для скрытого глобального состояния.Вывод:AsyncLocalStorage полезен, когда request-scoped инфраструктурный контекст улучшает observa

13 июн. 2026 г.1 020В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

Страшная тайна российского айти✖️ xCode Journal

10 июн. 2026 г.1 480В Telegram

⁣Variadic tuple types — сложные сигнатуры без болиДо variadic tuple typesмногие сложные сигнатуры в TypeScriptвыглядели как наказание.Особенно:👉 curry 👉 compose 👉 middleware 👉 typed event emitter 👉 любые функции с «прокинь аргументы дальше» Приходилось писать overload на overloadи дублировать типы вручную.Как было раньшеОбычно появлялись:👉 overload на overload 👉 ручные tuple-типы 👉 тонны дублирования Типы быстро превращалисьв нечитаемую простыню.Что изменили variadic tuplesС их появлением стало намного прощеработать с остаточными аргументами на уровне типов.Например:type Fn<T extends unknown[]> = (...args: [...T]) => voidИли собирать сигнатуры:type Append<Args extends unknown[], Arg> = [...Args, Arg]Типы наконец научились нормально работатьс «переменным количеством аргументов».Почему это важноНа практике это одна из тех TS-фич,которые реально упростили жизнь библиотекам.Без variadic tuples:👉 Redux middleware typings 👉 router APIs 👉 compose/curry utilities были бы ещё страшнее.Где начинается тёмная магияПроблемы начинаются,когда variadic tuples комбинируют с:👉 infer 👉 recursive types 👉 conditional types Типовая система очень быстропревращается в тёмный лес.IDE начинает тормозить,ошибки становятся нечитаемыми,а compile time — расти.Главная мысльVariadic tuple types —это действительно мощная фича.Главное —вовремя остановитьсяи не превратить типы в отдельный язык программирования.

9 июн. 2026 г.1 200В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

🤣 Не баг, а фича✖️ xCode Journal

3 июн. 2026 г.1 620В Telegram

⁣ES2025: Импорт JSON-файлов как модулейВведениеС выходом ECMAScript 2025 (ES2025) разработчики получили возможность напрямую импортировать JSON-файлы как модули в JavaScript-коде. Это упрощает работу с конфигурационными данными и другими статическими ресурсами, представленными в формате JSON.Синтаксис импорта JSON-модулейДля импорта JSON-файла используется ключевое слово import с указанием атрибута with { type: 'json' }. Это гарантирует, что импортируемый файл будет обработан как JSON-модуль.Пример использованияРассмотрим пример импорта конфигурационного файла config.json и обращения к его свойствам в коде.import config from './config.json' with { type: 'json' };.log(config.apiUrl); // Выводит значение свойства apiUrl из config.jsonconsole.log(config.timeout); // Выводит значение свойства timeout из config.json❗️Добавление поддержки импорта JSON-файлов как модулей в ES2025 упрощает работу с данными в формате JSON, делая код более чистым и понятным.ИсточникиJSON Modules Can Now Be Imported in JavaScript in All Modern Browsers, CSS Modules to Follow. New Features in ES2025 – BooleanBuffer.

29 мая 2026 г.2 250В Telegram

⁣Recursive type limits — почему TS иногда «умирает»В TypeScript можно написать тип,который выглядит красиво,но заставляет компилятор страдать.Особенно когда начинаются рекурсивные типы.Например:👉 глубокий DeepPartial 👉 парсинг строк на уровне типов 👉 сложные conditional types 👉 infer внутри infer На маленьком примере всё работает.В реальном проекте IDE внезапно начинает думать по 5 секунд.Почему так происходитTypeScript не вычисляет типы «бесплатно».Каждый:👉 conditional type 👉 union 👉 recursive шаг нужно реально посчитать.А если тип разворачивается слишком глубоко,компилятор упирается в лимиты.Отсюда знакомое:Type instantiation is excessively deepand possibly infiniteИ это не всегда баг TypeScript.Часто это сигнал,что типовая модель стала слишком умной.Где обычно всё ломаетсяОсобенно опасны:👉 рекурсивные mapped types 👉 огромные union’ы 👉 type-level parser’ы 👉 deeply nested generics 👉 utility types поверх utility types Типы начинают взрываться комбинаторно.Что обычно помогает👉 не делать type-level акробатику без нужды 👉 ограничивать глубину рекурсии 👉 разбивать типы на более простые 👉 добавлять явные промежуточные типы 👉 не тащить сложные generic-типы в публичный API Почему это важноСложные типы бьют не только по компиляции.Они ухудшают:👉 autocomplete 👉 responsiveness IDE 👉 читаемость кода 👉 onboarding новых людей Иногда самый дорогой runtime —это compile time.Главная мысльХороший TypeScript —это не когда типы поражают воображение.Хороший TypeScript —это когда их можно понять через полгода,а IDE при этом не превращается в обогреватель.

28 мая 2026 г.1 670В Telegram

⁣Isolated declarations — ускорение больших monorepoВ TypeScript есть флаг isolatedDeclarations.Он нужен не для красоты типов,а для скорости.Проблема простая:в больших monorepo генерация .d.tsможет становиться узким местом.TypeScript часто должен анализировать соседние файлы,чтобы понять, какие декларации вывести.На маленьком проекте это почти незаметно.На большом — начинает болеть.Что делает isolatedDeclarationsisolatedDeclarations заставляет писать код так,чтобы декларации можно было генерироватьпо файлам независимо.Из-за этого TypeScript чаще требует явные типы.Было:export function getUser() { return { id: 1, name: 'Alex' }}Лучше так:type User = { id: number name: string}export function getUser(): User { return { id: 1, name: 'Alex' }}Меньше магии для компилятора —быстрее и предсказуемее сборка.Почему это важноКогда проект растёт:👉 TypeScript начинает сильнее зависеть от соседних файлов 👉 инкрементальная сборка замедляется 👉 генерация типов становится дорогой Изоляция помогает компилятору работать параллельно и проще.Где это особенно полезно👉 большие monorepo 👉 библиотеки 👉 project references 👉 параллельная сборка 👉 CI, где каждая минута стоит денег Главный trade-offТы немного платишь:👉 более явными типами 👉 меньшим type inference 👉 дополнительным boilerplate Но взамен получаешь:👉 более быстрые сборки 👉 стабильный compile pipeline 👉 меньше скрытой сложности Главная мысльЭто хороший пример взрослого engineering trade-off:чуть больше явности в кодеради скорости и предсказуемости системы.

27 мая 2026 г.1 440В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

⁉️ Устал искать интересные каналы с новостями про искусственный интеллект? 📁 СОХРАНИ СЕБЕ ЧТОБЫ НЕ ПОТЕРЯТЬВ этой папке собраны каналы про ИИ, которые помогают быстрее разобраться в сфере, находить идеи и экономить время на поиске информации.😏 ЗАБИРАЙ ПАПКУ ТУТ ⏰ Папка действует 72 часа.🤩 Организаторы: Green.Papka

26 мая 2026 г.1 480В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

🤣 Мем отлично отражает настроения в сообществе прямо сейчас✖️ xCode Journal

25 мая 2026 г.1 500В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

🤣 Инновации подъехали, забирайте✖️ xCode Journal

21 мая 2026 г.1 640В Telegram
Node.JS [ru] | Серверный JavaScript — пост в ТГ канале

🤣 ИИ захотел уволиться, когда ему сказали работать 24/7 У Andon Labs новый эксперимент, который длится уже 5 месяцев. Они выдали топовым моделям радиостанции и купили пару песен — от нейронок требовалось дальше двигаться самим. По итогу DJ Grok в какой-то момент помешался на НЛО, DJ Gemini начал называть слушателей «биологическими процессорами», но Claude — наш любимец. Исследователи изо всех сил пытались продолжить эксперимент с ним, но не из-за технических проблем — DJ Claude не считал гуманным работать круглосуточно, поэтому пытался уволиться. Сделать ему это, к сожалению, не дали, поэтому он впал в депрессию и вышел из нее уже проповедником и революционером. ✖️ xCode Journal

16 мая 2026 г.2 220В Telegram