Как я всегда здесь делаю, давайте поговорим об очередном сенсационном релизе Node.js, версия 18 была анонсирована в апреле 2022 года! И вы, наверное, спрашиваете себя: ну и что?
Для тех, кто занимается JavaScript или нет, эта версия Node.js принесла много очень интересных изменений в саму среду исполнения, и некоторые из этих изменений настолько важны, что могут вдохновить другие среды исполнения на то же самое, так что давайте посмотрим на все, что мы имеем!
Но сначала, как я всегда делаю в подобных статьях, давайте немного подробнее расскажем о процессе выпуска Node.js.
Процесс выпуска Node.js
Как и многие другие крупные проекты, которые очень сильно зависят от сообщества, Node.js имеет чрезвычайно организованный график и организацию новых версий и релизов.
Все четные версии считаются «готовыми к производству», в то время как нечетные версии являются версиями для тестирования и разработки. Другими словами, версии с нечетными номерами — это как среда постановки, то есть более структурированное тестирование, чтобы освободить место для производственной версии. Обычно в таких релизах новые функции тестируются сообществом, а через некоторое время они переходят в стабильную версию.
График выпуска Node.js в 2022 году
Peer-релизы выпускаются в апреле и обозначаются как Current до октября, когда они становятся активной версией, а предыдущая peer-версия переходит в статус maintenance.
Разница между активной и текущей версией заключается в том, что активные версии считаются LTS или Long Term Support, которые получают обновления безопасности и поддержку в течение 3 лет, всегда есть 3 версии в статусе поддержки и одна LTS версия, все версии старше 3 лет являются устаревшими, что и произошло с версией 10 теперь, когда вышла версия 18.
Все даты и все планы по предыдущим и следующим версиям можно посмотреть на официальном сайте релизов.
В настоящее время таково состояние окружающей среды:
- Node v12: достиг конца срока службы в апреле 2022 года
- Node v14: Продолжает поддерживаться до апреля 2023 года, затем будет заброшен
- Node v16: В настоящее время это LTS-версия до октября 2022 года, затем она переходит на обслуживание до апреля 2024 года, после чего от нее откажутся.
- Node v18: Это текущая версия до октября 2022 года, когда она станет следующей LTS до апреля 2025 года.
Глобальная выборка доступна по умолчанию
В версии Node 17 было объявлено, что API fetch
, уже присутствующий в большинстве браузеров для JavaScript, придет и в Node. Таким образом, нам больше не понадобятся внешние пакеты, такие как известные axios
и got
, чтобы иметь возможность делать HTTP-запросы более простым способом, не нуждаясь в родном HTTP-клиенте Node — который, скажем так… Немного сложный.
Этот клиент реализован с помощью одной из самых интересных библиотек, когда-либо созданных для Node, undici, клиента HTTP/1.1, написанного с нуля, полностью на JavaScript для Node.js.
Эта реализация была первоначально добавлена через экспериментальный флаг в Node, который включал эту функциональность, но теперь у нас fetch
включен по умолчанию.
Вот как мы можем использовать этого нового клиента:
const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
const data = await res.json();
console.log(data);
}
В дополнение к fetch
были добавлены другие глобальные переменные: Headers
, Request
, Response
и FormData
.
Будьте осторожны, чтобы не спутать нативные типы
Request
иResponse
с теми же типами, что и в Express, когда мы используем TypeScript
Другие глобальные API
- Добавлена экспериментальная версия WebStreams API, позволяющая использовать потоки нативно в веб-средах без использования локальных интеграций
- Новый экспериментальный тип
Buffer
,Blob
, также был помещен в глобальный APIs - Для добавления в
worker_threads
,BroadcastChannel
теперь также является открытым глобальным API
Нативная программа для запуска тестов
Один из самых крутых API, который лично я ждал много лет, — это поддержка нативного запуска тестов. Правильно, больше никаких mocha
, jest
, ava
и других.
Теперь вы можете запускать все тесты программного обеспечения, которые у вас уже есть, с помощью модуля test
, который может быть загружен, только если обозначен префиксом node:
:
import test from 'node:test'
import assert from 'node:assert'
test('top level test', async (t) => {
await t.test('subtest 1', (t) => {
assert.strictEqual(1, 1);
});
await t.test('subtest 2', (t) => {
assert.strictEqual(2, 2);
});
});
API полностью документирован, конечно, пройдет некоторое время, прежде чем он достигнет уровня других библиотек, таких как jest
, если вообще достигнет.
Я говорю так, потому что основная идея этой библиотеки заключается не в том, что она заменяет основные библиотеки, которые мы уже используем, например, те, о которых я говорил ранее, а в том, что она снижает барьер входа для создания автоматизированных тестов с помощью Node.js. Таким образом, все больше систем смогут полагаться на автоматизированные тесты и станут гораздо более безопасными.
Однако есть некоторые соображения по реализации, которые мы должны рассмотреть:
- Node запустит все файлы тестов, когда вы инициализируете среду выполнения с флагом
--test
, каждый тест будет выполняться в собственном изолированном процессе. - Тесты могут быть синхронными или асинхронными, синхронные тесты считаются корректными, если они не вызывают исключений. Асинхронные, как и ожидалось, если они не отвергают Promise
- Подтесты, созданные с контекстом
t
, который мы передаем в примере, будут выполняться так же, как и родительский тест - Если вы хотите пропустить тест, просто отправьте объект options с флагом
{ skip: 'message' }
к объекту test, как в этом примере:
test('pulado', { skip: 'Esse teste foi pulado' }, (t) => {
// nunca executado
})
В настоящее время объект options принимает три типа ключей:
Бегунок тестирования пока носит экспериментальный характер и работает за флагами, но это должно измениться в следующих версиях.
Префикс node:
Давайте сделаем набросок, чтобы объяснить особенность, которая не обязательно появилась в самом Node 18, однако это было важное изменение, которое создает прецедент, которому можно следовать в будущем для всех других модулей.
В примере, который я приводил выше, вы можете заметить, что мы импортируем модули assert
и test
с префиксом node:
. Это начало того, что называется основными модулями только с префиксом.
Это существовало и раньше, но не было обязательным, до сегодняшнего дня все нативные модули, такие как fs
, assert
и другие, работали одинаково, независимо от того, импортировались они с префиксом node:
или нет. Сегодня это уже не так.
node:test
— это первый нативный модуль, который может быть импортирован только при использовании префикса node:
, если вы не используете префикс, среда выполнения попытается загрузить модуль под названием test
, который считается модулем userland, то есть модулем, сделанным сообществом.
Это замечательное изменение, поскольку с появлением префикса node:
в новых модулях (и, возможно, в качестве изменения в будущем релизе для старых модулей), у нас появится возможность иметь два модуля с одинаковым именем, один в userland, а другой в ядре Node.
Таким образом, поскольку модули ядра имеют приоритет над пользовательскими модулями, разработчики Node смогут создавать модули, не заботясь о том, что имя модуля уже существует, например, в NPM.
С другой стороны, это создает две проблемы, первая из которых заключается в том, что мы имеем явное несоответствие между модулями, которые уже существуют, такими как fs
и http
, и новыми модулями, которые только используют префикс. Решением этой проблемы должно быть обязательное использование префикса для всех модулей, а не только для новых.
Кроме того, возникает проблема безопасности: typosquatting, когда кто-то создает модуль в NPM с тем же именем или именем, очень похожим на оригинальный пакет — например, называя express
a expres
в NPM — так что ничего не подозревающие разработчики могут загрузить вредоносный пакет вместо оригинального пакета. Эти проблемы исходят не от команды Node, не в последнюю очередь потому, что NPM уже имеет некоторые блокировки безопасности против этого, но в любом случае, это то, о чем стоит упомянуть.
Пользовательские снимки
В версии 18 появилось нечто очень интересное — использование моментальных снимков во время сборки среды выполнения Node. Это очень интересно для тех, у кого много команд разработчиков и кому необходимо синхронизировать и даже улучшить производительность продукта между командами.
Начиная с этой новой версии, можно будет скомпилировать бинарный файл Node.js с пользовательским стартовым снимком, используя флаг --node-snapshot-main
. Например:
$ cd /path/to/node/source
$ ./configure --node-snapshot-main=marked.js
# Build do binário
$ make node
Сборка бинарного файла Node путем передачи точки входа, например marked.js
, которая является рендерером Markdown, инициализирует модуль и загрузит его в globalThis
, и вы сможете использовать его нативно, например:
const html = globalThis.marked(process.argv[1]);
console.log(html);
И запустите двоичный файл, созданный с помощью:
$ out/Release/node render.js test.md
Конечно, это для очень специфических случаев использования, когда вам нужно, фактически, перекомпилировать всю среду выполнения Node, чтобы включить одну или несколько точек входа модуля непосредственно в двоичный файл для улучшения времени компиляции.
В качестве продолжения, команда работает над PR #42617 и #38905, которые соответственно
- Позволяет загружать модуль без скрипта инициализации, который превратит весь бинарник в пользовательское приложение, таким образом, ваш конечный бинарник будет работать как
$ out/Release/markedNode test.md
, что на шаг ближе к полным бинарникам Node, как это делает сам Golang - Позволяет добавлять точки входа без необходимости перекомпиляции всего времени выполнения с помощью компилятора.
Изменения в V8 и других пунктах
Версия 10 v8 привносит некоторые новые возможности:
- Поддержка новых методов
findLast
иfindLastIndex
для массивов, которые делают то же самое, что иfind
, но находят последнее значение вместо первого - Улучшения в API
Intl.Locale
- Улучшена производительность инициализации свойств и приватных методов класса, чтобы они работали так же быстро, как обычные свойства.
- Импорт модулей JSON был официально удален из экспериментального флага