Node.js Recipes
3.23K subscribers
173 photos
7 videos
1 file
610 links
Download Telegram
Как правильно настроить TypeScript в Node.js проекте?
#typescript #best_practice

Как tsconfig.json появился в вашем проекте? Наиболее распространенные варианты:
1. Сделан фреймворком. В моем тех стэке, это npx @nestjs/cli new project-name
2. Результат команды ./node_modules/.bin/tsc --init
3. Копирование из другого проекта.

Каждый из этих вариантов, не учитывает под какой версией #nodejs вы будете запускать ваш проект. В результате этого, вы не можете использовать новые JavaScript конструкции.

TypeScript Wiki рекомендует такие настройки под Node.js v14:
{
"compilerOptions": {
"lib": ["ES2020"],
"module": "commonjs",
"target": "ES2020"
}
}

Для сравнения стандартная настройка Nest.js:

{
"compilerOptions": {
"module": "commonjs",
"target": "ES2017"
}
}

После изменения конфигурации у меня заработал Array.flat, ради которого я изучал этот вопрос. Полный список новых поддерживаемых фич ECMAScript можно посмотреть в исходниках typescript@src/lib.
Как конфигурировать Node.js приложение?
#best_practice #package #devops

TL;DR Конфигурация хранится в переменных окружения без значений по умолчанию. Если какой-либо переменной нет или формат не верный, то приложение не должно запускаться. Требуемые переменные описываются в env.example. Реализация dotenv-safe

Теория
Каждому #nodejs разработчику следует знать 12 факторный манифест . Следование его принципам позволит создавать масштабируемые веб-приложения и комфортно сотрудничать с DevOps инженерами. Третий фактор говорит, что конфигурация должна храниться в настройках окружения (env vars). Рекомендую с этим фактором ознакомиться, там подробно описано почему стоит использовать именной такой подход.

Применение
Значения всех переменных окружения доступны:
- в терминале с помощью команды env
- на уровне Node.js кода с помощью объекта process.env.

Значения конкретной переменной <NAME> доступно:
- в терминале с помощью $<NAME>
- на уровне Node.js кода с помощью process.env.<NAME>

Установить переменные окружения можно:
– посредством команды export. Например: export NODE_ENV=production . Результат команды не сохраняется между сессиями консоли. Для внесения долгосрочный изменений в окружение команду необходимо прописать в .bashrc или его аналог.
– посредством команды source
– В момент запуска процесса как ИМЯ=ЗНАЧЕНИЕ перед самой командой. Пример: NODE_ENV=production DEBUG=0 node src/index.js Работает как в терминале, так и в npm scripts.
– Изменением значений в process.env уже во время работы приложения.
 
.env
.env файл с переменными окружения используется для упрощения локальной разработки. На всех других окружениях его использование является плохой практиков. .env никогда не должен храниться в git репозитории. Поддержка есть во всех IDEA. Для консоли есть расширения, например autoenv. На уровне кода общепринятым пакетом является dotenv. Он вычитывает в process.env значения из .env, но не заменяет уже существующие значения.

.env.example
.env.example описывает все требуемые переменные окружения для работы приложения. Там можно и нужно делать комментарии. Это single source of truth для вашего DevOps инженера. Его необходимо хранить в git. Если приложение, не имеет какого-либо из ожидаемых переменных, то оно не должно стартовать. Fail fast! Этот функционал обеспечивает пакет dotenv-safe, который является оберткой над dotenv.

Советы по уменьшению количества переменных
– Используйте connection string. Пример: DB_URL=postgresql://postgres:password@localhost:5432/database
Используйте JSON в значениях переменных. Пример: const stripeConfig = JSON.parse(process.env.STRIPE_CONFIG)
Используйте значения через запятую. Пример: const adminList = process.env.ADMINS.split(',')

Распространенные ошибки
– Отсутствие приведение типа. Все ключи объекта process.env имеют значения типа string. Пример, вопреки ожиданиям при запуск с SOME_FEATURE=false код if process.env.SOME_FEATURE ... будет исполнен.
– Использование значений по умолчанию. Пример, const logLevel = process.env.LOG_LEVEL || 'info'. Это приводит к неявной конфигурации и дорогостоящим ошибкам.
– Ошибка в путях к .env из-за использования относительных, а не абсолютных путей.
– Ошибка характерная для FE разработчиков: не понимание разницы между переменными окружения в build-а и run time.
– Ошибка характерная для microservice разработчиков в проектах с Service discovery: различие локального и прод окружений. Необходимо запускать Consul или его аналоги через Docker.
​​Какую версию npm использовать?
#best_practice #npm #tech_stack

Node package manager – npm регулярно показывает Update available. Следовать этому оповещению и обновлять npm не стоит. Вместе с версией #nodejs идет конкретная версия npm и именно ее следует использовать. Версии указаны в таблице.

Пример текущей LTS комбинации: Node.js v14.16.1, npm v6.14.12. Этому следуют все:
- установочные бинарники,
- nvm (node version manager) и его аналоги,
- Docker image

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

Если вы используете yarn, то такой таблицы нет. Лучшей практикой будет использование версию прошитой в Docker image. Например, для Node.js v14.16.1 это будет yarn v1.22.5
Как узнать источник соединение в БД?
#best_practice #database

TL;DR Всегда ставьте application_name в конфигурации подключения к БД.

Сегодня обсудим малодокументированную фишку баз данных. При создание соединения можно указать application_name. Это аналог http заголовка User-Agent в мире баз данных. Он виден в списке соединений и slow query log. Приведу примеры кода для PostgreSQL.

Без ORM:
import { Client } from 'pg';
const client = new Client({
connectionString: process.env.DB_URL,
application_name: 'my-app@0.1.0'
});

TypeORM
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
const dbConfig: PostgresConnectionOptions = {
type: 'postgres',
url: process.env.DB_URL!,
extra: { application_name: 'my-app@0.1.0' },
entities: ...
};

Sequelize
import { Sequelize } from 'sequelize';
const sequelize = new Sequelize(process.env.DB_URL!, {
dialect: 'postgres',
dialectOptions: { appName: 'my-app@0.1.0' }
});


Теперь вы сможете увидеть application_name в pg_stat_activity с помощью запроса
SELECT * FROM pg_stat_activity WHERE datname = '<db_name>';

Аналогичные параметр есть у всех клиентов баз данных.
Например, MongoDB использует appName, а Redis – CLIENT SETNAME.
Что не стоит делать в PostgreSQL?
#best_practice #database

Сегодня у нас в рекомендациях ссылка Don't Do This из википедии PostgreSQL. Каждый из пунктов выдержан в стиле что не стоит делать, почему и в каких случаях все же стоит нарушить эту рекомендацию. Отлично подходит, чтобы отправить коллеге который таки решил сделать что-нибудь плохое.