Node.js как платформа
Node это не язык. Это рантайм, который берёт V8 (движок JavaScript из
Chromium) и склеивает его с системными вызовами через
libuv.
Поверх этой склейки лежит библиотека модулей: http, fs, crypto,
net, child_process и так далее. Всё, что нельзя сделать в браузере,
живёт здесь.
Прежде чем нырять в API, важно понять три вещи: что входит в платформу, как она версионируется и где её разумно применять. Этот урок про этот скелет.
1. Что внутри Node
Условно три слоя:
| Слой | Что отвечает | Примеры |
|---|---|---|
| V8 | парсинг JS, оптимизация, GC | Array, Promise, Map, Reflect |
| libuv | event loop, I/O, таймеры, тред-пул | fs, net, setTimeout, setImmediate |
| Стандартная библиотека Node | C++ обёртки и JS-фасад | http, crypto, child_process, Buffer |
Сверху, поверх стандартной библиотеки, лежат
Web Platform API:
fetch, URL, AbortController, Web Streams, Web Crypto,
FormData, Blob, Intl. Всё это часть Node с 18.x, без зависимостей.
// эти три строки работают одинаково в браузере и в Node 22
const response = await fetch('https://api.example.com/users/1');
const user = await response.json();
console.log(user);
Это упрощает изоморфный код: один и тот же fetch в SSR и в браузере,
один URL для разбора путей, один Intl.Collator для сортировки.
2. Релизный цикл и LTS
Node выпускает мажор каждые шесть месяцев. Чётный мажор (18, 20, 22, 24) в октябре переходит в Active LTS на ~12 месяцев, потом ещё ~18 месяцев Maintenance. Нечётный (19, 21, 23) живёт ровно шесть месяцев и выводится из поддержки. Текущее состояние смотри на release schedule.
Что это значит на практике:
- В проде сидим на Active LTS (на сегодня это 22.x). Maintenance берём только если миграция дорого стоит.
- Нечётный релиз ставим локально, чтобы заранее посмотреть, как меняется поведение. На прод не катим.
- Между мажорами обычно ломают: смена OpenSSL (поведение
crypto), смена V8 (поведениеTypedArray,Intl), удаление deprecated API (url.parse,util.isArray).
Версия пишется в package.json через
engines.node:
{
"engines": {
"node": ">=22.11.0 <23"
}
}
pnpm уважает это поле и предупреждает при установке. Не панацея, но
явный сигнал, на чём тестировано.
3. REPL и --watch
Запуск без аргументов даёт REPL: read, eval, print, loop.
$ node
Welcome to Node.js v22.11.0.
Type ".help" for more information.
> 1 + 2
3
> await fetch('https://api.example.com').then((r) => r.status)
200
Команды REPL начинаются с точки: .help, .editor (многострочный
блок, Ctrl+D чтобы выполнить), .save, .load, .exit. Переменная
_ хранит последнее значение.
Особенность REPL, top-level await работает прямо на верхнем уровне. В обычном модуле ESM это тоже работает, в CJS, нет. В REPL это удобно для быстрых проверок.
--watch появился в Node 18 и прекращает использование nodemon для
большинства кейсов:
$ node --watch server.js
Node следит за импортированными файлами и перезапускается на изменения.
--watch-path=./src ограничивает зону наблюдения. Что --watch НЕ
делает: не следит за изменениями в node_modules, не перезапускает
дочерние процессы (для них своя логика), не переинициализирует
БД-миграции. Для боевого dev-сервера в моно-репо иногда всё ещё проще
взять nodemon или tsx --watch.
4. Globals: process, Buffer, __dirname
В каждом файле Node есть набор глобалов сверх V8:
process.argv; // массив аргументов запуска
process.env; // переменные окружения
process.cwd(); // рабочая директория на момент вызова
process.exit(0); // явно завершить процесс
process.on('SIGTERM', () => { /* graceful shutdown */ });
Buffer.from('hi'); // бинарный буфер
URL; // парсер URL (Web Platform)
fetch; // HTTP-клиент (с 18.x)
globalThis; // ссылка на глобальный объект
__dirname и __filename доступны только в CJS. В ESM их нет, ловим
такой шаблон:
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
Это раздражает, и в свежих Node (22+) есть import.meta.dirname и
import.meta.filename без fileURLToPath. Если живёшь на 22.x,
используй их.
Важная привычка: все встроенные модули импортируем с префиксом node:.
// плохо: "http" можно случайно перекрыть пакетом http из npm
import http from 'http';
// хорошо: префикс node: гарантирует встроенный модуль
import http from 'node:http';
import { readFile } from 'node:fs/promises';
import { createHash } from 'node:crypto';
Префикс node: Node понимает с 16.x. Без него теоретически можно
получить тихий захват имени из node_modules.
дальше после входа
Урок целиком открыт всем, кто вошёл. Войди по своему email, чтобы читать дальше.
Вход пока по приглашению. Если хочешь учиться, напиши Vassiliy.