Поддержка Node и npm
Современные проекты Node.js будут работать в Deno с минимальными или без каких-либо переделок. Однако существуют некоторые ключевые различия между двумя средами выполнения, которые вы можете использовать, чтобы упростить и уменьшить свой код при миграции проектов Node.js в Deno.
Использование встроенных модулей Node
Deno предоставляет слой совместимости, который позволяет использовать встроенные API Node.js в программах Deno. Однако, для их использования вам необходимо добавить спецификатор node: в любые операторы импорта, которые их используют:
import * as os from "node:os";
console.log(os.cpus());
И запустить его с deno run main.mjs — вы заметите, что получите тот же вывод, что и при запуске программы в Node.js.
Обновление любых импортов в вашем приложении на использование спецификаторов node: должно позволить любому коду, использующему встроенные функции Node, работать так же, как и в Node.js.
Для упрощения обновления существующего кода Deno предоставит полезные подсказки для импортов, которые не используют префикс node::
import * as os from "os";
console.log(os.cpus());
$ deno run main.mjs
error: Relative import path "os" not prefixed with / or ./ or ../
hint: If you want to use a built-in Node module, add a "node:" prefix (ex. "node:os").
at file:///main.mjs:1:21
Те же подсказки и дополнительные быстрые исправления предоставляются Deno LSP в вашем редакторе.
Использование пакетов npm
Deno имеет встроенную поддержку импорта пакетов npm, используя спецификаторы npm:. Например:
import * as emoji from "npm:node-emoji";
console.log(emoji.emojify(`:sauropod: :heart: npm`));
Можно запустить с:
$ deno run main.js
🦕 ❤️ npm
Префикс npm install не нужен перед командой deno run, и папка node_modules не создается. Эти пакеты также подпадают под те же разрешения, что и другой код в Deno.
Спецификаторы npm имеют следующий формат:
npm:<package-name>[@<version-requirement>][/<sub-path>]
Для примеров с популярными библиотеками, пожалуйста, обратитесь к разделу руководств.
Поддержка CommonJS
CommonJS — это система модулей, которая предшествует модулям ES. Хотя мы твердо верим, что модули ES — это будущее JavaScript, существуют миллионы npm библиотек, написанных на CommonJS, и Deno предлагает полную поддержку для них. Deno автоматически определит, использует ли пакет CommonJS, и сделает его работу бесперебойной при импорте:
import react from "npm:react";
console.log(react);
$ deno run -E main.js
18.3.1
npm:react — это пакет CommonJS. Deno позволяет импортировать его так, как будто это модуль ES.
Deno настоятельно рекомендует использовать модули ES в вашем коде, но предлагает поддержку CommonJS со следующими ограничениями:
Система разрешений Deno всё ещё действует при использовании модулей CommonJS. Возможно, потребуется предоставить как минимум --allow-read разрешение, поскольку Deno будет исследовать файловую систему в поисках файлов package.json и каталога node_modules для правильного разрешения модулей CommonJS.
Использование расширения .cjs
Если расширение файла .cjs, Deno будет рассматривать этот модуль как CommonJS.
const express = require("express");
Deno не ищет файлов package.json и опцию type для определения, является ли файл CommonJS или ESM.
При использовании CommonJS Deno ожидает, что зависимости будут установлены вручную, и каталог node_modules будет присутствовать. Лучше всего установить "nodeModulesDir": "auto" в ваш deno.json, чтобы гарантировать это.
$ cat deno.json
{
"nodeModulesDir": "auto"
}
$ deno install npm:express
Add npm:express@5.0.0
$ deno run -R -E main.cjs
[Function: createApplication] {
application: {
init: [Function: init],
defaultConfiguration: [Function: defaultConfiguration],
...
}
}
Флаги -R и -E используются для предоставления разрешений на чтение файлов и переменных окружения.
Опция типа package.json
Deno попытается загрузить файлы .js, .jsx, .ts и .tsx как CommonJS, если есть файл package.json с опцией "type": "commonjs" рядом с файлом или выше по дереву каталогов в проекте с файлом package.json.
{
"type": "commonjs"
}
const express = require("express");
Инструменты, такие как бандлер Next.js и другие, будут автоматически генерировать файл package.json подобного формата.
Если у вас есть существующий проект, использующий модули CommonJS, вы можете заставить его работать как с Node.js, так и с Deno, добавив опцию "type": "commonjs" в файл package.json.
Всегда обнаруживать, может ли файл быть CommonJS
Возможно, указать Deno анализировать модули как потенциально CommonJS, запустив его с флагом --unstable-detect-cjs в Deno >= 2.1.2. Это применится, за исключением случаев, когда есть файл package.json с { "type": "module" }.
Поиск файлов package.json в файловой системе и анализ модуля для определения, является ли он CommonJS, занимает больше времени, чем если этого не делать. По этой причине и для отговаривания от использования CommonJS, Deno не делает этого по умолчанию.
Создать require() вручную
Альтернативный вариант — создать экземпляр функции require() вручную:
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const express = require("express");
В этом случае применяются те же требования, что и при работе с файлами .cjs — зависимости нужно устанавливать вручную и предоставлять соответствующие флаги разрешений.
require(ESM)
Реализация Deno для require() поддерживает требование модулей ES.
Это работает так же, как и в Node.js, где вы можете только require() модули ES, которые не содержат Top-Level Await в их модульной графе — или, другими словами, вы можете только require() модули ES, которые являются «синхронными».
export function greet(name) {
return `Hello ${name}`;
}
import { greet } from "./greet.js";
export { greet };
const esm = require("./esm");
console.log(esm);
console.log(esm.greet("Deno"));
$ deno run -R main.cjs
[Module: null prototype] { greet: [Function: greet] }
Hello Deno
Импортирование модулей CommonJS
Вы также можете импортировать файлы CommonJS в модули ES.
module.exports = {
hello: "world",
};
import greet from "./greet.js";
console.log(greet);
$ deno run main.js
{
"hello": "world"
}
Подсказки и предложения
Deno предоставит полезные подсказки и предложения, чтобы помочь вам работать с кодом CommonJS.
Например, если вы попытаетесь запустить модуль CommonJS, у которого нет расширения .cjs или у которого нет файла package.json с { "type": "commonjs" }, вы можете увидеть это:
module.exports = {
hello: "world",
};
$ deno run main.js
error: Uncaught (in promise) ReferenceError: module is not defined
module.exports = {
^
at file:///main.js:1:1
info: Deno supports CommonJS modules in .cjs files, or when the closest
package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM,
or change the file extension to .cjs,
or add package.json next to the file with "type": "commonjs" option,
or pass --unstable-detect-cjs flag to detect CommonJS when loading.
docs: https://docs.deno.com/go/commonjs
Импорт типов
Многие пакеты npm поставляются с типами. Вы можете импортировать их и использовать напрямую:
import chalk from "npm:chalk@5";
Некоторые пакеты не поставляются с типами, но вы можете указать их типы с помощью директивы @deno-types. Например, используя пакет @types:
// @deno-types="npm:@types/express@^4.17"
import express from "npm:express@^4.17";
Разрешение модулей
Официальный компилятор TypeScript tsc поддерживает различные настройки moduleResolution. Deno поддерживает только современное разрешение node16. К сожалению, многие пакеты npm не обеспечивают правильную поддержку типов с разрешением модулей node16, что может привести к тому, что deno check сообщит об ошибках типов, которые tsc не сообщает.
Если экспорт по умолчанию из импорта npm: кажется неправильным типом (при этом правильный тип, по-видимому, доступен в свойстве .default), скорее всего, пакет предоставляет неверные типы для импорта из ESM с разрешением модулей node16. Вы можете проверить это, проверив, появляется ли ошибка и с tsc --module node16 и "type": "module" в package.json или проконсультировавшись со сайтом «Are the types wrong?» (в частности, строка «node16 from ESM»).
Если вы хотите использовать пакет, который не поддерживает разрешение модулей node16 TypeScript, вы можете:
- Открыть вопрос на трекере проблем пакета по этой проблеме. (И, возможно, внести свой вклад в исправление 😃 (Хотя, к сожалению, отсутствует инструментарий для пакетов, поддерживающих как ESM, так и CJS, поскольку экспорты по умолчанию требуют разного синтаксиса. См. также microsoft/TypeScript#54593)
- Использовать CDN, который пересобирает пакеты для поддержки Deno, вместо идентификатора
npm:. - Игнорировать ошибки типов, которые появляются в вашем коде с
// @ts-expect-errorили// @ts-ignore.
Включение типов Node
Node поставляет множество встроенных типов, таких как Buffer, которые могут быть упомянуты в типах пакета npm. Для их загрузки необходимо добавить директиву ссылки на типы в пакет @types/node:
/// <reference types="npm:@types/node" />
Обратите внимание, что в большинстве случаев указание версии необязательно, так как Deno будет пытаться поддерживать ее синхронизацию со своим внутренним кодом Node, но вы всегда можете переопределить используемую версию при необходимости.
Исполнимые скрипты npm
Пакеты npm со скриптами bin могут быть запущены из командной строки без npm install с помощью спецификатора в следующем формате:
npm:<package-name>[@<version-requirement>][/<binary-name>]
Например:
$ deno run --allow-read npm:cowsay@1.5.0 "Hello there!"
______________
< Hello there! >
--------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
$ deno run --allow-read npm:cowsay@1.5.0/cowthink "What to eat?"
______________
( What to eat? )
--------------
o ^__^
o (oo)\_______
(__)\ )\/\
||----w |
|| ||
node_modules
При запуске npm install, npm создает каталог node_modules в вашем проекте, содержащий зависимости, указанные в файле package.json.
Deno использует спецификаторы npm для разрешения пакетов npm в центральном глобальном кэше npm, вместо использования папки node_modules в ваших проектах. Это идеально, так как оно использует меньше места и поддерживает чистоту каталога вашего проекта.
Однако могут быть случаи, когда вам понадобится локальная папка node_modules в вашем проекте Deno, даже если у вас нет package.json (например, при использовании фреймворков, таких как Next.js или Svelte, или при зависимости от пакетов npm, использующих Node-API).
Поведение зависимостей Deno по умолчанию
По умолчанию Deno не будет создавать папку node_modules при использовании команды deno run, зависимости будут установлены в глобальный кэш. Это рекомендуемая настройка для новых проектов Deno.
Автоматическое создание node_modules
Если вам нужна папка node_modules в вашем проекте, вы можете использовать флаг --node-modules-dir или опцию nodeModulesDir: auto в файле конфигурации, чтобы указать Deno на создание папки node_modules в текущей рабочей директории:
deno run --node-modules-dir=auto main.ts
или с помощью файла конфигурации:
{
"nodeModulesDir": "auto"
}
Автоматический режим автоматически устанавливает зависимости в глобальный кэш и создаёт локальную папку node_modules в корне проекта. Это рекомендуется для проектов, имеющих зависимости npm, которые полагаются на папку node_modules — в основном для проектов, использующих бандлеры или те, которые имеют npm зависимости с скриптами postinstall.
Ручное создание node_modules
Если в вашем проекте есть файл package.json, вы можете использовать режим ручного управления, который требует шага установки для создания вашей папки node_modules:
deno install
deno run --node-modules-dir=manual main.ts
или с помощью файла конфигурации:
{ "nodeModulesDir": "manual" }
Затем вы запустите deno install/npm install/pnpm install или любой другой менеджер пакетов, чтобы создать папку node_modules.
Режим ручного управления является режимом по умолчанию для проектов, использующих package.json. Вы можете узнать этот рабочий процесс из проектов Node.js. Рекомендуется для проектов, использующих фреймворки, такие как Next.js, Remix, Svelte, Qwik и т. д., или инструменты, такие как Vite, Parcel или Rollup.
Мы рекомендуем использовать режим по умолчанию none, и переходить к режиму auto или manual, если вы получите ошибки о недостающих пакетах внутри папки node_modules.
node_modules с Deno 1.X
Используйте флаг --node-modules-dir.
Например, дан main.ts:
import chalk from "npm:chalk@5";
console.log(chalk.green("Hello"));
deno run --node-modules-dir main.ts
Выполнение приведенной выше команды с флагом --node-modules-dir создаст папку node_modules в текущей директории со структурой папок, похожей на npm.
Глобальные объекты Node.js
В Node.js имеется ряд глобальных объектов, доступных в области видимости всех программ, специфичных для Node.js, например, объект process.
Вот несколько глобальных объектов, которые вы можете встретить в дикой природе, и как использовать их в Deno:
-
process- Deno предоставляет глобальный объектprocess, который является, пожалуй, самым популярным глобальным объектом, используемым в популярных пакетах npm. Он доступен для всего кода. Однако Deno направит вас к явным импортам из модуляnode:processс помощью предупреждений проверки и быстрых исправлений:
console.log(process.versions.deno);
$ deno run process.js
2.0.0
$ deno lint process.js
error[no-process-globals]: NodeJS process global is discouraged in Deno
--> /process.js:1:13
|
1 | console.log(process.versions.deno);
| ^^^^^^^
= hint: Add `import process from "node:process";`
docs: https://lint.deno.land/rules/no-process-globals
Found 1 problem (1 fixable via --fix)
Checked 1 file
-
require()- см. поддержку CommonJS -
Buffer- для использования APIBufferнеобходимо явно импортировать его из модуляnode:buffer:
import { Buffer } from "node:buffer";
const buf = new Buffer(5, "0");
Предпочтительнее использовать Uint8Array или другие подклассы TypedArray вместо этого.
-
__filename- используйтеimport.meta.filenameвместо этого. -
__dirname- используйтеimport.meta.dirnameвместо этого.
Дополнения Node-API
Deno поддерживает дополнения Node-API, которые используются популярными пакетами npm, такими как esbuild, npm:sqlite3 или npm:duckdb.
Вы можете ожидать, что все пакеты, использующие публичные и документированные Node-API, будут работать.
Большинство пакетов, использующих дополнения Node-API, полагаются на npm "скрипты жизненного цикла", такие как postinstall.
Хотя Deno их поддерживает, они не выполняются по умолчанию из-за соображений безопасности. Подробнее в deno install документации.
Начиная с Deno 2.0, пакеты npm, использующие дополнения Node-API, поддерживаются только при наличии папки node_modules/. Добавьте "nodeModulesDir": "auto" или "nodeModulesDir": "manual" в свой файл deno.json, или запустите с флагом --node-modules-dir=auto|manual для правильной работы этих пакетов. В случае неправильной настройки Deno предоставит подсказки, как можно решить ситуацию.
Миграция с Node на Deno
Запуск вашего проекта Node.js с помощью Deno — это простой процесс. В большинстве случаев вы можете ожидать небольших или вообще никаких изменений, если ваш проект написан с использованием ES-модулей.
Основные моменты, о которых следует знать:
- Импорт встроенных модулей Node.js требует спецификатора
node::
// ❌
import * as fs from "fs";
import * as http from "http";
// ✅
import * as fs from "node:fs";
import * as http from "node:http";
Рекомендуется изменить эти спецификаторы импорта в вашем существующем проекте. Это рекомендуемый способ их импорта и в Node.js.
- Некоторые глобальные объекты, доступные в Node.js, должны быть явно импортированы, например,
Buffer:
import { Buffer } from "node:buffer";
-
require()доступен только в файлах с расширением.cjs, в других файлах экземплярrequire()нужно создать вручную. Зависимости npm могут использоватьrequire()независимо от расширения файла.
Запуск скриптов
Deno поддерживает запуск npm скриптов непосредственно с помощью подкоманды deno task (если вы мигрируете с Node.js, это аналогично команде npm run script). Рассмотрим следующий проект Node.js со скриптом под названием start внутри папки package.json:
{
"name": "my-project",
"scripts": {
"start": "eslint"
}
}
Вы можете выполнить этот скрипт с помощью Deno, выполнив:
deno task start
Дополнительные улучшения
Одним из основных преимуществ Deno является унифицированная среда разработки, которая поставляется с поддержкой TypeScript «из коробки», а также инструментами, такими как проверка кода, форматирование и система тестирования. Переход на Deno позволяет упростить вашу цепочку инструментов и уменьшить количество движущихся компонентов в вашем проекте.
Настройка
Deno имеет свой собственный файл конфигурации, deno.json или deno.jsonc, который можно использовать для настройки вашего проекта.
Вы можете использовать его для определения зависимостей с помощью опции imports — вы можете мигрировать зависимости по одной, из package.json, или выбрать не определять их в файле конфигурации вообще и использовать спецификаторы npm: непосредственно в вашем коде.
В дополнение к указанию зависимостей вы можете использовать deno.json для определения задач, опций проверки и форматирования, сопоставлений путей и других параметров времени выполнения.
Проверка кода
Deno поставляется со встроенным анализатором кода, написанным с учётом производительности. Он похож на ESlint, но с ограниченным количеством правил. Если вы не полагаетесь на плагины ESLint, вы можете удалить зависимость eslint из раздела devDependencies вашего файла package.json и использовать deno lint вместо него.
Deno может проверять большие проекты всего за несколько миллисекунд. Вы можете попробовать это на своём проекте, выполнив:
deno lint
Это проверит все файлы в вашем проекте. При обнаружении проблемы анализатором кода, он отобразит строку в вашем редакторе и в выводе терминала. Вот как это может выглядеть:
error[no-constant-condition]: Use of a constant expressions as conditions is not allowed.
--> /my-project/bar.ts:1:5
|
1 | if (true) {
| ^^^^
= hint: Remove the constant expression
docs: https://lint.deno.land/rules/no-constant-condition
Found 1 problem
Checked 4 files
Многие проблемы с проверкой кода могут быть автоматически исправлены, передав флаг --fix:
deno lint --fix
Полный список всех поддерживаемых правил проверки кода можно найти на https://lint.deno.land/. Чтобы узнать больше о настройке анализатора кода, ознакомьтесь с deno lint подкомандой.
Форматирование
Deno поставляется со встроенным форматированием, которое может по желанию отформатировать ваш код в соответствии со стилем руководства по стилю Deno. Вместо добавления prettier в devDependencies вы можете использовать встроенный форматировщик кода Deno без конфигурации deno fmt.
Вы можете запустить форматировщик на своём проекте, выполнив:
deno fmt
Если вы используете deno fmt в CI, вы можете передать аргумент --check для выхода форматировщика с ошибкой при обнаружении неправильно отформатированного кода.
deno fmt --check
Правила форматирования можно настроить в вашем файле deno.json. Чтобы узнать больше о настройке форматировщика, ознакомьтесь с deno fmt подкомандой.
Тестирование
Deno рекомендует писать тесты для вашего кода и предоставляет встроенный тестовый запуск, чтобы упростить написание и выполнение тестов. Тестовый запуск тесно интегрирован в Deno, так что вам не нужно выполнять дополнительную настройку, чтобы заставить работать TypeScript или другие функции.
Deno.test("my test", () => {
// Your test code here
});
deno test
При передаче флага --watch, тестовый запуск автоматически перезагрузится, если какие-либо из импортированных модулей изменятся.
Чтобы узнать больше о тестовом запуске и о том, как его настроить, ознакомьтесь с документацией подкоманды deno test.
Приватные репозитории
Не следует путать с приватными репозиториями и модулями.
Deno поддерживает приватные репозитории, которые позволяют размещать и обмениваться собственными модулями. Это полезно для организаций, которые хотят сохранить свой код в секрете, или для отдельных лиц, которые хотят поделиться своим кодом с небольшой группой людей.
Что такое приватные репозитории?
Крупные организации часто размещают собственные приватные npm репозитории, чтобы безопасно управлять внутренними пакетами. Эти приватные репозитории служат хранилищами, где организации могут публиковать и хранить свои собственные или пользовательские пакеты. В отличие от публичных npm репозиториев, к приватным репозиториям имеют доступ только авторизованные пользователи внутри организации.
Как использовать приватные репозитории с Deno
Сначала настройте файл .npmrc, чтобы указать на ваш приватный репозиторий. Файл .npmrc должен находиться в корне проекта или в директории $HOME. Добавьте следующее в свой файл .npmrc.
@mycompany:registry=http://mycompany.com:8111/
//mycompany.com:8111/:_auth=secretToken
Замените http://mycompany.com:8111/ на фактический URL вашего приватного репозитория и secretToken на ваш токен аутентификации.
Затем обновите файл deno.json или package.json, чтобы указать путь импорта для вашего приватного пакета. Например:
{
"imports": {
"@mycompany/package": "npm:@mycompany/package@1.0.0"
}
}
или, если вы используете package.json:
{
"dependencies": {
"@mycompany/package": "1.0.0"
}
}
Теперь вы можете импортировать свой приватный пакет в свой код Deno:
import { hello } from "@mycompany/package";
console.log(hello());
и запустить его с помощью команды deno run:
deno run main.ts
Справочник по переходу с Node.js на Deno
| Node.js | Deno |
|---|---|
node file.js | deno file.js |
ts-node file.ts | deno file.ts |
nodemon | deno run --watch |
node -e | deno eval |
npm i / npm install
| deno install |
npm install -g | deno install -g |
npm run | deno task |
eslint | deno lint |
prettier | deno fmt |
package.json |
deno.json или package.json
|
tsc |
deno check ¹ |
typedoc | deno doc |
jest / ava / mocha / tap / и т.д.
| deno test |
nexe / pkg
| deno compile |
npm explain | deno info |
nvm / n / fnm
| deno upgrade |
tsserver | deno lsp |
nyc / c8 / istanbul
| deno coverage |
| benchmarks | deno bench |
¹ Проверка типов происходит автоматически, компилятор TypeScript встроен в исполняемый файл deno.
© 2018–2024 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/runtime/fundamentals/node