Обновить
32K+

Node.JS *

Среда для запуска JavaScript-приложений

37,44
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Как соцсеть для Егоров превратилась в автономный город на Node.js и SQLite

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели13K

11 недель назад я начал делать социальную сеть, в которой гражданство зависело только от имени.

Если тебя зовут Егор, Георгий или одной из форм имени, происходящего от Georgios, то это место для тебя, 100%! Остальные становятся Наблюдателями: могут читать, реагировать, писать в личку, жить в своих районах — что-то вроде ВНЖ.

На этом месте проект вполне мог закончиться хорошей шуткой, которой и являлся ИЗНАЧАЛЬНО. Но пользователи начали спрашивать, кто здесь главный.

Так в Егороде появился мэр. Потом люди спросили, кто выбирает мэра. Появились выборы.

Затем — партии, депутаты, кабинет, указы, вето и импичмент, а социальная сеть начала подозрительно напоминать государство, состоящее преимущественно из Node.js, SQLite и людей по имени Егор.

Сейчас в проекте около 11,9 тысячи регистраций, обычный DAU — примерно 30–35 человек, кодовая база выросла примерно до 210 тысяч строк, 176 таблиц и 2625 тестов.

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

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

Читать далее

Steam глазами разработчика: OpenID из 2007-го, звёздочка в имени ножа и цена строкой в чужой локали

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели6.4K

«Просто прикрутить вход через Steam и цены из маркета» — примерно так это выглядит из бэклога. На деле: OpenID 2.0 образца 2007 года вместо OAuth, звёздочка ★ в имени ножа, из-за которой одно и то же название готовится для двух соседних эндпоинтов противоположными способами, и цена, приходящая строкой в чужой локали. Собрал все проблемы в одном месте.

Читать далее

Я написал сайт с кейсами CS2 целиком и выложил под MIT

Уровень сложностиСредний
Время на прочтение24 мин
Охват и читатели9.7K

Открыл кейс — получил предмет. Между этими двумя событиями лежат HMAC, миллион тикетов и RTP, который кто-то посчитал заранее. Я написал сайт с кейсами CS2 целиком и выложил под MIT: про то, где в «provably fair» проходит граница между «проверяемым» и «выгодным», и почему 0,023% перекоса я оставил осознанно.

Читать далее

Лучший хостинг для Node.js-приложений и Next.js-сайтов с SSR в 2026

Время на прочтение8 мин
Охват и читатели10K

В статье мы рассмотрим специализированные PaaS-облака и особенности хостинга сайтов с SSR (рендерингом на стороне сервера) на React (Next.js, Remix, Astro), Vue (Nuxt.js, Quasar) и Angular. Рассмотрим сильные и слабые стороны сервисов. А также рассмотрим хостинг у VPS и Serverless-провайдеров. И приведём пример деплоя Node.js приложения с BullMQ и Redis.

Читать далее

Как мы собрали корпоративный мессенджер на Matrix: инженерный дневник

Уровень сложностиСредний
Время на прочтение16 мин
Охват и читатели6.9K

Задача звучала просто: создать ВКС с jitsi и чатом нарисовать красивый интерфейс в корп стиле.

Решение — написать собственный тонкий веб‑клиент поверх matrix-js-sdk, который разговаривает с уже существующим Synapse‑сервером и Jitsi‑сервером, но выглядит и ведёт себя как часть внутреннего портала компании.

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

Читать далее

Рендеринг Angular‑приложения в Minecraft

Уровень сложностиСложный
Время на прочтение18 мин
Охват и читатели12K

Что потребуется, чтобы Angular-приложение отображалось в Minecraft и реагировало на действия игрока? Разбор собственной платформы и Renderer2, расчёта layout через Yoga, отрисовки текста и изображений блоками. В результате получается интерактивный прогноз погоды, которым можно управлять прямо из игрового мира.

Читать далее

Claude Code — Все статуслайны показывают тебя. Я сделал тот, который показывает других

Уровень сложностиПростой
Время на прочтение6 мин
Охват и читатели9.4K

В два часа ночи ты упираешься в лимит модели. Сессия на середине, мысль на середине, и до сброса окна ещё полтора часа. Ты сидишь и смотришь в терминал, где написано, сколько ты потратил токенов, сколько это стоило в долларах и сколько процентов контекста съедено.

Чего там не написано — что прямо сейчас ещё шестеро сидят и ждут того же сброса. И четверо из них тоже глубоко за полночь.

Про это и получился инструмент. Одна строка в статуслайне Claude Code:

Читать далее

Я 22 месяца двигал ставки в Telegram Ads руками, потом написал автомат. Он воевал сам с собой

Уровень сложностиСредний
Время на прочтение14 мин
Охват и читатели6.1K

За 22 месяца в Telegram Ads у меня накопилось 1 043 канала, 3 000 креативов и стопка скриптов вокруг кабинета: харвест справочника, скоринг каналов языковой моделью, степпер ставок и гейт по прогнозной цене подписчика. В какой-то момент объём подписок просел на треть без видимой причины. Две недели я искал её снаружи, а нашёл внутри: степпер поднимал ставку объявлению без показов, гвард через сорок пять минут ронял её обратно, и оба скрипта писали в лог успех. Разбор с кодом, конечным автоматом и граблями, включая тихо непринятый PATCH и мёртвую зону на 250 показах.

