Node.js, начиная с 20.6.0, поддерживает env файлы. Пример запуска node --env-file .env --env-file .env.development. В целом, мы давно уже привыкли считывать env файлы с помощью библиотек, но у нативного способа есть одно преимущество - т.к. нативно Node.js считывает енвы перед запуском, то есть возможность описать NODE_OPTIONS. Раньше такой возможности не было (т.к. устанавливать опции надо до запуска ноды, а считывать через либы можно только после запуска ноды) и нужно было указывать разные важные для ноды вещи отдельно.
Для тех кто не знает что такое env-файлы. Это файлы, описывающие переменные окружения, которые будут использоваться для запуска приложения. Часто часть конфигов приложения (урлы до API, уровень логирования, ключи) выносят в переменные окружения, которые сохраняют в отдельном env-файле и из которого их в последствии устанавливают для приложения
The complexity of writing an efficient NodeJS Docker image
Хороший гайд про создание оптимизированного докер-образа для nodejs приложения. Докер образа построены на слоях - т.е. каждая команда в нем создает отдельный слой, который затем может кешироваться. При скачивании образа, где оптимизации не были применены, мы можем скачать много "лишних" слоев
В этом гайде шаг за шагом показано, как использовать особенности работы Docker себе во благо. Автор добивается ускорения сборки новой версии образа в 43% без кеша и 73% с кешом, а также уменьшения размера образа в 5 раз.
Примененные оптимизации:
Взять оптимизированный base для образа. Автор берет nodejs-slim, т.к. alpine хоть и меньше, несет с собой musl вместо glibc, из-за чего могут наблюдаться ошибки в работе кода
Использовать dockerignore
Использовать multi-stage сборку. Автор использует 3 стейджа.
Не устанавливать или удалять dev и некоторые другие "лишние" зависимости
Вынести установку пакетов из package.json в отдельные шаги. Т.е. вместо добавления всех исходников и установки пакетов, в образ сначала добавляются только package.json. Это позволяет улучшить кеширование (т.к. исходный код меняется часто, а package.json - нет)
Лично для меня новыми были 2 техники: установка пакетов с копированием только package.json (не совсем новое, но давненько про это не читал и не использовал) и запуск кастомного скрипта чтобы зафорсить кеширование определенных слоев (автор удаляет лишние зависимости из package.json, но это также можно использовать и для удаления или изменения полей, например version)
Testing the dark scenarios of your Node.js application
Обычно nodejs разработчики пишут авто-тесты на функционал: обрабатывают позитивные и негативные сценарии работы логики. Однако разработчики часто забывают про простые тесты, которые проверяют работу приложения вне конкретной функциональности
В статье описываются, какие простые и короткие тесты стоит писать на любое node.js приложение. Хотя в целом это касается не только node.js, но эта статья посвящена именно node.js и есть несколько специфичных кейсов
Какие тесты следует писать:
- The zombie process test: проверка, что приложение закрывает текущий процесс, если случилось что-то непредвиденное. Если приложение не убивает свой процесс в случае, когда оно не смогло инициализироваться, то может сложится ложное впечатление, что приложение работает (процесс то запущен), когда оно не смогло стартовать
- The observability test: проверка, на то что ошибки корректно уходят в логгер
- The 'unexpected visitor' test - проверка на обработку непойманных исключений (`uncaughtException`)
- The 'hidden effect' test - мы часто проверяем, что в случае успеха мы делаем какой-то сайдэффект (например, записываем данные в БД), но мы часто упускаем проверку, что в случае неуспеха мы НЕ выполняем этот сайдэффект
- The 'overdoing' test - проверка, что функционал не делает лишний сайдэффект. Очень близко к предыдущему кейсу, но немного про другое: проверка, что в случае успеха, делаются только нужные сайдэффекты, а ненужные - не делаются
- The 'slow collaborator' test - обработка таймаутов
- The 'poisoned message' test - проверка на обработку "сломанной" структуры данных. Часто мы предполагаем, что у нас есть контракт и все ему следуют, но что если это не так?
- Test the package as a consumer - мы пишем юнит-тесты на свои npm-пакеты, но это не гарантирует нам, что у пользователя все будет работать корректно. Например, мы можем криво сконфигурировать сборку. Поэтому следует проверять работу пакета с точки зрения пользователя - делая импорт пакета или вызывая его cli
- The 'broken contract' test - еще 1 тест на сломанный контракт. Когда я описывал "poisoned message" я сразу поднял уровень абстракции до сломанного контракта. Эти 2 пункта про сломанный контракт, но немного различны в нюансах (там - про сообщения из шины событий, здесь - про доверие OpenAPI спеке)
Статья, подробно рассказывающая, как дебажить node.js с помощью различных инструментов. Начиная от console.log и заканчивая подключением к дебагерру через Chrome DevTools и VSCode и работе в дебагере
Advanced Fastify: Hooks, Middleware, and Decorators
Статья про использование хуков, мидлварок и декораторов в fastify. Ниже приведу краткий пересказ.
Хуки используются, чтоб добавить кастомную логиу перед или после какого-то действия. Например, перед отправкой ответа можно добавлять служебные заголовки
Например
```
fastify.addHook("onSend", (request, reply, payload, done) = {
reply.headers({
Server: "fastify",
});
done();
});
```
Хуки можно навесить как глобальные, так и на отдельные роуты. Хуки могут быть связаны как с запросами или ответами, так и с циклом работы приложения.
Мидлварки позволяет добавить в цепь обработки запроса кастомную логику. Например, популярные использования для мидлварок - парсинг cookie или body у запроса. Fastify поддерживает expressjs-style мидлварок с помощью плагинов, но лучше использовать нативные fastify middlewares.
Например, подключение `cookie-parser` позволяет удобно работать с куками в обработчиках запросов.
```
import Fastify from "fastify";
import middie from "@fastify/middie";
import cookieParser from "cookie-parser";
const fastify = Fastify({
logger: true,
});
await fastify.register(middie);
fastify.use(cookieParser());
```
Также в fastify есть декораторы. По названию кажется что это еще 1 API для добавления логики к обработчикам запросов, но это не так. Декораторы позволяют добавлять новые свойства или функции к объекту fastify приложения, запроса или ответа. По сути, они позволяют добавить кастомное API во встроенные в fastify объекты. Например, можно добавить метод `isAuth` прямо в request, что звучит достаточно удобно.
Также fastify имеет встроенную поддержку валидации данных через JSON-схему
```
fastify.post(
"/users",
{
schema: {
body: bodySchema,
},
},
async (request, reply) = {
/* обработка запроса */
}
);
```
Если запрос не проходит валидацию, fastify отвечает 400 кодом с описанием, какое поле не прошло валидацию.
Если вам надо переехать на fastify с expressjs, то можно использовать плагин `@fastify/express`, который облегчает использование `expressjs` кода в fastify окружении.
Анализ производительности разных версий nodejs (16, 18 и кое-где 20).
Анализ проводился в трех категориях:
- Скорость работы внутрянки node.js
- Запуск опен-сорс бенчмарка для node.js
- Скорость работы сервера (без логики)
В целом результаты следующие:
- Node.js стал быстрее в большинстве кейсов. Где-то на чуть-чуть (5-10%), а где то на 400-500% (тесты на скорость доступа к переменной)
- Кое где Node.js стал медленнее. Например, чтение файла с utf-8 кодировкой намного медленнее чем с ascii кодировкой. Например, заметен регресс производительности в 18 ноде в работе с потоками и буферами. В 20 ноде частично пофиксено
Замеры производительности всегда синтетические. Даже если все графики показывают большое увеличение производительности, на реальных приложениях это скажется не так сильно (не стоит ожидать ускорения в 50-100%). Скорее стоит ожидать, что сама платформа становится все более производительной. Теперь при обнаружении проблем производительности намного меньше шанс, что проблема внутри node.js, а не в вашем коде
Рекомендую к прочтению тем, кто пишет на node.js. Возможно статья даст вам идеи, как ускорить ваше приложение.
Вышел Node.js 20. Из интересных новшеств:
- Экспериментальная модель разрешений. Теперь можно ограничить использование файловой системы, запуск процессов и тредов. Также планируют уметь ограничивать использовать сети и переменных окружения. В общем, фича из Deno переводится в node.js, что не может не радовать
- Новый тест раннер теперь считается стабильным, т.е. он доступен без флага, гарантируется что он более менее работает, а его API не будут сильно менять
- Появилась возможность упаковывать JS-приложения в бинарники. Т.е. можно взять и написать простой cli и затем упаковать его средствами ноды в готовый исполняемый файл (например exe для windows), который не требует установки node.js в ОС. В целом и раньше был способ упаковывать код + nodejs в бинарники, но теперь это реализовано самими node.js. Пока что фича эксперементальная и возможно что-то еще помют, потому что сейчас из доки не совсем понятны возможности фичи.
Хороший обзор нового встроенного в nodejs test runner'а. В обзора сравниванются функциональные возможности ранера по сравнению с существующими.
В целом, node:test выглядит достаточно неплохо:
- Есть watch режим
- Можно приладить кастомные репортеры, которые умеют обрабатывать Tap репорт
- Есть базовые асерты, но вывод ошибок в консоль неудобен. Ошибка есть, но где именно разница - непонятно.
- Есть возможность распаралеллить тесты в рамках 1го файла.
- Есть функционал для мокирования. Как функций так и целых модулей
- Есть возможность указать отдельный лоадер для запуска, например, ts файлов
- Немного странное решение с выполнением определенных тестов через `only` - по умолчанию раннер игнорирует эту опцию и учитывает её только с определенным флагом. Это расходится с уже устоявшимся паттерном "если в файле есть only - то только они и запускаются, на прекомите запрещаем комитить only"
- Есть сбор code coveraage
В общем, выглядит достаточно неплохо и не требует установки кучи пакетов, что уже плюс.
Обзор популярных пакетов для nodejs cli приложений.
Рассматривается, а что вообще есть популярного для cli приложений, как это разрабатывается и поддерживается и какие есть характеристики. Это очень поверхностный обзор, но он может быть интересен.
Вышел публичный релиз WebContainer API.
Если коротко - webcontainer позволяет запускать node.js приложения прямо в браузере. И все это сделано с помощью wasm. Там есть разные ограничения, но текущие примеры вызывают уважение - можно прямо в браузере собрать код, запустить expressjs сервер, сделать линтинг.
Технология открывает новые возможности для веб-приложений. Но Stackblitz явно нацелены на запуск полноценного окружения или IDE прямо в браузере, чтобы пользователи могли собрать приложение, не требуя запуска кода в какой-нибудь железячной виртуалке.
Tao of Node - Design, Architecture & Best Practices | Alex Kondov - Software Engineer
Тао of Node - opinionated список бест практиксов для разработы сервисов на node.js.
Большинство практик действительно несут объективную пользу. Остальные являются скорее выбором автора среди альтернатив (поэтому список и opinionated).
Некоторые практики описаны достаточно подробно (с примерами кода), некоторые слишком утрировано. В целом получается скорее обзор на практики.
Практики разделены на 4 группы.
Общие. Например, валидируйте запросы, разделяйте приложение на слои, обрабатывайте ошибки. Они практически все хороши и являются бест практисами в разработке в целом, даже не привязываясь к nodejs)
Далее идут инструменты. Тут советы уже весьма opinionated, но в целом все равно хороши
Затем идет блок про тестирование, который, достаточно короткий, но на мой взгляд, содержит очень правильные рекомендации по тестированию nodejs - вкладываться в test coverage, тестировать интеграционными тестами, бизнес-логику покрывать юнит-тестами.
Заключительный блок про перформанс. Он достаточно короткий, но сводится к тому, что перформансом надо заниматься тогда, когда увидел где и от чего он страдает.
Могу рекомендовать к прочтению тем, кто окунается в nodejs разработку. Опытные разрабы также могут просмотреть список, но большую часть они скорее всего уже знают
Hyperstack is a modern full-stack Node.js web framework for the pragmatic programmer
Вышел новый веб-фреймворк для nodejs - Hyperstack.
Вдохновлен rails и уже имеет в себе всё, что нужно разработчику для комфортной и быстрой разработки:
- контроллеры
- orm (если я правильно понял)
- апи для написания автотестов
- апи для создания джоб
An overview of Node.js: architecture, APIs, event loop, concurrency
Новый пост от Dr. Axel Rauschmayer, теперь про то, как работает Node.js. Рассмотрены следующие моменты:
- Архитектура Node.js (где там Node.js, где v8, а где С++ код)
- Встроенные возможности и глобальные переменные
- Как работает event loop и асинхронное взаимодействие
- Разница между асинхронным и синхронным I/O в рамках libuv
- Возможности для многопоточности в Node.js
Рекомендую, если вы хотите ознакомиться с Node.js или если вы работает на Node.js и вам интересно, как устроена внутренняя асинхронность
Новый туториал от Dr. Axel Rauschmayer, в этот раз про то, как работают запускаемые файлы (bin) в npm пакетах. Очень подробно рассказано, как же так выходит, что вы пишете `npx somepackage`, а npm запускает что-то конкретное.
Рекомендую к прочтению. Там и про то, как регистрировать bin файлы в пакете, и куда они устанавливаются и как этим управлять, и как проверять пакеты через `npm link` (и альтернативы линковке) и про кэши. В общем, ИМХО, очень полезная статья для любого фронтенд-разработчика.
Popular Node.js patterns and tools to re-consider | Practica.js
Статья от автора книг "JavaScript testing best practices" and "Node.js best practices". Он рассматривает популярные в node.js мире паттерны и инструменты и оценивает их с точки зрения, насколько это актуально сейчас и какие есть альтернативы.
Короткий список:
- Dotenv для загрузки конфига из .env файла = Предлагается использовать `convict`
- Жирный сервис, вызываемый из контроллера = Предлагается декомпозировать, создавая use-case
- Закинуть все в DI (например в Nest.js) = Предлагается закидывать только то, что нужно конфигурировать
- Passport.js = Слишком жирное решение, вместо комбайна следует использовать точечные библиотеки
- Supertest для тестов api = http-библиотека + assert'ы от фреймворка тестирования
- Декораторы fastify для функций (не для обработчкиов реквеста или веб-утилит) = корректная декомпозиция
- Логирование из catch = Дополнение контекста ошибки в catch, но единое логирование в глобальном обработчике
- Использование morgan = Используйте удобный вам логгер, напишите руками небольшую мидлварку
- Условия на `NODE_ENV` = следует избегать
Я очень сильно утрировал. Какие-то пункты очень странные. Я, например, не знал, что кто-то использует API fastify, потому что лень самим декоратор написать над функцией. Но во многих пунктах полезно прочесть не конкретную рекомендацию (они как раз неинтересны), а то, почему текущий паттерн - может быть плох, и на каких принципах следует основывать выбор паттерна или инструмента
Deeper testing of Bun's performance and compatibility against Node.js
Продолжение сравнения bun и node.js. Статья от того же чувака, которого я уже постил. И даже кейс тот же - он переводит свой сайт. Но эта статья - она типа v2.0 прошлой статьи про bun vs node.js
Что тут нового:
- Разбор перформанс тестов. Например, там есть набор тестов, тестирующих скорость доступа к sqlite, т.е. тестируются библиотека для nodejs, библиотека для deno и встроенное в bun нативно решение на rust
- Автор чуть более подробно рассказывает про то, как он тестировал совместимость bun и node.js на своем проекте. К чести bun, автор оформлял им реквесты в github и к моменту публикации статьи некоторые уже были пофиксены.
- Автор сделал свой бенчмарк (или он у него уже был), где проверяются основные инструменты, использующиеся в его проекте (рендер блога). Из 11 сценариев на bun он смог перенести всего 6. Но при этом те, которые были перенесены - в целом выполнились быстрее (в среднем на где-то 10%, но один бенч выполнился в 2 раза быстрее)
Далее автор описывает свой опыт работы в Java, где есть спека и есть куча рантаймов, его имплементирующих. И есть тесты для этих рантаймов. И вот как было бы круто, если бы была спека node.js (хотя он не язык и ему незачем) или хотя бы какая-то хорошая табличка совместимости, за которой можно следить.
Custom ESM loaders: Who, what, when, where, why, how
Оказывается, в NodeJS есть возможность определять кастомные загрузчики для esm файлов. Пока, правда, это фича считается экспериментальной
Что это значит и как это работает?
NodeJS поддерживает ES modules. Но некоторые модули мы не можем заимпортировать в nidejs просто так. Например, нельзя просто так, без уважения, делать импорт css-стилей для реакт приложения или импорт TS файла. Для решения этой задачи можно взять какой-нибудь инструмент типа babel, webpack, vite etc. Но также в NodeJS есть возможность указать кастомные загрузчики модулей, которые могут помочь в этой ситуации.
В статье рассматривается загрузка css-кода в рамках запуска тестов в mocha.js. Для решения этой задачи мы могли бы заиспользовать какие-нибудь плагины к mocha или сделать обвязку вокруг mocha, которые подготовят все файлы, предсобрав их с помощью какого-нибудь препроцессора.
Но решения для этой задачи можно написать свой кастомный загрузчик. Для тестов нам не нужно получать честный css, достаточно получить только имена классов. Такой загрузчик относительно легко написать, при этом не нужно заводить сложные инструменты для решения этой простой задачи.
В рамках статьи также добавляются лоадер на TS файлы и лодар для загрузки сетевых ресурсов (`import blabla from 'https://blabla.com'`).
Само применение лоадеров выглядит вот так
```
node \
--loader typescript-loader \
--loader css-loader \
--loader network-loader \
app.tsx
```
Применение этих лоадеров позволило в 8 раз ускорить работу тестов.
Также в статье приводятся ссылка на другие интересные лоадеры.
Рекомендую посмотреть статью, если вы интересуетесь nodejs или кастомными решениями для автоматизации (возможно кастомные лоадеры помогут вам решить какие-то проблемы)
Isolating and fixing a memory leak in a real Node.js web application
Короткий гайд про то, как найти утечку памяти в nodejs приложении.
Рекомендуемый алгоритм такой:
- Взять один из инстансов прод приложения после старта, вывести его из под трафика, сделать снапшот. Создание снапшота - ресурсоемкая операция. Поэтому мы выводим инстанс из под трафика и также нужно следить, чтобы инстансу хватило памяти так как для создания снапшота необходимо примерно столько же памяти, сколько уже используется приложением
- Ввернуть трафик на инстанс
- Снова вывести, сделать второй снапшот, сравнить их и провести анализ
При этом в статье есть ссылки на инструменты для этого и ссылки на три больших и полных гайда по устранению утечек памяти
Вышел fastify 4.
Из важных изменений:
* Ускорение холодного старта
* Улучшение перформанса.
* Обновление Pino
* Задепрекейтили кучу разных способов вызвать listen, оставили основные 3
* Изменили композицию обработчиков ошибок
* Пофиксили разные случаи, когда было странное поведение
GitHub - extremeheat/JSPyBridge: 🌉. Bridge to interoperate Node.js and Python
Вышел 1.0.0 релиз тулинга, позволяющего:
- запускать JS из Python
- запускать Python из node.js
Причем делается не просто как exec из nodejs API, а имено импорт сущностей одного языка в другой язык.
Выглядит интересно, хотя очевидно, что это очень нишевая история и у нее куча ограничени
Неплохая статья про то, почему fastify должен восприниматься как стандарт для создания вбе-серверов на nodejs вместо express
Собственно вся статья сравнивает fastify с express. Когда-то мне не хватало именно такой статьи чтобы ссылаться на нее при рекомендации взять fastify вместо express или koa.
В статье упоминается что fastify лучше чем express потому что:
- Более адекватное API для расширения функционала
- Перформанс
- Некоторые вещи есть пря внутри fastify
Того, чего нет в статье, но что я оценил в свое время в fastify
- typescript first
- встроенное апи для тестирования сервера. Вместо того чтобы приседать с поднятием сервера через какой-нибудь supertest, в fastify из коробки есть возможность эмулировать обработку запроса, и эмулированный запрос пройдет все стадии обработки также, как и настоящий
Небольшая история от RudderStack о том, как они ускорили запуск nodejs приложения в разы.
Если коротко, то ребята используют nodejs как бекенд, но при деплое он запускается около 5 минут, что очень плохо.
Просто представьте, что вы деплоете код, а узнаете о том, что он неправильно работает только через 2 минуты. А потом еще катите фикс и, не смотря на вашу скорость делания самого фикса, ждете еще 2 минуты пока новая версия приложения попробует запуститься.
Вообще, это звучит довольно странно т.к. nodejs имеет один из самых низких показателей времени старта приложения на AWS (согласно доклада чувака из Amazon на frontendconf)
У ребят оказась проблема в том, что для запуска приложения они использовали ts-node. ts-node - это либа, которая запускает node.js и "учит" его транспайлить typescript код, позволяет запускать nodejs на typescript без предварительной компиляции.
Это очень удобно, но очень медленно. Если у вас много кода, то приложение перед запуском будет вынуждено его весь скомпилировать. У меня есть пара пет-проектов и я раньше тоже не парился с компиляцией ts кода и просто деплоил docker-образ, в котором запускался ts-node. Для моих пет проектов не страшно иметь небольшую задержку при запуске. Но оказалось, что это также сьедает кучу памяти, а мой VPS имеет ее не так уж много.
В общем, не используйте ts-node в продакшне - это замедляет запуск приложения и увеливает потребление памяти.
Инженеры из RudderStack тоже это поняли, даже сделали профилирование. Они попробовали предварительно скомпилировать код с помощью tsc и результат им не понравился. Конкретно, там есть проблема с тем, как tsc компилирует импорты.
Тут я бы сказал, что надо просто взять babel\swc и немного подконфигурировать этот сетап и стало бы просто замечательно. Но ребята взяли webpack. Возможно у них была сложная ситуация с кастомными правилами транспиляции кода. В этом случае действитеьно легче взять webpack.
Как итог, заменив ts-node на webpack ребята значительно ускорили свое приложение.
Что в этой истории интересного:
- Не надо использовать ts-node в продакшне
- Посмотрите, как они запрофилировали запуск приложения
- Посмотрите, как они искали решение и на основе чего их отбрасывали
Эта история - хороший пример поиска и решения проблем.
A Built-in Test Runner Is Coming to Node and Why You Should Care
Важная новость. В NodeJS решили сделать свой собственный, встроенный test runner.
Так исторически сложилось, что NodeJS поставлял библиотеку для асертов, но не поставлял ничего для тестирования. Т.е. все, что связано с авто-тестами было вынесено для реализации сообществом. И сообщество за все это время успешно опробовало различные способы тестировать код, а какие-то стали чем-то вроде профессионального стандарта (имею в виду jest и mocha)
Теперь сообщество NodeJS решило, что пора внести в NodeJS возможность запускать тесты из коробки. При этом у проекта нет цели с нуля создать самый лучший фреймворк тестированиял. Вместо этого NodeJS сосредоточится на базовом функционале, который нужен всем фреймворкам тестирования и который используется большинством популярных решений.
В NodeJS войдет:
- Функция `test` для определения тестов и сьютов
- Поддержка асинхронных тестов
- Возможность запустить тесты проекта и указать какие конкретно
- Гарантия изоляции тестов
- Возможность запускать тесты в несколько потоков
Пощупать test runner уже можно в nightly билдах NodeJS. Лично я надеюсь что это войдет уже в следующий LTS.
Introducing WebContainers: Run Node.js natively in your browser
Stackblitz сделали возможным запуск nodejs прямо в браузере. На wasm написано окружение, умеющее запускать nodejs приложения. Сам stackblitz разрабатывают онлайн IDE. Вместе это позволяет писать nodejs код, запускать сервер и дебажить его прямо в браузере.
Из фичей:
- нативная интеграция с дебагером хрома
- чистое окружение при релоаде вкладки
- быстрая установка нпм пакетов
- возможность открыть код проекта, сразу его запустить и посмотреть как это работает. Звучит круто для кодревью
Рекомендую к чтению, очень интересный концепт
FoalTS - nodejs веб-фреймворк. Это как NestJS, если представить что NestJS не срисовывали с типичного Java.
Из коробки есть практически все, что нужно при разработке серверов.