Node.js 18 напоминает мне о Deno

Node.js 18 был выпущен 19 апреля 2022 года. В отличие от двух предыдущих версий, Node.js 18 предлагает интересные инновации и показывает направление, в котором Node.js будет развиваться в будущем.

Получить API

Первое существенное изменение в Node.js 18 — это встроенная поддержка Fetch API. Таким образом, Node получает стандартизированный HTTP-клиент, который мы уже знаем из браузера.

Вы можете подумать, что нам больше не нужны внешние модули, такие как Axios или Request, но на первый взгляд это не так, потому что Fetch API основан на модуле NPM undici. Этот модуль не поддерживает ни HTTP 2, ни HTTP 3. Вместо этого он полностью использует только HTTP 1.1.

Это немного разочаровывает, учитывая распространенность HTTP 2 в наши дни. Однако вы уже сегодня можете использовать Fetch API. Но вам придется обойтись без поддержки HTTP 2 и HTTP 3.

Веб-потоки

Кто уже имел дело с Fetch API, знает, что ответ, полученный от сервера, можно обрабатывать не только в виде JSON или текста, но и в виде потоков. Потоки — важная функция с многочисленными вариантами использования, потому что потоки дают вам возможность анализировать и обрабатывать ответ, даже если ответ не полностью загружен.

Хотя в Node.js всегда были известны потоки, можно подумать, что потоки работают из коробки. Но Fetch API не использует встроенные потоки. Онииспользуют веб-потоки, разработанные для браузеров. Это неудивительно, поскольку Fetch API также исходит из браузера.

Веб-потоки делают то же самое, что и классические потоки в Node.js, но технически они структурированы иначе. Так сказать, они работают немного по-другому с технической точки зрения. Это означает, что Node.js теперь поддерживает уже известные нам веб-потоки и классические потоки.

И я не уверен, что мне это должно нравиться. Реализация классических потоков была уже третьей попыткой правильно реализовать потоки в Node.js. А веб-потоки теперь являются 4-й попыткой.

Теперь у нас есть два принципиально разных потока чтения, потока записи и потока преобразования. Дуплексные потоки больше не существуют в веб-потоках, и я могу относиться к этому, потому что дуплексные потоки не имели смысла в Node.js. Но все остальные типы потоков теперь дублируются.

Это не так уж плохо, но это способствует непоследовательности среди разработчиков Node.js, которую я часто критикую. Это пропагандируемое несоответствие является фундаментальной причиной, по которой я недавно написал статью о том, почему я предпочитаю переход на TypeScript или Node.js.



По таким функциям видно, что Node.js уже не новинка, но все еще развивается. Развиваться дальше и развиваться ближе к стандартам — это, прежде всего, положительный момент. Но все становится проблематичным, если сами стандарты не были успешно реализованы.

Так что речь идет о дальнейшем развитии, которое не обязательно хорошо, а скорее об улучшении от худшего. И Fetch API и веб-потоки — яркие тому примеры.

Глобальные пространства имен

Как эти новые API и функции будут доступны в Node? В данном случае, предположительно из соображений совместимости с браузером, было принято решение использовать наихудший из возможных подходов, на мой взгляд. Эти новые функции теперь доступны как глобальные переменные.

Это означает, что вам не нужно использовать такие ключевые слова, как «require» или «import» для их импорта, вы можете вызвать Fetch API таким же образом.

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

Раньше в браузере почти не было альтернатив, кроме глобальных пространств имен, так как импорт модулей появлялся очень долго. Но этой проблемы или потребности не существует в Node. Поэтому мне интересно, почему Node должен сделать эти функции доступными как глобальные переменные и, таким образом, зарезервировать 24 дополнительных имени переменных.

Существуют необычные имена, такие как «ReadableStreamDefaultReader», а также повседневные термины, такие как «Запрос», «Ответ», «Заголовки» и «Блоб».

Суть в том, что я считаю ужасной идеей назначать глобальные идентификаторы таким ключевым терминам, которые уже используются во многих приложениях. Эти имена переменных заблокированы в этой версии, а это означает, что при обновлении до Node.js 18 у вас возникнет конфликт в 24 различных случаях.

Я не думаю, что это хорошая идея — размещать глобальные переменные случайным образом. Все заслуга совместимости между Node и веб-браузерами, но Node не является веб-браузером. 99% кода, написанного для Node и веб-браузера, никогда не выполняется на другой платформе.

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

У меня сложилось впечатление, что Node здесь очень тесно связан с Deno, потому что Deno делает именно то, что я только что критиковал. И тот же эффект можно наблюдать и со следующей особенностью.