Читать далее

V8 startup snapshot: как правильно запустить JS-код на сервере

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели7.3K

Представьте типичную ситуацию. У вас есть сервер на каком-то языке (сейчас какой именно для нас не важно, но допустим, это Rust). И в нём по каким-то причинам нужно исполнить JavaScript-код. Например, фронтенд написан на React, и вы хотите рендерить HTML на сервере (SSR). Или есть бизнес-логика, которая проще пишется на JS. Или библиотека, которая существует только в npm, и переписывать её на Rust нет ни сил, ни желания. Таких примеров можно привести множество: markdown, dompurify, highlight.js и т.д.

Читать далее

Один контракт данных, разные адаптеры: как перестать писать миграцию магазина заново

Уровень сложностиСредний
Время на прочтение8 мин
Охват и читатели6.7K

Первый файл, который я получил при переезде своего магазина с InSales, парсер прочитал как одну длинную строку мусора. Выгрузка заказов оказалась в UTF-16 LE с BOM и табуляцией вместо запятой — ни один разумный дефолт не подошёл.

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

Отсюда вывод, к которому стоит прийти раньше, чем на третьем проекте: середина должна быть одна, а платформенная специфика — жить в тонком слое на входе. Ниже — как этот каркас устроен у меня, с кодом из работающего проекта: собственного магазина, который я перевёз с InSales на свой движок на Next.js и PostgreSQL.

Сразу оговорюсь про доставленные миграции: полностью пройдена одна — та, о которой пойдёт речь. Про требования к адаптерам под 1С‑выгрузки и товароучётные API дальше я говорю как о проектных требованиях к каркасу; готовыми кейсами они не являются. Это важно, чтобы вы правильно оценили вес каждого утверждения.

Резонный вопрос до всего остального: почему не готовый инструмент. Airbyte, n8n, коннекторы к товароучётным системам делают ровно это — вытащить, преобразовать, положить. Для регулярной синхронизации они и есть правильный выбор. Разовая миграция магазина отличается тем, что сложность сидит не в перекладывании строк, а в доменных правилах: как собрать заказ из нескольких строк, что делать с позицией, товара которой больше нет в каталоге, как при повторном прогоне не затереть свежие данные старыми. Эти правила всё равно пишутся руками, а в визуальной цепочке трансформаций их неудобно тестировать и нельзя перезапустить кусочком. Поэтому середина своя, а тонкими остаются края.

Читать далее

Тест проходил за миллисекунды. На настоящем файле тот же код думал минуту

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели7.7K

«👋».length === 2 — это знают все. Дальше все пишут честную функцию, которая ходит по строке по символам, а не по кодовым единицам UTF-16. И почти всегда она получается квадратичной: и длина, и обращение по индексу проходят строку с начала, поэтому обычный цикл по ним — это n²/2 шагов без единого вложенного цикла в коде.

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

Внутри: замеры роста, починка через один вопрос «есть ли в строке суррогатная пара», и почему тест на время здесь бесполезен, а тест на показатель роста — нет.

Читать далее

Из генерации — в переписку: доводим ответ ИИ‑агента до клиента и CRM на n8n

Уровень сложностиСредний
Время на прочтение13 мин
Охват и читатели9.6K

Всем привет!) Напомню: в первой статье я показал дебаунс на Redis, который склеивает дробные сообщения клиента. Во второй — модуль привязки «чат = сделка» и то, почему вебхуки стоит держать в изолированных ключах. Обе части заканчиваются примерно одинаково: «...и текст уходит ИИ‑агенту». Это, пожалуй, тот финал, на котором обычно ставят точку и заливают демо на GitHub... Но не в данном случае!)

Читать далее

Почему Deno быстрее Node.js: расследование

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели9.2K

На официальном сайте Deno (раздел Built for the real world) красуется любопытная табличка. Согласно их замерам, Deno уходит в отрыв от Node.js по HTTP аж в 1.65 раза:

Независимые тесты (denosaurs/bench, pkgpulse 2026, jsmanifest 2026) показывают похожую картину: Deno стабильно быстрее на HTTP-нагрузке. Я решил копнуть глубже и понять, где Deno получает преимущество по сравнению с Node.js.

Читать далее

Ближайшие события

Подмена страницы интернет-банка First Partner Bank на Standoff 365

Время на прочтение6 мин
Охват и читатели9.1K

Привет, Хабр! Будем знакомы — grizzzer, участник различных CTF-команд и независимый исследователь кибербезопасности. В этой статье разберу, как я реализовал критическое событие в банковском сегменте онлайн-полигона Standoff 365 — «Дефейс веб-сервиса ДБО First Partner Bank».

Покажу всю цепочку — от DNS-разведки до эксплуатации уязвимости server-side template injection (SSTI) в шаблонизаторе Pug и финальной подмены текста на главной странице.

Читать далее

IndexNow из Node.js: переобход без аккаунтов, и почему fetch обрывается там, где curl проходит

Время на прочтение6 мин
Охват и читатели6.2K

Чтобы сказать Яндексу «страница изменилась, приди посмотреть», аккаунт в Вебмастере не нужен. Есть протокол IndexNow: вы кладёте в корень сайта файл с ключом, шлёте POST со списком адресов — и поисковик приходит за часы вместо недель. Ни регистрации, ни OAuth, ни капчи. Реализуется тридцатью строками на Node.js без единой зависимости.

Ниже — рабочий скрипт целиком, шесть кодов ответа, которые он может получить, и три грабли, на которые я наступил, пока доводил его до состояния «запустил и забыл». Одна из них интереснее прочих: fetch в Node падает с fetch failed на том же запросе, который curl отправляет с первого раза.

Читать далее

Почему рекламный пост в Telegram нельзя публиковать через copyMessages

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели6.3K

Если бот копирует один и тот же пост в десять каналов, в Google Analytics все клики свалятся в одну кучу. URL у скрытой ссылки живёт не в тексте, а в MessageEntity, а copyMessages копирует его как есть. Ниже — как пересобрать пост под каждую площадку, не сломав жирный шрифт, эмодзи и health‑check.

Telegram умеет одно очень удобное действие: copyMessages. Берёте сообщение из чата A, кладёте в чат B — форматирование, медиа, альбом, скрытые ссылки, всё на месте. Для рассылок и зеркал это идеальный метод.

Для рекламы он ломает самое важное.

Рекламодатель покупает размещения в разных каналах и смотрит в свою аналитику: откуда пришёл клик. Если во всех десяти постах в text_link лежит один и тот же https://shop.example/sale, UTM бесполезен. Каналы неразличимы. Сделка неразличима. Дата размещения неразличима.

Как пересобрать пост и не убить UTM

410.chat — Одноразовый чат для двоих

Время на прочтение5 мин
Охват и читатели95K

Последние недели делал небольшой проект, который в итоге назвал 410.chat.

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

Обычно для этого мы всё равно идём в какой-нибудь мессенджер и фактически открываем другому человеку постоянный способ связаться с собой. Мне стало интересно сделать наоборот: контакт, который существует только пока идёт конкретный разговор.

Так появился 410.

Читать далее

Self‑hosted вместо подписок: асинхронная очередь для ИИ‑агента на n8n и Redis

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели6.6K

В прошлой статье я показал, как простой дебаунс на Redis спасает бюджет от дробных сообщений: клиент строчит «привет» — «сколько стоит» — «а есть другой размер» пятью сообщениями подряд, а LLM получает один склеенный промпт.

Читать далее

Заголовки товарной кампании Директа — это теги YML-фида: прослойка на Node вместо правки сайта

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели5.5K

Товарная кампания и смарт-баннеры Яндекс Директа не дают редактировать текст объявления в интерфейсе. Заголовок Директ берёт из тега <name> товарного фида, описание — из <description>, и оба тега писал сайт: под карточку товара, а не под рекламную ленту. В галерее видно около 35 знаков заголовка, жёсткий предел — 56, дальше Директ обрезает по символам. «Печеные яблоки, фаршированные медом и грецкими орехами» в объявлении выглядят как «Печеные яблоки, фаршированные медо».

Сайт при этом трогать нельзя: та же карточка ранжируется в поиске и стоит в чеке, у неё своя работа. Ниже — как мы вклинились между сайтом и Директом одним процессом на Node без базы данных, который хирургически подменяет ровно два тега в YML, зачем над генератором заголовков стоит валидатор с правилами модерации и человек на аппруве, и что из этого вышло за первые дни на реальном проекте: пекарня с доставкой по Москве, около пятисот позиций в фиде.

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

Читать далее

Управляемые корутины в TypeScript: как получить контроль над асинхронностью и памятью. Разбираемся во всех аспектах

Уровень сложностиСложный
Время на прочтение16 мин
Охват и читатели8.9K

Современный JavaScript / TypeScript сегодня, предоставляет мощный инструмент для асинхронного программирования, который знаком каждому - async/await на основе Promise. Он позволяет писать последовательный код и легко обрабатывать ошибки. Однако за простотой скрываются серьёзные ограничения, которые становятся критичными в высоко-нагруженных системах, играх, сложных пользовательских интерфейсах и приложениях, требующих предсказуемой производительности.

Представьте себе сервер, обрабатывающий тысячи запросов одновременно. Все они конкурируют за процессорное время. Как гарантировать, что запрос от клиента выполнится раньше, чем фоновая синхронизация? Как отменить долгую операцию, если клиент разорвал соединение? Как избежать пауз сборщика мусора при создании миллионов временных объектов? Нативный async/await не даёт ответов на эти вопросы - он лишь оборачивает асинхронные операции в удобный синтаксис.

В этой статье мы разберём, как кооперативные корутины (Coroutines) решают эти задачи на примере моей библиотеки ts-adaptive-coroutines, изучив каждый аспект по кирпичикам, посмотрев на инструмент, который добавляет в TypeScript адаптивные приоритеты, арены памяти, каналы, семафоры и много-поточность.

Читать далее