Тестовая среда

Одним из ярких моментов Node.js 18 является возможность писать готовые тесты. Во-первых, это хорошая функция, потому что вы избавляетесь от внешних зависимостей, таких как Jest или Mocha. Название этого модуля называется «Тест». Этот API приносит с собой много многообещающих инноваций.

Вы можете определить синхронные и асинхронные тесты. Тесты можно вкладывать по желанию, а можно пропускать тесты, можно запускать тесты параллельно и т.д.

Таким образом, Test API поставляется с некоторыми полезными функциями, а в сочетании с модулем «assert» или «assert/strict» вам действительно не нужно полагаться на Jest. в большинстве случаев. Так что мне любопытно, как Jest, Mocha и другие будут позиционировать себя в долгосрочной перспективе.

Но теперь мы подходим к вопросу Я не понимаю. Из соображений безопасности в Node существует правило, согласно которому модуль Node всегда загружается поверх модуля NPM с тем же именем. Это правило имеет смысл. В конце концов, Node всегда страдал от поврежденных модулей NPM.

Как разработчик модулей NPM, вы должны избегать имен своих модулей, как модулей, которые поставляются с самим Node, потому что тогда вы не сможете загрузить эти модули NPM.

Конечно, с таким названием, как тест, заранее запрограммировано, что в NPM уже есть модуль с таким именем. Беглый взгляд на NPM подтверждает, что этот модуль уже существует, но не обновлялся почти десять лет.

Таким образом, вы можете предположить, что этот модуль плохо поддерживается, и, возможно, вы могли бы занять позицию, что если вы создадите интегрированный модуль Node с тем же именем, вы не сломаете слишком много, потому что этот модуль NPM не является широко распространенным ни в хорошем состоянии.

Но Node использует здесь другой подход. Чтобы не вызвать конфликт с этим модулем NPM, вы не можете загрузить тестовый модуль Node с помощью «test». Вместо этого вам нужно импортировать его с протоколом Node, например «node:test».

import * from 'node:test'

А я вот так не понимаю. С помощью Fetch API и веб-потоков Node создает конфликт с 24 именами переменных, которые вы заблокируете в будущем, но с одним модулем, который не получал обновлений в течение 10 лет. strong>s, Node идет несогласованным путем, что создает несогласованность?

Да, указание протокола для загрузки модулей Node имеет смысл в долгосрочной перспективе. Реализация для конкретного узла не гарантируется, если импорт загружается в других средах. Так что имеет смысл всегда указывать протокол, и я подозреваю, что так будет и в будущем.

Однако в настоящее время оно несовместимо, или согласованность здесь намеренно нарушена.

Утверждения импорта JSON

В Node.js 18 появились так называемые утверждения импорта JSON. Это позволяет явно отметить импорт файла JSON с помощью дополнительного параметра. При загрузке файла Node может проверить, является ли он файлом JSON, а не исполняемым кодом, который может привести к повреждению.

Это устраняет потенциальную брешь в безопасности. Важность этой функции возрастает, если подумать о следующей функции этой версии — импорте по протоколу HTTPS.

HTTPS-импорт

Раньше модули NPM можно было загружать только из локальной файловой системы. В Node.js 18 появилась экспериментальная возможность загружать модули NPM во время выполнения через HTTPS.

Это следующая функция, которая, кажется, вдохновлена ​​Deno, потому что Deno продает эту функцию как выдающееся достижение, поскольку она не зависит от центрального реестра, такого как NPM.

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

Конечно, можно возразить, что для этого можно использовать теги Github, но не каждый модуль есть на Github. Некоторые хранятся на альтернативных сервисах, таких как Gitlab или Bitbucket.

Краткое содержание

Я немного скептически отношусь к тому, в каком направлении движется Node. Конечно, на первый взгляд такие функции выглядят великолепно. Но еще предстоит выяснить, хороши ли эти функции или нет.

Потому что многие из этих функций напоминают Deno, и если бы я хотел работать с Deno, я бы работал с Deno. Но я принял сознательное решение против Deno и в пользу Node. И меньше всего я хочу, чтобы Node стал копией Deno.

Еще неизвестно, как будет развиваться Node.js, и не поймите меня неправильно. Я думаю, это здорово, что Node.js постоянно развивается и не стоит на месте. Но я не знаю, нравится ли мне нынешнее направление этого развития, как мне.

Спасибо, что прочитали мою статью о Node.js 18. Следите за новостями.

Ваше здоровье!

Читать дальше







Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Присоединяйтесь к нашему сообществу Discord.